RCE.SU - реверсинг, кодинг, выделенные сервера, ICQ, proxy

Исследование Special EXE Password Protector v1.0

Защищена эта прога каким-то новым протектором "SVKP", который не переносит Softice, TRW и ваще все дебагеры. При этом эта зараза не дает делать дампы... Потом еще и импорт не дает по-человечески восстановить. Еще и дразнится :(((

Иструменты: TRW2000, IDA, Procdump, Delphi, Imprec 1.42
Я так и не понял почему, но procdump кричит что процесс низя дампить, а дампер в TRW вешает комп.
Ну фиг с ними. Я просто запустил SEPP и написал в делфи примитивный дампер. Типа так:

Var i:cardinal;
buf:array [1..$58000] of char; //58000 - это IMAGE SIZE в PE
h:thandle;
f:file of char;
j:dword;
begin
 h:=OpenProcess(PROCESS_ALL_ACCESS,false,$fffd5d6b); //Pid я просто посмотрел в Procdump :)
 readprocessmemory(h,pointer($400000),@buf,$58000,i);
 closehandle(h);

 assignfile(f,'c:\sepphex.exe'); //ну самомнение у мя завышенное, не отрицаю :)
 rewrite(f);
 for j:=1 to i do
 write(f,buf[j]);
 closefile(f);
end;
Сдампил и сделал Rebuil Pe.
Дойти к oep у нас не выйдет т.к. протектор просто каким-то извратным методом не дает запускать дебагер пока прога не распакуется и запустится, поэтому искать его будем в дампе по импорту. Все прекрасно знают, что практически все проги в самом начале выполняют GetModuleHandleA, так что если найдем эту функцию то уже очень скоро найдем oep. Но сначала нужно взять импорт. Для уверности я после запуска SEPP запустил TRW и зациклил прогу. Так как oep я не знал, нужно было как-то предположить где ж импорт. Я просто взял и глянул на код с адреса 401000 и увидел такое дело:
00401000                 push    0
00401002                 call    dword ptr [00412188]
00401008                 mov     dword ptr [0040C081], eax
412188 - это импорт. IAT начинается с 412000. Можно брать импорт в Imprec. Некоторые функции восстановятся, а некоторые придется искать самому. Весь импорт построен на полиморфных переходниках. При этом еще останется 6 функций которые у вас ну никак не будут восстанавливаться, потому что эти ненайденые функции будут выглядеть как длинные циклические полиморфы. Т.е. сильно не потрейсишь - задолбаешься. А тут и не надо трейсить. Импорт без этих 6 фунцкий будет выглядеть вот так:
FThunk: 0001212C	NbFunc: 00000001
1	0001212C	comctl32.dll	0054	InitCommonControlsEx

FThunk: 00012134	NbFunc: 00000001
1	00012134	comdlg32.dll	006E	GetOpenFileNameA

FThunk: 0001213C	NbFunc: 00000014
1	0001213C	kernel32.dll	02C6	SetEndOfFile
1	00012140	kernel32.dll	00B9	CreateFileA
1	00012144	kernel32.dll	00A0	CloseHandle
1	00012148	kernel32.dll	035F	lstrlen
1	0001214C	kernel32.dll	0177	GetFileSize
1	00012150	kernel32.dll	00BA	CreateFileMappingA
1	00012154	kernel32.dll	0249	MapViewOfFile
1	00012158	kernel32.dll	00C6	CreateProcessA
1	0001215C	kernel32.dll	00AD	CopyFileA
1	00012160	kernel32.dll	00D8	DeleteFileA
1	00012164	kernel32.dll	0172	GetFileAttributesA
1	00012168	kernel32.dll	02CD	SetFileAttributesA
1	0001216C	kernel32.dll	0178	GetFileTime
1	00012170	kernel32.dll	02D0	SetFileTime
1	00012174	kernel32.dll	0319	VirtualAlloc
1	00012178	kernel32.dll	031B	VirtualFree
1	0001217C	?       0000    06231F09
1	00012180	kernel32.dll	0314	UnmapViewOfFile
1	00012184	kernel32.dll	02CF	SetFilePointer
1	00012188	?       0000    06233276

FThunk: 00012190	NbFunc: 00000004
0	00012190	?	0000	06236E2D
0	00012194	?	0000	06236FC5
0	00012198	?	0000	06238067
0	0001219C	?	0000	0623859D

FThunk: 000121A4	NbFunc: 0000000E
1	000121A4	user32.dll	01F2	SendDlgItemMessageA
1	000121A8	user32.dll	00B7	EndDialog
1	000121AC	user32.dll	0036	CheckDlgButton
1	000121B0	user32.dll	00FC	GetDlgItem
1	000121B4	user32.dll	020E	SetDlgItemTextA
1	000121B8	user32.dll	0246	ShowWindow
1	000121BC	user32.dll	0051	CreateDialogParamA
1	000121C0	user32.dll	01F7	SendMessageA
1	000121C4	user32.dll	0091	DialogBoxParamA
1	000121C8	user32.dll	0195	LoadIconA
1	000121CC	user32.dll	00FE	GetDlgItemTextA
1	000121D0	user32.dll	01AD	MessageBoxA
1	000121D4	user32.dll	0017	CallWindowProcA
1	000121D8	user32.dll	0182	IsDlgButtonChecked
Как мы видим 4 функции ваще хз какие, а 2 идут в разделе kernel32.dll. Если присмотреться, то можно заметить что функции GetmodulehandleA нет, и еще нет функции которой прога будет завершаться, т.е. ни Postquitmessage, ни TerminateProcess, ни ExitProcess... Можно предположить что одна из этих 2-х ненайденых в kernel32.dll функций это getmodulehandleA, а вторая - какая-то функция выхода. Как жеж определить кто есть who? Просто в запущеном SEPP поставить брейкпоинты на эти адреса и посмотреть что выполнится при выходе. А выполнится при выходе функция 0001217C (см. импорт) И при вызове ей дадут всего один параметр число 0. Это у нас ExitProcess. А вторая - это Getmodulehandlea (00012188). Вот с теми 4-мя сложнее, это у нас функции защиты, если поставить брейкпоинты на эти функции то можно увидеть, что 00012190 вызывается при вызове About. Как я понял это что-то типа GetRegInfo. С остальными у мя до сих пор непонятки, они ничего не берут, но без них прога не пашет. Я так понимаю, что функции проги, которые этот SVKP встраиваются в тело протектора чтоб никто их оттуда не выдрал. Поэтому я их просто оставил как есть и дописал полученый импорт. Теперь если дизасмнуть наш дамп в IDA и глянуть по адресу 401000, можно увидеть такое:
.text:00401000                 push    0
.text:00401002                 call    ds:GetModuleHandleA
.text:00401008                 mov     dword_40C081, eax
.text:0040100D                 push    0Ah
.text:0040100F                 push    0
.text:00401011                 push    dword_40C081
.text:00401017                 call    sub_40102A
.text:0040101C                 push    0
.text:0040101E                 call    ds:ExitProcess
Интуиция :) Это OEP. А вообще можно было б поискать вызовы к адресу 412188 (это GetmodulehandleA) и мы как раз нашли бы тоже самое.

Теперь остались эти вредные 4 функции... Чо ж делать? Я забил на всякие попытки их эмулировать. Я просто сдампил весь код протектора от 6230000 до 6243000 (итого 13000h), дописал его в конец файла. Потом поправил ImageSize так чтоб получилось 6243000. Ну и задал нужные параметры для новой секции. Чтоб она грузилась по адресу 6230000. Т.е.
RVA=5E30000
Psize=Vsize=13000
Да, согласен что это как-то грубо такое делать, такие обьемы памяти под прогу требовать. Ну так сессия у меня блин, некогда делать все как положено :( Главное - прога запускается и работает :)

Теперь осталось убрать два ограничения: лимит на 3 символа в пароле и нагу, которую оно дописывает в защищенный exe.
Начнем с наги. Защитим какой-нить exe файл. Дальше ставим bpx messageboxa и смотрим как оно вызывается. Вот так:

push    ebp
push    2000h
push    ecx
push    edx
push    0
call    dword ptr [ebp+7A04h]

Это сооиветствует опкодам:
8D8DFF7700005568... и т.д.
Ищем эту последовательность в нашем дампе. Она находится по адресу 403B51:
.text:00403B51                 push    ebp
.text:00403B52                 push    2000h
.text:00403B57                 push    ecx
.text:00403B58                 push    edx
.text:00403B59                 push    0
.text:00403B5B                 call    dword ptr [ebp+7A04h]
.text:00403B61                 pop     ebp
Правим дамп вот так:
.text:00403B51                 push    ebp
.text:00403B52                 jmp     loc_403B61
.text:00403B57                 push    ecx
.text:00403B58                 push    edx
.text:00403B59                 push    0
.text:00403B5B                 call    dword ptr [ebp+7A04h]
.text:00403B61                 pop     ebp
Наг больше не будет.

Теперь про три буквы... :)
Опять же bpx messageboxa и мы вот тут:

.text:00401684                 mov     ebx, [ebp+hDlg]
.text:00401687                 push    ebx
.text:00401688                 push    20h             ; nMaxCount
.text:0040168A                 push    offset unk_40C7B1 ; lpString
.text:0040168F                 push    3EBh            ; nIDDlgItem
.text:00401694                 push    ebx             ; hDlg
.text:00401695                 call    ds:GetDlgItemTextA
.text:0040169B                 cmp     eax, 3 
.text:0040169E                 jbe     short loc_4016BA
.text:004016A0                 push    2000h           ; uType
.text:004016A5                 push    offset aWarning ; lpCaption
.text:004016AA                 push    offset aInUnregistered ; lpText
.text:004016AF                 push    0               ; hWnd
.text:004016B1                 call    ds:MessageBoxA
Надеюсь все понятно :) Но это тока месага, надо еще удостоверится что возмется именно более 3 символов, а то мало что оно там творит. Смотрим дальше:
.text:004016BA                 push    4               ; nMaxCount  - ага! Все-таки 4, а не 3 :) 
.text:004016BC                 push    offset unk_40C7B1 ; lpString
.text:004016C1                 push    3EBh            ; nIDDlgItem
.text:004016C6                 push    ebx             ; hDlg
.text:004016C7                 call    ds:GetDlgItemTextA
.text:004016CD                 test    eax, eax
.text:004016CF                 pop     ebx
.text:004016D0                 jz      short loc_40172C
.text:004016D2                 lea     esi, ds:40C7B1h
.text:004016D8                 lea     edi, ds:40C74Eh
.text:004016DE                 mov     ecx, eax
.text:004016E0                 repe movsb
.text:004016E2                 mov     byte_40C74D, al - А это что-то интересное, записывет 
                                                        длина пароля, она как раз в EAX лежит.
.text:004016E7                 push    4               ; nMaxCount - угу ! :)
.text:004016E9                 push    offset unk_40C76F ; lpString
.text:004016EE                 push    3ECh            ; nIDDlgItem
.text:004016F3                 push    ebx             ; hDlg
.text:004016F4                 call    ds:GetDlgItemTextA
.text:004016FA                 test    eax, eax
.text:004016FC                 jz      short loc_40172C
.text:004016FE                 lea     esi, ds:40C74Eh
.text:00401704                 lea     edi, ds:40C76Fh
.text:0040170A                 mov     ecx, 3            - опять 3 символа.
.text:0040170F                 repe cmpsb  - это проверяет чтоб пароли совпали
.text:00401711                 test    ecx, ecx
.text:00401713                 jz      short loc_401733
Если поправить все nmaxcount чтоб читало более 4 символов пароля и этот mov ecx,3 - на mov ecx, eax(напоминаю, в eax после GetDlgItemTextA лежит длина строки), то прога перестанет кричать. Но все же проьектить паролем не будет, а начнет выдавать месаги типа "wrong Pe format" Это неправда :) Мы кое-что упустили. Мы не посмотрели что происходит со значением которое было занесено тут:
.text:004016E2                 mov     byte_40C74D, al

Поставим bpm 40C74D. Сработает оно тут:
.text:00401A23                 mov     al, byte_40C74D
.text:00401A28                 add     al, 33h
.text:00401A2A                 cmp     al, 36h
.text:00401A2C                 jbe     short loc_401A31
Это последняя проверка, исправив ее прога ставит пароли нужной длины.
P.S. Я говорил что прога дразнится. Это правда. Если вы попытаетесь пройти до оер, то в коде распаковщика вы увидите вот такое:
"If You are there, You are a good cracker, but this is only the beginning :) This is a special greeting to my friends:Hello boys: 3rt, EliCZ, VAG, Daemon, Gamumba, Chris, SACUnknown One and all boys from UG2000 and other good "unpackers" !If You will find the way how to decode SVKP, please contact me :)"
P.S.S. Значит я таки "good cracker" :)


<= Вернуться к статьям


Rambler's Top100