Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Авторские статьи (https://forum.antichat.xyz/forumdisplay.php?f=31)
-   -   Распаковка Ntkrnl packer (https://forum.antichat.xyz/showthread.php?t=51440)

0x0c0de 18.10.2007 19:16

Распаковка Ntkrnl packer
 
Распаковка Ntkrnlpacker.

[Intro]

Итак, в связи с болезнью появилось свободное время, которое я трачу на реверсинг и математику. Что мне удалось написать под температурой 38 читаем ниже. Пинаемся, кусаемся и критикуем как обычно в комментариях=).

[Начнем]

Вот, что пишут про данный прот

Цитата:

NTkrnl Packer uses new and unique encryption polymorphic technology and provides software developers and publishers with an undetectable level of encryption to significantly increase their revenues.

+ Anti-cracking
NTkrnl Packer has innovative powerful routine against the reverse engineering in the business. It has new code protection features to stop the latest cracking software and cracker issues.

...

+ Code and Resource Compression
In addition to protection features, NTkrnl Packer allows you to compres

+ Compatible with several Development Tools
NTkrnl Packer is able to pack software written in Delphi, C++ Builder, Microsoft Visual C++, Visual Basic.
И все в таком духе. В общем как обычно. Раньше об этом агрегате не слышала, стало интересно посмотреть, что за зверь. А зверь оказался интересный. Начнем с entry point запакованной программы

Код:

00401061 C>  68 5D544100                  PUSH anyprog.0041545D
00401066    E8 01000000                  CALL anyprog.0040106C
0040106B    C3                          RETN
0040106C    C3                          RETN

И, черт возьми, в этом было нечто знакомое ;-) Проблема возникла с отладкой. Оля до определенного момента дебажила, а потом прога вылетала. Причем что только я не перепробовала. Конечно, возникла идея приаттачится к процессу, но об этом чуть позже. Сначала расскажу о тех анти-дебаг приемах, которые используются (встретившиеся мне до того, как Оля уперлась рогами и отказалась работать).
Ниже привожу два куска кода, которые с завидным постоянством и незначительной модификацией кочуют из сорца в сорец)
Спаливание Оли через RDTSC

Код:

00415F3D    0F31                        RDTSC
00415F3F    33C9                        XOR ECX,ECX
00415F41    03C8                        ADD ECX,EAX
00415F43    0F31                        RDTSC
00415F45    2BC1                        SUB EAX,ECX
00415F47    3D FF0F0000                  CMP EAX,0FFF
00415F4C    72 04                        JB SHORT anyprog.00415F52
00415F4E    0F31                        RDTSC
00415F50    50                          PUSH EAX

И обнуление др-регистров (через seh)

Код:

00415FE6    55                          PUSH EBP
00415FE7    8BEC                        MOV EBP,ESP
00415FE9    BB 00010000                  MOV EBX,100
00415FEE    F7D3                        NOT EBX
00415FF0    8B45 10                      MOV EAX,DWORD PTR SS:[EBP+10]
00415FF3    2198 C0000000                AND DWORD PTR DS:[EAX+C0],EBX
00415FF9    8BB8 C4000000                MOV EDI,DWORD PTR DS:[EAX+C4]
00415FFF    C740 04 00000000            MOV DWORD PTR DS:[EAX+4],0 ; обнуляем др0 регистр
00416006    3E:FF37                      PUSH DWORD PTR DS:[EDI]
00416009    64:8F05 00000000            POP DWORD PTR FS:[0]
00416010    C740 08 00000000            MOV DWORD PTR DS:[EAX+8],0 ; обнуляем др1 регистр
00416017    8380 C4000000 08            ADD DWORD PTR DS:[EAX+C4],8
0041601E    8BB8 A4000000                MOV EDI,DWORD PTR DS:[EAX+A4]
00416024    C740 0C 00000000            MOV DWORD PTR DS:[EAX+C],0 ; обнуляем др2 регистр
0041602B    89B8 B8000000                MOV DWORD PTR DS:[EAX+B8],EDI
00416031    8B5D 10                      MOV EBX,DWORD PTR SS:[EBP+10]
00416034    33C0                        XOR EAX,EAX
00416036    8943 10                      MOV DWORD PTR DS:[EBX+10],EAX  ; обнуляем др3 регистр
00416039    8943 14                      MOV DWORD PTR DS:[EBX+14],EAX  ; обнуляем др6
0041603C    C743 18 55010000            MOV DWORD PTR DS:[EBX+18],155 ; пишем в др7
00416043    8B83 B0000000                MOV EAX,DWORD PTR DS:[EBX+B0]

Потом проверка на бряки. Причем проверяет только первый байт функции. В общем не страшно.

Код:

00415FA7    55                          PUSH EBP
00415FA8    8BEC                        MOV EBP,ESP
00415FAA    8B45 08                      MOV EAX,DWORD PTR SS:[EBP+8]
00415FAD    0340 3C                      ADD EAX,DWORD PTR DS:[EAX+3C]
00415FB0    05 80000000                  ADD EAX,80
00415FB5    8B08                        MOV ECX,DWORD PTR DS:[EAX]
00415FB7    034D 08                      ADD ECX,DWORD PTR SS:[EBP+8]
00415FBA    83C1 10                      ADD ECX,10
00415FBD    8B01                        MOV EAX,DWORD PTR DS:[ECX]
00415FBF    0345 08                      ADD EAX,DWORD PTR SS:[EBP+8]
00415FC2    8B18                        MOV EBX,DWORD PTR DS:[EAX]
00415FC4    803B CC                      CMP BYTE PTR DS:[EBX],0CC ; проверочка
00415FC7    74 18                        JE SHORT anyprog.00415FE1
00415FC9    8B55 0C                      MOV EDX,DWORD PTR SS:[EBP+C]
00415FCC    891A                        MOV DWORD PTR DS:[EDX],EBX
00415FCE    83C0 04                      ADD EAX,4
00415FD1    8B18                        MOV EBX,DWORD PTR DS:[EAX]
00415FD3    803B CC                      CMP BYTE PTR DS:[EBX],0CC ; проверочка
00415FD6    74 09                        JE SHORT anyprog.00415FE1
00415FD8    8B55 10                      MOV EDX,DWORD PTR SS:[EBP+10]
00415FDB    891A                        MOV DWORD PTR DS:[EDX],EBX
00415FDD    5D                          POP EBP

Себя защита распаковывает долго и извратно. Там очень большой цикл (повторяющийся много раз), который здесь не приводится. А теперь вернемся к нашему процессу. Аттачимся. Оля ругнется на невалидный файл, так как присутствует антидамп, но о нем чуть позже. Теперь вопрос, как в такой ситуации найти oep? Ответ – посмотреть в стек. Кстати, как в самом протекторе, так и в нескольких тестовых запакованных программах с oep байт не крадется, что для нас большой плюс. Значит скролим окно стека вниз к самому началу и ищем первый адрес возврата, принадлежащий коду программы. Этот адрес будет находиться в непосредственной близости от oep. Будете ворчать, что способ нехороший. Знаю я, знаю) Но тем не менее в сработал успешно (несколько раз, а это уже статистика). Опять же. Дамп снимать еще пока нельзя. Так как у нас уже искажены переменные и с немалой долей вероятности программа будет работать неправильно, а некоторые (и много таких) программы вообще проверяют значение переменных. Так как в таком случае нам получить правильный дамп? Заинжектить длл, которая будет перехватывать какую-либо функцию, вызывающуюся непосредственно в oep-процедуре. Если,например, это делфи-программа, то идельно подходит GetModuleHandleA (в зависмости от компилятора это может быть __set_app_type или GetVersion). Причем нужно проверять адрес возврата, который мы знаем точно. И после этого (если все совпало), зацикливаем программу и дампим. В мое тестовом примере была прога на MingWin32 GCC 3.x. Оставим пока эту идею с dll и поговорим об импорте. Часть функций есть, а часть адресов нет. Смотрим (привожу кусок).

Код:

00407120  00F00000
00407124  00F00084
00407128  00F00108
0040712C  00F0018C
00407130  00F00210
00407134  00F00294
00407138  00F00318
0040713C  00F0039C
00407140  00F00420
00407144  00000000
00407148  00000000
0040714C  77C0EEEB  msvcrt.__getmainargs
00407150  77C0F1C5  msvcrt.__p__environ
00407154  77C0F1DB  msvcrt.__p__fmode
00407158  77C2537C  msvcrt.__set_app_type

Что у нас по адресу 00F00000?

Код:

00F00000    60                          PUSHAD
00F00001    E8 00000000                  CALL 00F00006
00F00006    5D                          POP EBP
00F00007    81ED 0F469400                SUB EBP,94460F
00F0000D    FFB5 81469400                PUSH DWORD PTR SS:[EBP+944681]
00F00013    FFB5 85469400                PUSH DWORD PTR SS:[EBP+944685]
00F00019    FFB5 89469400                PUSH DWORD PTR SS:[EBP+944689]
00F0001F    FFB5 79469400                PUSH DWORD PTR SS:[EBP+944679]
00F00025    FFB5 7D469400                PUSH DWORD PTR SS:[EBP+94467D]
00F0002B    E8 08000000                  CALL 00F00038
00F00030    894424 1C                    MOV DWORD PTR SS:[ESP+1C],EAX
00F00034    61                          POPAD
00F00035    FFE0                        JMP EAX
00F00037    C3                          RETN

Джамп еах передает управление оригинальной функции. Все переходники одинаковые. То же самое по адресу 00F0018C и всем остальным.
Из этого всего делаем вывод. Запросто теперь напишем скрипт, восстанавливающий импорт. Он попросит ввести начало таблицы и ее конец. Принцип такой. Проходимся по всей таблице, берем невалидный адрес, устанавливаем eip на него ищем опкод jmp eax, ставим на него точку останова, выполняем… Кладем значение eax на место невалидного адреса.

Код:

var iat_begin
var iat_end
var element
var iat_end_
var jaddr

ask "Iat begin"
mov iat_begin,$RESULT
cmp iat_begin,0
je fin

ask "Iat end"
mov iat_end,$RESULT
add iat_end,4
mov iat_end_,$RESULT
add iat_end_,4
cmp iat_end,0
je fin
mov element,iat_begin
mov eip,[element]

start:
findop eip,#FFE0#  ; jmp eax
mov jaddr,$RESULT
bphws jaddr,"x" ; хардвар на джамп еах
run
mov [element],eax
add element,4
cmp element,iat_end_
je fin
cmp [element],0 ; ноль? пропускаем
je add_
cmp [element],50000000 ; адрес уже есть? пропускаем
ja add_
mov eip,[element]
bphwc jaddr
jmp start

fin:
msg "Done"
ret

add_:
add element,4
cmp element,iat_end_
je fin
je fin
cmp [element],0
je add_
cmp [element],50000000 ; адрес уже есть? пропускаем
ja add_
mov eip,[element]
bphwc jaddr
jmp start

Получаем нормальную таблицу. А теперь снова о dll. В моем случае oep

Код:

00401240    55                          PUSH EBP
00401241    89E5                        MOV EBP,ESP
00401243    83EC 08                      SUB ESP,8
00401246    C70424 02000000              MOV DWORD PTR SS:[ESP],2
0040124D    FF15 58714000                CALL DWORD PTR DS:[407158]                            ; msvcrt.__set_app_type
00401253    E8 A8FEFFFF                  CALL anyprog.00401100

Значит интересует нас функция __set_app_type из msvcrt.dll. Ее и будем перехватывать. Далее код искомой dll. Ассемблер …. Я здесь ничего не оптимизировала и писала на скорую руку. Важно было быстро получить результат

Код:

.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
include kernel32.inc
includelib kernel32.lib
includelib user32.lib
.data
lib db "msvcrt.dll",0
proc_ db "__set_app_type",0
buffersbytes db 6 dup (?)
func_ dword ?
.code
unhook proc
mov esi,offset buffersbytes
mov edi,func_
mov ecx,6
rep movsb
ret
unhook  endp

hook_ proc
mov edi,func_
mov byte ptr[edi],068h
mov dword ptr [edi+1],offset hooked_
mov byte ptr[edi+5],0c3h
ret
hook_ endp

loop_ proc
local dwOldProtect:dword
invoke VirtualProtectEx,-1,00401253h, 3, PAGE_EXECUTE_READWRITE,addr dwOldProtect
mov edi,00401253h
mov word ptr[edi],0feebh ; бесконечный цикл
ret
loop_ endp

hooked_ proc par1:dword
cmp dword ptr[esp+4],00401253h ; адрес возврата
jnz ret_
call loop_
ret_:
call unhook
push par1
call func_
pop par1
call hook_
ret
hooked_ endp

DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
local dwOldProtect:dword
        cmp  reason,DLL_PROCESS_ATTACH
        jnz ret__
        pushad
        invoke GetModuleHandleA,offset lib
        test eax,eax
        jnz gaddress_
        invoke LoadLibrary,offset lib
        test eax,eax
        je ext
        gaddress_:
        invoke GetProcAddress,eax,offset proc_
        test eax,eax
        je ext
        mov func_,eax
        invoke VirtualProtectEx,-1,func_, 6, PAGE_EXECUTE_READWRITE,addr dwOldProtect
        test eax,eax
    jz ext
    mov edi,func_
    mov esi,offset buffersbytes
    mov dl,byte ptr[edi]
    mov byte ptr[esi],dl
    mov edx,dword ptr[edi+1]
    mov dword ptr[esi+1],edx
    mov dl,byte ptr[edi+5]
    mov byte ptr[esi+5],dl
    mov byte ptr[edi],068h
    mov dword ptr [edi+1],offset hooked_
    mov byte ptr[edi+5],0c3h
        ext:
        popad
        jmp ret_
        ret__:
        call unhook
        ret_:
        ret
DllEntry Endp
End DllEntry

Вот. Ее и заинжектим.
Дамп. Выбираем опцию LordPE: Active dump engine->IntelliDump->Select! И дампим. Импорт восстанавливаем с помощью Imprec и нашего скрипта… На этом этапе последнее- это исправление двух байт, использующихся для зацикливания по адресу 00401253h (адрес возврата из функции). EBFE на E8A8.
Все.

-----------------------Добавлено-------------------------------
Мешало отладке то, что прот устанавливал на память аттрибут PAGE_EXECUTE_READ|PAGE_GUARD. В Phantom plugin надо включить опцию Custom handler exceptions, тогда все будет норм отлаживаться. Антиотладка

Код:

00416957    6A 04                        PUSH 4
00416959    68 00100000                  PUSH 1000
0041695E    68 00100000                  PUSH 1000
00416963    6A 00                        PUSH 0
00416965    E8 78FFFFFF                  CALL CyberPro.004168E2                                ; JMP to kernel32.VirtualAlloc
0041696A    C600 C3                      MOV BYTE PTR DS:[EAX],0C3
0041696D    8985 9F029D01                MOV DWORD PTR SS:[EBP+19D029F],EAX
00416973    8D85 9B029D01                LEA EAX,DWORD PTR SS:[EBP+19D029B]
00416979    50                          PUSH EAX
0041697A    68 20010000                  PUSH 120
0041697F    6A 10                        PUSH 10
00416981    FFB5 9F029D01                PUSH DWORD PTR SS:[EBP+19D029F]
00416987    E8 50FFFFFF                  CALL CyberPro.004168DC                                ; JMP to kernel32.VirtualProtect
0041698C    8B85 9F029D01                MOV EAX,DWORD PTR SS:[EBP+19D029F]
00416992    FFD0                        CALL EAX
00416994    0F31                        RDTSC
00416996    50                          PUSH EAX
00416997    C3                          RETN

(с) 0x0c0de 2007

genom-- 18.10.2007 20:42

хм не очень секу в асме -- но вродебы сам писал старался и не боян - в общем наконецто норм статья -- молодцом


Время: 03:14