Вот решил провести эксперимент и написал (не без помощи сайтов) прогу (masm32), которая определяет адрес базы kernel32.dll: Code: .386 option casemap:none .model flat, stdcall ;----------------------------include--------------------- includelib \masm32\lib\kernel32.lib include \masm32\include\kernel32.inc ;-------------------------------------------------------- .data db 0 .code start: mov esi, [esp] call GetBase; после вызова в eax база kernel32.dll invoke ExitProcess, 0 ;#####################################GetBase############################### ; ; Получение базы kernel32.dll ; ;########################################################################### GetBase: push esi;сохраняем все регистры, которые используются push ecx pushf;сохраняем регистр флагов and esi,0FFFF0000H;гранулярность выделения памяти mov ecx,6;счетчик страниц _@1: ;проверка очередной страницы cmp word ptr [esi], "ZM" jz WeGotBase _@2: sub esi, 10000h loop _@1 WeFailed: mov eax, 00000000h ;база не найдена jmp EndGetBase WeGotBase: xchg eax, esi EndGetBase: popf;восстанавливаем значения флагов pop ecx pop esi;восстанавливаем значения регистров ret ;######################################################################### ;Конец процедуры GetBase ;######################################################################### end start В Windows XP SP3 я получил адрес базы 7C800000h в Windows 7 77140000h
cmp word ptr [esi], "ZM" jz WeGotBase после этого чекай на PE. А вообще байан редкостный. Тем более для dll не подходит.
спрашивается а нафига её искать методом поиска? Если же можно тупо взять из PEB Вариант с подмененным и неправильным PEB'ом можно расценивать как манию приследывания и последюю стадию шизофрении. Так что лучше юзать через PEB Под 2k, XP, 2k3 ты получишь адрес kernel32.dll а под w7 - адрес KERNELBASE KERNELBASE - это считай жалкий аналог kernel32.dll Но есть хитрость. В них в обоих есть функции GetProcAddress и LoadLibraryExA через который можно загрузить любую либу (хотябы туже kernel32 для w7) Для всякого малвара своего юзаю примерно такую схему: Code: __declspec(naked) HMODULE GetKernel32(void) { __asm { push esi xor eax,eax mov eax,fs:[0x30] js find_kernel_9x mov eax,[eax+0x0c] mov esi,[eax+0x1c] lodsd mov eax,[eax+0x8] jmp find_kernel_end find_kernel_9x: mov eax,[eax+0x34] lea eax,[eax+0x7c] mov eax,[eax+0x3c] find_kernel_end: pop esi ret } } KERNELBASE = GetKernel32(); *(void* *)&_LoadLibraryExA = HideGetProcAddress(KERNELBASE, "LoadLibraryExA"); *(void* *)&_GetProcAddress = HideGetProcAddress(KERNELBASE, "GetProcAddress"); if (!_LoadLibraryExA || !_GetProcAddress) return 0; kernel32_dll = _LoadLibraryExA("kernel32.dll", 0, 0); итд итп. HideGetProcAddress - самописная функция поиска адреса функции (когдато выкладывал тут её) И пашет идеально на всей линейке NT начиная от 2k Другое дело в ядре искать адрес загрузки ядра, Там это уже нужно осуществлять перебор. Вот пример Code: mov esi, dword ptr ds:[0ffdff038h]; адрес обработчика для IDLE lodsd cdq lodsd base_loop: dec eax cmp dword ptr [eax], 00905a4dh ; сигнатура для файла ядра MZ+P+0x00 jnz base_loop mov lib, eax Но этот код очень удобно юзать под ядром. Вернее под ядром его тока и можно заюзать )
>>>> cmp word ptr [esi], "ZM" - разве это не есть проверка на PE это проверка на дос заголовок. В досовских exe файлах и в старом LE нету PE заголовка ) Проверка на PE делается так 1) находится ImageBase и проверяется сигнатура MZ 2) ImageBase + 0x3С - по этому офсету хранится DWORD указывающий смещение (относительно ImageBase) на PE заголовок 3) ImageBase + офсет на PE и по этому адресу проверяется двойное слово на сигнатуру 'P' 'E' 0x00 0x00
2slesh жесть, зачем это делать ассемблерной вставкой? али влом структуры описывать и пользоваться макросами для LIST_ENTRY?
по старинке юзаю из шелкодов ) Но вообще некоторые операции без асм вставки будут некрасиво выглядеть. Допустим та же mov eax,fs:[0x30], которую придется заменить на соотвествующую апишку
Code: mov esi,[eax+0x1c] lodsd mov eax,[eax+0x8] зачем тут еsi?) А ещё сравнил бы на всякий случай имя библиотеки
2desTiny как зачем, а указать lodsd откуда грузить значение? Мы ж обращаемся ко второму LDR_MODULE_ENTRY в цепочке. а проверять не нужно, там постоянно ntdll->kernel32->[user32]->...
mov esi,[eax+0x1c] lodsd ~ mov eax, [eax+0x1c] mov eax, [eax] и нафиг не нужны эти первый пуш и последний поп >> там постоянно никто ничего не обещает. Вот если ты так уверен в порядке - ну-ка сходу скажи, где в цепочке будет kernelbase.dll?
2desTiny а зачем мне kernelbase.dll? главное я чотко уверен, что под всей линейкой ntdll->kernel32. Остальное в принципе не интересно ) в данном случае. Поэтому проверять не надо.
Для самоуверенных читать мой пост где я кинул кусок кода и там описал что и как. И То что нужно искать там LoadLibraryExA/W потому что других подобных нету. Это пришлось сделать именно из-за W7 потому как именно kernelbase там получалась а не kernel32.
Верно ли написан код получения GetProcAddress ? Вроде все как в туториале Code: .386 .model flat, stdcall option casemap:none includelib \masm32\lib\kernel32.lib ExitProcess PROTO : DWORD .data db 0 ProcAd db "GetProcAddress",0h Counter db 0h OrdinalTableVA db 0h AddressTableVA db 0h Kernel db 0h .code start: ;считаем дельта смещение call VirDelta VirDelta: sub dword ptr [esp], offset VirDelta push dword ptr [esp] ;jmp ReadSEH ; Читаем SEH ReadSEH: xor edx, edx ; edx = 0 assume fs:flat mov eax, fs:[edx] ; читаем элемент SEH dec edx ; edx = 0FFFFFFFFh ; Ищем элемент со значением 0FFFFFFFFh SearchKernel32: cmp [eax], edx ; сравниваем очередной с 0FFFFFFFFh je CheckKernel32 ; прыгаем, если нашли mov eax, [eax] ; получаем следующее значение jmp SearchKernel32 ; если не нашли - ищем дальше ; Определяем адрес Kernel32 CheckKernel32: mov eax, [eax + 4] ; получаем адрес ГДЕ-ТО в ; kernel32.dll xor ax, ax ; выравниваем полученный адрес ; Ищем сигнатуру MZ SearchKernelMZ: cmp word ptr [eax], 5A4Dh ; сверяем сигнатуру MZ je CheckKernelMZ ; сигнатура верна, переходим на ; проверку сигнатуры PE sub eax, 10000h ; если не равна MZ, то ищем дальше jmp SearchKernelMZ ; Проверяем сигнатуру PE CheckKernelMZ: mov edx, [eax + 3Ch] ; переходим на PE-заголовок cmp word ptr [eax + edx], 4550h ; сверяем сигнатуру jne _Exit ; неверная сигнатура, поэтому ; выходим call GetAPI _Exit: invoke ExitProcess, 0h ;поиск адреса GetProcessAddress GetAPI: mov edx, offset Kernel mov [edx], eax mov esi, offset ProcAd mov edx, esi @_1: cmp byte ptr [esi], 0; конец строки? jz @_2 inc esi jmp @_1 @_2: inc esi sub esi, edx mov ecx, esi ;;теперь в ecx и esi находится размер имени функции GetProcessAddress (12h символов) mov ebx, eax xor eax, eax mov esi, ebx add esi, 3Ch ;заголовок PE lodsw add eax, ebx mov esi, [eax + 78h] ;RVA таблицы экспортов add esi, ebx ;указатель на RVA таблицы адресов add esi, 1ch lodsd ;eax = RVA таблицы адресов add eax, ebx ;eax VA таблицы адресов mov edx, offset AddressTableVA mov[edx], eax ;push eax ;сохраняем lodsd ;eax = RVA таблицы указателей на имена add eax, ebx ; eax = VA таблицы указателей на имена push eax ;сохраняем lodsd ;eax = RVA таблицы ординалов add eax, ebx mov edx, offset OrdinalTableVA mov [edx], eax ;push eax pop esi @_3: push esi ;сохраняем VA таблицы указателей на имена lodsd add eax, ebx mov esi, eax mov edi, offset ProcAd push ecx cld repe cmpsb pop ecx jz @_4 pop esi add esi, 4 mov edx, [offset Counter] inc edx push ecx mov ecx, offset Counter mov [ecx], edx pop ecx jmp @_3 @_4: pop esi mov edx, offset Counter mov eax, [edx] shl eax, 1 mov edx, offset OrdinalTableVA add eax, [edx] shl eax, 2 mov edx, offset AddressTableVA add eax, [edx] mov edx, offset Kernel add eax, [edx] ret end start по идее в EAX должен остаться адрес этой функции...Сильно не ругайте за корявый код я только начал учить асму