Доброго времени суток. Вот выдалось немного свободного времени и я решил поэксперементировать с патчингом DLL Изрядно покурив маны, получилось что-то вроде этого. Code (Text): use32 API_NUMS equ 2h ; - Количество необходимых нам функций Delta: ; Entry Point pushad ; 1 Байт pushf ; 1 байт ;--- определение _dwReason cmp dword [ebp+10h],01h ; 4 Б jne _Exit ; 2 Б call $+5 pop edx ; Находим дельта смещение sub edx, 11h ; xor edx, edx ; mov edx, ebx push edx ; Для работы блока. Кладем в стек адрес дельта смещения ;------------------- "БЛОК" поиска АПИ функций по ХЕШ значениям ---------------------------------------- _ReadSEH: xor edx,edx ; EDX=0 db 64h,8Bh,02h ;mov eax,FS:[edx]- EAX=Указатель на 1st SEH dec edx ; EDX=FFFFFFFFh - Маркировка последнего SEH (Kernel) _SrchKernelSEH: cmp [eax],edx ; IF 1st SEH=SEH(Kernel) je _GetAddrInK ; TRUE находим Kernel Base mov eax,dword [eax] ; FALSE указатель Next SEH jmp _SrchKernelSEH ; Цикл "поиск SEH(Kernel)" _GetAddrInK: mov eax,[eax+4] ; Адресс ExepProc(Kernel) в SEH xor ax,ax ; Кратно 64кб = 10000h _SearchMZ: mov edx,[eax] ; EDX=DWORD [начало страницы (Kernel)] cmp dx,5A4Dh ; "MZ" ; Если WORD<>"MZ" jne _ContinueSearchMZ; TRUE Kernel База Найдена xor ecx, ecx ; проверка на кол-во этов в таблице импорта mov ecx, [eax+3Ch] ; add ecx, 84h ; cmp dword [eax+ecx], 0h ; Если 0 значит мы в Ntdll.dll jne _CheckPE ; <> 0 Проверим PE _ContinueSearchMZ: sub eax,10000h ; EAX=EAX-10000h (След Страница) jmp _SearchMZ ; Цикл "поиск KernelBase" _CheckPE: xor edx,edx ; Дополнительная проверка mov edx,[eax+3Ch] ; Кернела на формат PE EXE cmp dword [eax+edx],4550h ; "PE" jne _ApiErrorExit ; КРАХ! ВЫХОД! _SearchAPI: mov esi,[eax+edx+78h] ; ESI=Export Table RVA (смещение от Base) add esi,eax ; ESI=ESI+KernelBase -- Указатель Export Table add esi,18h ; Указатель на (Num of Name Pointers) xchg eax,ebx ; EBX = KERNEL BASE lodsd push eax ; Num of Name Pointers DWORD [+18h] lodsd push eax ; Address Table RVA DWORD [+1Ch] lodsd push eax ; Name Pointers RVA DWORD [+20h] ;mov eax,[esp+4*1] add eax,ebx ; EAX=EAX+KERNEL BASE push eax ; EAX= Index (Name Pointers VA) lodsd push eax ; Ordinal Table RVA DWORD [+24h] mov edi,[esp+4*5] ; Delta offset lea edi, [edi+HashAPI-Delta] ; EDI=HASH TABLE lea edi,[edi+HeshTable] mov ebp,esp _BeginSearch: mov ecx,[ebp+4*4] ; ECX=Кол-во Имен Функций (NumOfNamePointers) xor edx,edx ; EDX=0 _SearchAPIName: mov esi,[ebp+4*1] ; ESI=STACK + 4 mov esi,[esi] ; ESI=Index RVA (Указатель на 1st API ASCII) add esi,ebx ; ESI=Index VA (+ Kernel Base) _GetHash: xor eax,eax ; EAX=0 push eax ; PUSH 0000h _CalcHash: ror eax,7 xor dword [esp],eax lodsb test al,al jnz _CalcHash pop eax ; в eax ХЕШ _OkHash: cmp eax, dword [edi] je _OkAPI add dword [ebp+4*1],4h inc edx loop _SearchAPIName _OkAPI: shl edx,1h ; номер функции mov ecx,[ebp] ; OrdinalTableRVA add ecx,ebx add ecx,edx mov ecx,[ecx] and ecx,0FFFFh mov edx,[ebp+4*3] ;AddressTableRVA add edx,ebx shl ecx,2h add edx,ecx mov edx,[edx] add edx,ebx push edx ; сохраняем адрес найденной функции стеке cmp word [edi+4],0FFFFh ; 0FFFFh-End of HeshTable je _SearchEnd ; следующее hash-значение функции add edi,4 _NextName: mov ecx,[ebp+4*2] ;NamePointersRVA add ecx,ebx mov [ebp+4*1],ecx ;Index в таблице имен jmp _BeginSearch _SearchEnd: mov edi,[esp+4*(5+API_NUMS)] ; Delta offset lea edi, [edi+AddrAPI-Delta] ; EDI=HASH TABLE lea edi,[edi+HeshTable] mov ecx,API_NUMS _@loop: pop eax stosd loop _@loop mov edi,[esp+4*5] ; Delta offset add esp,4*5 ; Восстанавливаем стек. Работа блока закончена ;------------- pop edx ;Берем из стека базовый адрес jmp _Exit; Для отладки, по началу думал что косяк где-то дальше по коду call [@GetCommandLineA + edx] ; -- поиск имени файла mov esi, eax _SearchStart: cmp byte [eax], '\' jne _NextChar lea esi, [eax + 1] _NextChar: inc eax cmp byte [eax], '"' je _GetHash2 cmp byte [eax], 0 jne _SearchStart _GetHash2: xor eax,eax ; EAX=0 push eax ; PUSH 0000h _CalcHash2: ror eax,7 xor dword [esp],eax lodsb ; загрузка символа в AL cmp al,'a' jb _CheckChar cmp al,'z' ja _CheckChar sub al, 20h _CheckChar: cmp byte al, '"' jne _CalcHash2 pop eax ; в eax хеш ; ---- поиск хеша в таблице lea edi, [HashProc + edx] _@SearchLoop: cmp eax, dword [edi] je _Found cmp word[edi + 4], 0FFFFh je _Exit; add edi, 4h loop _@SearchLoop _Found: lea ebp, [libName + edx] push ebp call [@LoadLibraryA + edx]; jmp _Exit _ApiErrorExit: pop edx ; Ппц костыль _Exit: popf popad ;ret ; jmp near 0 ;; <- адрес оригинальной точки входа ;-------------------------- Таблица ХЕШей всех необходимых нам функций ------------------------- HashAPI: dd 071E40722h ; "LoadLibraryA" dd 0FCFED34Ah ; "GetCommandLineA" dd 0FFFFh ; EndOfHashTable Конец таблицы. необходимо ;------------------------ После выполнения блока эта таблица заполнится адресами функций. ------------ AddrAPI: @GetCommandLineA dd 0h @LoadLibraryA dd 0h ; --------------------------------- Таблица ХЕШей имен процессов --------------------------------- HashProc : dd 0F2F32210h ; ShellDebug.exe dd 0FFFFh ; EndOfHashTable libName db 'test.dll',0 Все как обычно. Беру Dll, создаю секцию, меняю точку входа. Заручаю осел в оле. И... Вуаля! Все казалось бы работает. Но только до перезагрузки. После ребута система ( точнее explorer.exe ) начинает себя крайне неадекватно вести. Это еще более сильно раззадорило мой интерес. На какой подводный камень я наткнулся? Зы. Простите за кривой код, просто пока не знаю как лучше, я новичек в асме
//оффтоп а чем плох метод получения базы kernel через PEB? mov eax, [fs:30h] mov eax, [eax+0ch] mov eax, [eax+1ch] mov eax, [eax+0] mov eax, [eax+08h]
Вы хотите сказать что возникает ситуация когда я не получаю адрес базы kernel32. В таком случае все вызовы ф-й будут в никуда. ( Отсюда возможно эксцепшены и глюки. Хотя все проходит молча ) Но этот код исключает возможность вызова ф-й kernela И всеравно ситуация не меняется
GoldFinch Почему оффтоп ? Детский, ламерский способ - получение базы модуля из блока загрузчика. Альтернатива - анализ стекового фрейма в SEH при исключении.
CrystalIC, так какие минусы у этого способа-то? Альтернатива - получение адреса в kernel32.dll из таблицы импорта зараженного модуля
GoldFinch Какой импорт , отсылаю тебя изучать механизмы обработки исключений, зарегистрированная процедура(SEH) вызыватеся из модуля kernel32 посредством инструкции Call. Минусы - используется Ldr. Что это значит - гугли.
упс. но вот тут вы обсуждаете хорошие грабли. дело в том, что не все виндовсы одинаковы полезны при таком подходе. я уже столкнулся с тем, что на висте SEH установлен не на процедуру из kernel'а!, а на ntdll проще получить базу по адресу возврата. Да и настоятельно рекомендую проверить хэш. дело в том, что простые способы хэширования имен API дают повторные результаты! (это еще одни недокументированные грабли, я лично проверял много способов, но самым лучшим считаю CRC32, он не простой, но с кодом CRC сливается очень даже не плохо, даже при дизассемблировании). + Code (Text): jmp near 0 ;; <- адрес оригинальной точки входа я вот только одного не наблюдаю. где исправляем 0 на адрес оригинальной точки входа?
Эм.... Я патчу точку входа в DLL, которую вызывает загрузчик. Я написал простенькую программу, которая делает все сама ) В отладчике все норм. Я исключил возможность вызова ф-й, следовательно на данном этапе это не имеет ровно никакого отношения к возникающему багу. Я исходил из соображений что в Win Xp Sp2-Sp3 ntdll.dll и kernel32.dll непременно присутствуют в ап процесса. Возникали ситуации когда в результате анализа SEH я оказывался в ntdll. Для этого реализована следующая проверка : Code (Text): xor ecx, ecx ; проверка на кол-во этов в таблице импорта mov ecx, [eax+3Ch] ; add ecx, 84h ; cmp dword [eax+ecx], 0h ; Если 0 значит мы в Ntdll.dll jne _CheckPE ; <> 0 Проверим PE базирующаяся на определении кол-ва элементов таблицы импорта ( ntdll ничего не импортирует ) Ps Хотелось бы уточнить суть проблеммы. Беру ws2_32 и патчу. Запускаю любой софт -- все работает, причем отладчик ( OllyDbg ) это подтверждает. Перезагружаюсь... И тут начинается самое интересмное. Очень долго запускается explorer.exe, пропадает возможность копипаста, на таскбаре не появляются окна... Вобщем глюки. Вопросс в том, какую ситуацию я не учел, что приводит к таким артефактам
FakeMan что значит сама. этого она точно не делает! спокойно может оказаться, что kernel выше чем ntdll или ито вовсе они не подряд расположены
ищите имя dll в секции импорта/экспорте. да и в ntdll есть querysysteminformation - получай список модулей или LdrGetDllHandle!
Вопрос к Клерку, но хотелось бы услышать и других, кто его поддерживает в этом. Почему? Возьмем к примеру ntdll База хранится там на постоянном месте. Можно и иначе получить, о какие минусы именно этого способа?
Я использую поиск через обработчик SEH. Естественно там может оказаться как ntdll (что обычное дело для NT) так и kernel32 (что обычное дело для 9x). Обе эти библиотеки обязательно что либо экспортируют (для того они и нужны собственно), а следовательно, у них есть блок экспорта (кстати не обязательно,что это отдельная секция - я данные, импорт и экспорт частенько сливаю в одну секцию для уменьшения объёма результирующего файла). В блоке экспорта обязательно должно быть имя этого модуля (у системных библиотек оно обязательно должно быть и совпадать с именем самого файла библиотеки) которое мы и используем для определения в какой мы библиотеке. Если мы угодили в ntdll то, как уже сказал max7C4, используем функцию LdrGetDllHandle для поиска kernel32 (правда там слегка специфический формат строк). Это у меня одинаково успешно работает и в 9x и в NT. Находить загрузочные базы библиотек через PEB быстро, но на совместимость влияет плохо (только NT и то не все) и защитное ПО такой подход ой как не любит. Сами модули могут располагаться в памяти как угодно (зависит от билда винды и от установленных заплаток и сервис-паков). Встречал случаи когда левые dll выбивали системные с их законных адресов. У меня ntdll ниже по адресам чем kernel32 и между ними ещё 5 модулей впихнуто. Для имён функций, ИМХО, лучший хэш, это CRC32. Вот такие дела.
Например. Разве не все? 9х это разве актуально? Я к тому что разве есть смысл беспокоиться о 9х? То есть это и не преимущество значит? Нет? В каком смысле?