Кратчайший путь нахождения адреса KERNEL32

Оригинальный текст: Billy Belcebu/DDT
Перевод: NeKr0!

Simplest way for get KERNEL32 base address       Billy Belcebг/DDT

Хм, как вы поняли я люблю писать маленькие и эффективные туториалы (кроме моего VWGs), и вот пред вами еще один. Это на мой взгляд простейший (в идее и реализации) путь для получения адреса KERNEL32.DLL. Я проводил тестирование на своем компьютере, на Win98 и WinNT4-SP3, и это работало также хорошо, как и моя процедура поиска таблицы импортов. Как всегда, как и со всеми моими знаниями, я должен за свою идею Super'у (perdon por llamarte tanto, ya se ke soy un puto pesao ;). Хрм... Oкей, oкей, я пошел :)
Как вы знаете, когда мы выполняем приложение, код "вызывается" из части кода KERNEL32 (т.e., типа KERNEL делает CALL в наш код) и, если вы помните, когда сделан call, адрес возврата находится в стеке (это кусок памяти на котрый указывает ESP). Давайте взглянем на пример по теме:


        .586p                           ; Ну... просто ради прикола.
        .model  flat                    ; Hehehe я люблю 32 bit фишки ;)

        .data                           ; Некоторые данные 
					; (для нужд TASM32/TLINK32)
        
        db      00h

        .code

 start:
        mov     eax,[esp]               ; Теперь в EAX должно быть BFF8XXXXh 
					; (если система w9X)
        ret                             ; Способ завершить процесс ;)
 end    start

Вроде просто. Мы имеем в EAX число приблизительноравное BFF8XXXX (XXXX это ненужные циферки, потому что нет нужды знать их точно, не надоедайте мне с такими простыми вещами, как эта ;). Win32 платформы обычно все вырывнивают на границу страницы, мы можем искать заголовок KERNEL'а на любой странице, он просто находится в начале страницы, и мы с легкостью можем это проверить. И когда мы найдем заголовок PE мы будем знать адрес KERNEL32. Хрмм, предел для поиска мы могли бы установить в 50h страниц. Хехе, не беспокойтесь. Пример последует ;)


        .586p
        .model  flat
        .data

extrn   ExitProcess:PROC

                db      0

kernel          equ     0BFF70000h
imagebase       equ     000400000h
limit           equ     (50000h/1000h)

 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
 ; Бесполезные и несущественные данные :)                                   ;
 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;

        .code

test:       
        call    delta
delta:
        pop     ebp
        sub     ebp,offset delta

        mov     esi,[esp]
        and     esi,0FFFFF000h                  ; AND ESI,-1000
        call    GetK32

        push    00000000h
        call    ExitProcess

 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
 ; Блин, я предполагаю что ты немного умеешь кодить на ASMе, еще я предпола-;
 ; гаю что ты знаешь, что первый блок инструкций - для получения смещения,  ;
 ; (не нужно в этом примере, но всеравно мне нравиться делать это похожим на;
 ; вирусный код). Второй блок - это как раз то, что нас интересует. Мы имеем;
 ; в ESI адрес, откуда "вызвано" наше приложение, этот адрес указывает нам  ;
 ; ESP (если мы конечно не трогали стек после загрузки программы). Вторая   ;
 ; команда, AND, для выравния адреса, с которого нас вызвали, на границу    ;
 ; страницы. Мы вызовем нашу процедурку, и после этого завершим процесс ;)  ;
 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;

GetK32:

__1:    cmp     byte ptr [ebp+K32_Limit],00h
        jz      WeFailed

        cmp     word ptr [esi],"ZM"
        jz      CheckPE

__2:    sub     esi,1000h
        dec     byte ptr [ebp+K32_Limit]
        jmp     __1

 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
 ; Первым делом мы проверим не превысили ли мы предел наших 50 страниц.После;
 ; После этого мы проверим начало страницы на предмет сигнатуры MZ (как это ;
 ; должно быть), если она там - проверим на предмет PE заголовка. Если ниче-;
 ; го не совпало - вычитаем из адреса 1 страницу (1000h байт, 4096d байт),  ;
 ; уменьшим значение предела для поиска страниц и поищем снова...           ;
 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;

CheckPE:
        mov     edi,[esi+3Ch]
        add     edi,esi
        cmp     dword ptr [edi],"EP"
        jz      WeGotK32
        jmp     __2
WeFailed:
        stc
WeGotK32:
        xchg    eax,esi
        ret

K32_Limit       dw      limit

 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
 ; Мы взяли число по смещению 3Ch из MZ заголовка (указывающий RVA адрес где;
 ; начинается PE заголовок), мы устаканили его с адресом страницы, и если по;
 ; этому смещению стоят буковки PE, я думаю мы его нашли... неужели мы его  ;
 ; нашли! ;)                                                                ;
 ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;

end     test


Рекомендация: я тестировал этот метод и он не создавл мне проблем в системах Win98 и WinNT4 с SP3, но, т.к. я не знаю что может где-нибудь случиться, я рекомендую вам использовать SEH чтобы избежать возможных Page Fault'ов (и сопутствующих им "синих экранов").

Я не намерен больше тратить свое время на этот простой туториал. Увидимся.

Billy Belcebг, mass killer and ass kicker.

© Nekr0!