Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Распаковка ThunderBolt 0.02

Обсудить статью на форуме

Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.

Автор: kR01eG <netu@ego.ru>

Сегодня в меню: ThunderBolt v0.02 (http://tuts4you.com/request.php?1942)
Тут нас ждет:
1. Morphed Code
2. AntiDebug
3. Import steal
Столовые приборы: OllyDbg, ImpRec, LordPE, компилятор C++ по вкусу, мозги (тоже по вкусу).
Начнем-с..
Мы сюда не эксепшены ловить пришли, так что смело врубаем игнор всех ошибок в olly.
Едем дальше, до EP.

0040B000 > /E9 00000000     JMP     UnPackMe.0040B005
0040B005   60              PUSHAD
0040B006    E8 14000000     CALL    UnPackMe.0040B01F
0040B00B    5D              POP     EBP
0040B00C    81ED 00000000   SUB     EBP,0
0040B012    6A 45           PUSH    45
0040B014    E8 A3000000     CALL    UnPackMe.0040B0BC
0040B019    68 00000000     PUSH    0
0040B01E    E8 5861E8AA     CALL    AB29117B
0040B023    0000            ADD     BYTE PTR DS:[EAX],AL

Заходим в CALL по F7, потом еще в один, потом еще..
Видим такое:

0040B1CD    C3              RETN
0040B1CE    F0:EB FF        LOCK JMP SHORT UnPackMe.0040B1D0         ; LOCK prefix is not allowed
0040B1D1  ^ 73 ED           JNB     SHORT UnPackMe.0040B1C0
0040B1D3  ^ 72 EB           JB      SHORT UnPackMe.0040B1C0
0040B1D5  ^ EB FA           JMP     SHORT UnPackMe.0040B1D1
0040B1D7  ^ 71 83           JNO     SHORT UnPackMe.0040B15C
0040B1D9    C3              RETN
0040B1DA    F8              CLC
0040B1DB    EB FF           JMP     SHORT UnPackMe.0040B1DC
0040B1DD  ^ 73 ED           JNB     SHORT UnPackMe.0040B1CC
0040B1DF  ^ 72 EB           JB      SHORT UnPackMe.0040B1CC
0040B1E1  ^ EB FA           JMP     SHORT UnPackMe.0040B1DD
0040B1E3  ^ 71 83           JNO     SHORT UnPackMe.0040B168
0040B1E5    C3              RETN
0040B1E6    14 EB           ADC     AL,0EB
0040B1E8    FF73 ED         PUSH    DWORD PTR DS:[EBX-13]
0040B1EB  ^ 72 EB           JB      SHORT UnPackMe.0040B1D8
0040B1ED  ^ EB FA           JMP     SHORT UnPackMe.0040B1E9
0040B1EF  ^ EB 83           JMP     SHORT UnPackMe.0040B174
0040B1F1    C3              RETN
0040B1F2    10EB            ADC     BL,CH
0040B1F4    FF73 ED         PUSH    DWORD PTR DS:[EBX-13]
0040B1F7  ^ 72 EB           JB      SHORT UnPackMe.0040B1E4
0040B1F9  ^ EB FA           JMP     SHORT UnPackMe.0040B1F5
0040B1FB    E8 83C30CEB     CALL    EB4D7583
0040B200    FF73 ED         PUSH    DWORD PTR DS:[EBX-13]
0040B203  ^ 72 EB           JB      SHORT UnPackMe.0040B1F0
0040B205  ^ EB FA           JMP     SHORT UnPackMe.0040B201
0040B207    FF83 C308EBFF   INC     DWORD PTR DS:[EBX+FFEB08C3]
0040B20D  ^ 73 ED           JNB     SHORT UnPackMe.0040B1FC
0040B20F  ^ 72 EB           JB      SHORT UnPackMe.0040B1FC
0040B211  ^ EB FA           JMP     SHORT UnPackMe.0040B20D
0040B213  ^ EB 83           JMP     SHORT UnPackMe.0040B198
0040B215    C3              RETN
0040B216    17              POP     SS                               ; Modification of segment register

Что, код нестабильный скрипит на зубах? :) Это у нас Morphed Code. Кто хочет потратить лучшие годы своей жизни на трассировку, могут продолжать. А мы "пойдем другим путем" (c).
Ну че делать? Бум наверно запускать прогу :) Жмем Alt+M, ставим break-on-access на секцию .text нашего UnPackMe, давим Shift+F9 и... И... и приплыли!..
Итак, это вторая часть нашего путешествия - антидебаг. Для софтайса он конечно может быть и незаметен, но в целях самообразования мы его найдем сами. А потом - мы его убьем.
Открываем анпакми в LordPE, там Directories и кнопка "..." напротив ImportTable. Там еще много разных директориес существует, это очень глубокая ж*па, и многие хорошие протекторы ее юзают.
Открылась табличка импорта. Что мы видим - из одной-единственной библиотеки KERNEL32.dll импортируется 3 функции, посмотрите дети - это GetProcAddress, GetModuleHandleA и LoadLibraryA. Вы слышали чтобы дебагеры грохал LoadLibraryA? А GetProcAddress??? Да, вы отчасти правы, действительно, GetProcAddress существует для усложнения (а в клинических случаях - и для облегчения) жизни простого народа, т.е. крэкеров. А посему перезагружаем программу в OllyDbg и пишем в команд лайн (Alt+F1 если не видно :)) - BP GetProcAddress и жмем Enter.
Ну, попробуем: Shift+F9. Остановились раз, остановились два, три. Четвертый раз:

EDI 7C90E642 ntdll.ZwSetInformationThread
EIP 7C80ADA0 kernel32.GetProcAddress

Обана! ZwSetInformationThread, да еще и низкоуровневый! Неспроста это... Хорошо, убираем бряк с GetProcAddress, проходим по Ctrl+F9 до RET и возвращаемся в главную программу. Ну ладно, раз уж мы его в EDI нашли, значит так и напишем. Жмем Ctrl+B и набираем FF D7. Это код инструкции CALL EDI, давно пора знать уже! ]:-) Находим ее по адресу 321459h, ставим бряк по F2. Shift+F9 - попался скотина!! Убираем бряк, и пойдем с 32145Bh, не выполняя CALL EDI. Для этого выделим следующую инструкцию и нажмем Ctrl+Num* (звездочка на NumPad). Нас спросят, в своем ли мы уме - отвечаем "да", как бы сильны ни были наши сомнения в этом. И еще - функции из ntdll - низкоуровневые, там используется регистровый метод вызова, поэтому стек выравнивать не надо.
Все! Теперь пробуем снова поставить break-on-access на секцию .text и запустить программу. Вуаля!

0040B2A2    8B7424 24       MOV     ESI,DWORD PTR SS:[ESP+24]
0040B2A6    8B7C24 28       MOV     EDI,DWORD PTR SS:[ESP+28]
0040B2AA    FC              CLD
0040B2AB    B2 80           MOV     DL,80
0040B2AD    33DB            XOR     EBX,EBX
0040B2AF    A4              MOVS    BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
0040B2B0    B3 02           MOV     BL,2
0040B2B2    E8 6D000000     CALL    UnPackMe.0040B324
0040B2B7  ^ 73 F6           JNB     SHORT UnPackMe.0040B2AF
0040B2B9    33C9            XOR     ECX,ECX
0040B2BB    E8 64000000     CALL    UnPackMe.0040B324
0040B2C0    73 1C           JNB     SHORT UnPackMe.0040B2DE
0040B2C2    33C0            XOR     EAX,EAX
0040B2C4    E8 5B000000     CALL    UnPackMe.0040B324
0040B2C9    73 23           JNB     SHORT UnPackMe.0040B2EE
0040B2CB    B3 02           MOV     BL,2

Теперь стоим здесь. Видно, что тут расшифровывается код, мало того - это до боли знакомый еще из EXAMPLES к masm32 - aPLib. Чистый код, не замутненный всякими там JMP, JO и т.д. Ставим бряк на последний POPAD/RETN 8 и благополучно выходим из подпрограммы. Ставим Memory breakpoint on write на все тот же .text и пропускаем все попадания, кроме этого:

003216BD    8907            MOV     DWORD PTR DS:[EDI],EAX                       ; kernel32.CreateThread
003216BF    5A              POP     EDX
003216C0    0FB642 FF       MOVZX   EAX,BYTE PTR DS:[EDX-1]
003216C4    03D0            ADD     EDX,EAX
003216C6    59              POP     ECX
003216C7    42              INC     EDX
003216C8    83C7 04         ADD     EDI,4
003216CB  ^ E2 E5           LOOPD   SHORT 003216B2
003216CD  ^ EB B0           JMP     SHORT 0032167F
003216CF    64:A1 30000000  MOV     EAX,DWORD PTR FS:[30]
003216D5    85C0            TEST    EAX,EAX
003216D7    78 0F           JS      SHORT 003216E8
003216D9    8B40 0C         MOV     EAX,DWORD PTR DS:[EAX+C]
003216DC    8B40 0C         MOV     EAX,DWORD PTR DS:[EAX+C]
003216DF    8140 20 0020000>ADD     DWORD PTR DS:[EAX+20],2000
003216E6    EB 23           JMP     SHORT 0032170B
003216E8    6A 00           PUSH    0
003216EA    FF95 0A190000   CALL    NEAR DWORD PTR SS:[EBP+190A]
003216F0    85D2            TEST    EDX,EDX
003216F2    79 17           JNS     SHORT 0032170B
003216F4    837A 08 FF      CMP     DWORD PTR DS:[EDX+8],-1
003216F8    75 11           JNZ     SHORT 0032170B
003216FA    52              PUSH    EDX
003216FB    8B52 04         MOV     EDX,DWORD PTR DS:[EDX+4]
003216FE    8142 50 0020000>ADD     DWORD PTR DS:[EDX+50],2000
00321705    5A              POP     EDX
00321706    8B52 0C         MOV     EDX,DWORD PTR DS:[EDX+C]
00321709    FE02            INC     BYTE PTR DS:[EDX]
0032170B    8B85 1A190000   MOV     EAX,DWORD PTR SS:[EBP+191A]
00321711    83F8 01         CMP     EAX,1
00321714    0F85 7D010000   JNZ     00321897
0032171A    8BBD 22190000   MOV     EDI,DWORD PTR SS:[EBP+1922]
00321720    03FD            ADD     EDI,EBP
00321722    8DB5 AB180000   LEA     ESI,DWORD PTR SS:[EBP+18AB]
00321728    8B07            MOV     EAX,DWORD PTR DS:[EDI]
0032172A    0BC0            OR      EAX,EAX
0032172C    0F85 51010000   JNZ     00321883
00321732    68 00FE9F07     PUSH    79FFE00
00321737    53              PUSH    EBX
00321738    E8 5D000000     CALL    0032179A

Обратите внимание на LOOPD, JMP и MOV - это признак (точнее, сигнатура), что мы остановились правильно. Снимаем breakpoint on write с секции, ставим бряк на выделенную жирным инструкцию и скромно, подобно падающему с дерева листу, наблюдаем за подгрузкой библиотек.
Ну вот теперь-то, мы так долго этого ждали и наконец - ставим break-on-access на секцию .text, отпускаем прогу и радуемся (ну, сначала нажав Ctrl+A для анализа кода):

00401000   .  E8 4D320000   CALL    UnPackMe.00404252                            ;  OEP!!!!!!
00401005   .  6A 00         PUSH    0
00401007   .  E8 C2310000   CALL    UnPackMe.004041CE
0040100C   .  A3 94724000   MOV     DWORD PTR DS:[407294],EAX
00401011   .  33D2          XOR     EDX,EDX
00401013   .  52            PUSH    EDX
00401014   .  68 28104000   PUSH    UnPackMe.00401028
00401019   .  52            PUSH    EDX
0040101A   .  6A 64         PUSH    64
0040101C   .  50            PUSH    EAX
0040101D   .  E8 00320000   CALL    UnPackMe.00404222
00401022   .  50            PUSH    EAX
00401023   .  E8 8E310000   CALL    UnPackMe.004041B6

Это наш OEP, с чем друг друга и поздравляем!
Но что такое?? Почему ImpRec не находит ни одной функции? В нормальной программе уже сразу с OEP видны call MessageBox, call GetModuleHandle и подобные (вспомнили OEP Дельфи? верной дорогой идете .))! Но у нас такого нету.. Посмотрим.. Зайдем к примеру в первый же CALL и видим:

00404198  /$  90            NOP
00404199  |.  E8 0DD7F1FF   CALL    003218AB
0040419E  |$  90            NOP
0040419F  |.  E8 07D7F1FF   CALL    003218AB
004041A4  |$  90            NOP
004041A5  |.  E8 01D7F1FF   CALL    003218AB
004041AA  |$  90            NOP
004041AB  |.  E8 FBD6F1FF   CALL    003218AB
004041B0  |$  90            NOP
004041B1  |.  E8 F5D6F1FF   CALL    003218AB
004041B6  |$  90            NOP
004041B7  |.  E8 EFD6F1FF   CALL    003218AB
004041BC  |$  90            NOP
004041BD  |.  E8 E9D6F1FF   CALL    003218AB
004041C2  |$  90            NOP
004041C3  |.  E8 E3D6F1FF   CALL    003218AB
004041C8  |$  90            NOP
004041C9  |.  E8 DDD6F1FF   CALL    003218AB
004041CE  |$  90            NOP
004041CF  |.  E8 D7D6F1FF   CALL    003218AB
004041D4  |$  90            NOP
004041D5  |.  E8 D1D6F1FF   CALL    003218AB
004041DA  |$  90            NOP
004041DB  |.  E8 CBD6F1FF   CALL    003218AB
004041E0  |$  90            NOP
004041E1  |.  E8 C5D6F1FF   CALL    003218AB
004041E6  |$  90            NOP
004041E7  |.  E8 BFD6F1FF   CALL    003218AB
004041EC  |$  90            NOP
004041ED  |.  E8 B9D6F1FF   CALL    003218AB
004041F2  |$  90            NOP
004041F3  |.  E8 B3D6F1FF   CALL    003218AB
004041F8  |$  90            NOP
004041F9  |.  E8 ADD6F1FF   CALL    003218AB
004041FE  |$  90            NOP

Нет, вы не сошли с ума, так и есть! Просто таблица импорта бессовестно сперта в неизвестном направлении. Точнее, в относительно неизвестном. Начинающие анпакеры часто пугаются таких извращений и жмут Alt+F2, но мы все-таки доведем дело до конца, как бы ни было страшно, противно, мерзко и т.д. Попробуем разобраться. То, что программа выполняется эквивалентно тому что ее можно распаковать. Мало того, необходимо! Процессор загружает левый код, а ведь в это время вы могли бы посчитать структуру какого-нибудь нуклеотида, участвуя в проекте распределенных вычислений!
Каким образом программа узнает о том куда надо будет уйти с этого CALL? Вспомним как действует инструкция CALL. В стек заносится адрес следующей после CALL инструкции и идет переход на подпрограмму. Кстати! Команда CALL xxxxxx в 32-разрядном коде занимает ровно 5 байт! Но у нас еще есть NOP, занимающий, как вы уже знаете, 1 байт. 5+1=6 байт. Запомним это значение, дабы не было непоняток. Дело вот в чем. В стек заносится не адрес CALL, а адрес СЛЕДУЮЩИЙ после CALL. И в декодировании используется именно он. Это важный момент, может так получиться что весь импорт вроде бы восстановлен, а программа вылетает, т.к. при ошибке таблица получится "сдвинутая" и вместо GetModuleHandle получится ExitProcess. Я сам попался первый раз :) Учите матчасть, товарищи!
Зайдем же скорее в этот чудный CALL 3218ABh и позырим чудеса заморские.

003218AB    50              PUSH    EAX                         ;Непонятно
003218AC    8BC4            MOV     EAX,ESP                     ;Уже понятнее
003218AE    60              PUSHAD                              ;Сохраняем регистры и смотрим резко ниже - там POPAD :)
003218AF    8BD8            MOV     EBX,EAX                     ;EBX = ESP
003218B1    E8 04000000     CALL    003218BA                    ;перескакиваем через следующие 4 байта
003218B6    0000            ADD     BYTE PTR DS:[EAX],AL        ;т.е. вот это вот
003218B8    3200            XOR     AL,BYTE PTR DS:[EAX]        ;не выполнится :)
003218BA    5D              POP     EBP                         ;EBP = 3218B6h, еще помните про коварный CALL? :)
003218BB    8B6D 00         MOV     EBP,DWORD PTR SS:[EBP]      ;EBP = 320000h, посмотрите на 4 байта, да это же DWORD!
003218BE    8B7B 04         MOV     EDI,DWORD PTR DS:[EBX+4]    ;EDI = АДРЕС ВОЗВРАТА!
003218C1    8BB5 22190000   MOV     ESI,DWORD PTR SS:[EBP+1922] ;ESI = dword[321922h] = смещение какой-то таблички.
003218C7    03F5            ADD     ESI,EBP                     ;ESI = полный адрес, в EBP была база секции.
003218C9    8B06            MOV     EAX,DWORD PTR DS:[ESI]      ;а это - сюрприз :) посчитаем немного
003218CB    33D2            XOR     EDX,EDX                     ;EAX = DWORD из таблички, EDX = 0
003218CD    B9 02000000     MOV     ECX,2                       ;умножаем EAX на 2
003218D2    F7E1            MUL     ECX                         ;вотъ
003218D4    D1E8            SHR     EAX,1                       ;делим на 2, простым сдвигом
003218D6    3BF8            CMP     EDI,EAX                     ;и сравниваем с адресом возврата
003218D8    75 0A           JNZ     SHORT 003218E4              ;если не равны, то берем следующий адрес возврата
003218DA    0AD2            OR      DL,DL                   ;а если равны, то интерес представляет DL
                                                            ;он остался после MUL ECX. EDX здесь - старший DWORD
003218DC    75 04           JNZ     SHORT 003218E2 ----+    ;если DL не ноль, то идем на Блок2
003218DE    EB 09           JMP     SHORT 003218E9     |    ;иначе прыгаем на Блок1 ------------------+
003218E0    EB 02           JMP     SHORT 003218E4     |                                              |
003218E2    EB 10           JMP     SHORT 003218F4 <---+                                              |
003218E4    83C6 08         ADD     ESI,8                                                             |
003218E7  ^ EB E0           JMP     SHORT 003218C9                                                    |
-----  Блок1  ----------------------------------------------                                          |
003218E9    8B46 04         MOV     EAX,DWORD PTR DS:[ESI+4] ;интересно, EAX = какой-то адрес <-------+
003218EC    8903            MOV     DWORD PTR DS:[EBX],EAX   ;т.к. EBX = ESP, значение инструкции очевидно
003218EE    61              POPAD                            ;восстанавливаем регистры
003218EF    58              POP     EAX                      ;посмотрите, в [EBX] лежит адрес из таблички!
003218F0    8B00            MOV     EAX,DWORD PTR DS:[EAX]   ;по этому адресу лежит адрес API!
003218F2    FFE0            JMP     NEAR EAX                 ;уходим на импорт, дальнейшее неважно
-----  Блок2  ----------------------------------------------
003218F4    8B46 04         MOV     EAX,DWORD PTR DS:[ESI+4]
003218F7    8903            MOV     DWORD PTR DS:[EBX],EAX
003218F9    61              POPAD
003218FA    58              POP     EAX
003218FB    83C4 04         ADD     ESP,4
003218FE    8B00            MOV     EAX,DWORD PTR DS:[EAX]
00321900    FFE0            JMP     NEAR EAX                 ;уходим на импорт, дальнейшее неважно

JNZ по 3218DCh запросто может прыгнуть на 3218F4h, видимо автор спецально оставил такой код, собираясь дальше развить свою инженерную мысль. Значит не зря мы мучаемся :)
Смотрим, Блок1 и Блок2 отличаются только указателем стека после вызова импорта. Логика очевидна: так как переходники протектора у нас в виде CALL, для импорта необходимо подставить адрес возврата в главную программу, а не в таблицу импорта (а текущий адрес возврата именно туда и указывает).
Теперь все встало на свои места! Нам нужно заменить NOP/CALL xxxxxx на эквивалентные по размеру инструкции, переходящие по заданному адресу. Первое (а значит верное), что пришло в голову - это FF 25 XX XX XX XX, т.е. инструкция вида CALL [адрес], которая весит ровно 6 байт. Но таблица спертого импорта порой достигает двух-трех килобайт, поэтому мы автоматизируем этот процесс. Вот исходник программы на C++ (для MSVC 6.0, но легко компилится борландовским bcc32), которая проделает всю грязную работу за нас:

#pragma comment (linker,"/NODEFAULTLIB /merge:.rdata=.data /filealign:0x200")
#pragma comment (linker," /merge:.data=.text /merge:.bss=.text /merge:.text=kR01eG /section:kR01eG,WREX /filealign:0x200")
#pragma comment (linker,"/entry:main /subsystem:windows")
#include 
#define width 200
#define height 100


long __stdcall WndProc(HWND,UINT,WPARAM,LPARAM);

MSG msg;
HWND win1,but1,edit1,edit2,edit3;
HINSTANCE hInst;
char clsname[]="tb002imprec";
WNDCLASSEX wc = {sizeof(WNDCLASSEX),0,&WndProc,0,0,0,0,
		0,(HBRUSH)(COLOR_BTNFACE+1),0,clsname,0};
LOGFONT fnt = {15,9,0,0,0,0,0,0,ANSI_CHARSET,0,0,0,0,"Verdana"};
LOGFONT fnt2 = {12,5,0,0,0,0,0,0,ANSI_CHARSET,0,0,0,0,"Tahoma"};
HFONT hFont;
char buffer[]={0xFF,0x25,0x00,0x00,0x00,0x00};
long position;

long strtohex(char* str,int len) {
	char t;
	long sum=0;
	while (len-->0) {
		t=str[0];
		t-=0x30;
		if (t>9) t-=7;
		sum<<=4;
		sum+=t;
		str++;
	}
	return sum;
}

void do_work() {
	long iatstart,iatend,t;
	HANDLE hProcess;

	hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,0,strtohex((char*)clsname,GetWindowText(edit3,(char*)clsname,8)));
	iatstart=strtohex((char*)clsname,GetWindowText(edit1,(char*)clsname,8));
	iatend=iatstart+strtohex((char*)clsname,GetWindowText(edit2,(char*)clsname,8));
	t=iatstart;
	while (t<=iatend) {
		ReadProcessMemory(hProcess,(void*)t,(void*)&position,4,0);
		position<<=1;
		position/=2;
		position-=6;
		ReadProcessMemory(hProcess,(void*)(t+4),(void*)(buffer+2),4,0);
		WriteProcessMemory(hProcess,(void*)position,&buffer,6,0);
		t+=8;
	}
	  return;
}

long __stdcall WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) {
	switch(uMsg) {
		case WM_COMMAND:
			if (lParam==(LPARAM)but1) {
				do_work();
				MessageBox(hWnd,"done..","hehe .)",0x40);
			}
			break;
		case WM_CREATE:
			hFont = CreateFontIndirect(&fnt2);
			edit1 = CreateWindowEx(0,"EDIT","Stolen IAT start",WS_BORDER|WS_VISIBLE|WS_CHILD|BS_LEFT,5,10,90,21,hWnd,0,hInst,0);
			SendMessage(edit1,WM_SETFONT,(unsigned int)hFont,0);
			edit2 = CreateWindowEx(0,"EDIT","Stolen IAT size",WS_BORDER|WS_VISIBLE|WS_CHILD|BS_LEFT,5,35,90,21,hWnd,0,hInst,0);
			SendMessage(edit2,WM_SETFONT,(unsigned int)hFont,0);
			edit3 = CreateWindowEx(0,"EDIT","Process ID",WS_BORDER|WS_VISIBLE|WS_CHILD|BS_LEFT,100,10,90,21,hWnd,0,hInst,0);
			SendMessage(edit3,WM_SETFONT,(unsigned int)hFont,0);
			but1 = CreateWindowEx(0,"BUTTON","Recover!",WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON|BS_CENTER,100,35,90,21,hWnd,0,hInst,(void*)200);
			SendMessage(but1,WM_SETFONT,(unsigned int)CreateFontIndirect(&fnt),0);
			break;
		case WM_CLOSE:
			DestroyWindow(hWnd);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default: return DefWindowProc(hWnd,uMsg,wParam,lParam);
	}
	return 0;
}

int main() {
	hInst = GetModuleHandle(0);
	wc.hInstance = hInst;
	wc.hIcon = LoadIcon(hInst,(char*)100);
	wc.hCursor = LoadCursor(0,IDC_ARROW);
	RegisterClassEx(&wc);
	win1 = CreateWindowEx(WS_EX_TOPMOST,clsname,
		"TB0.02 impReX",
		WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_VISIBLE,
		(GetSystemMetrics(SM_CXSCREEN)-width)/2,
		(GetSystemMetrics(SM_CYSCREEN)-height)/2,width,height,0,0,hInst,0);
	ShowWindow(win1,SW_SHOWNORMAL);
	UpdateWindow(win1);
	while (GetMessage(&msg,0,0,0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	ExitProcess(0);
	return 0;
}


Укажем начало спертой таблицы, ее размер и PID программы, все естественно в 16-ричном виде большими буквами (no foolproof! сами себе навредите :)) и нажмем Recover.

Проверяем в отладчике, импорт восстановлен :)

Все! Дампим и прикручиваем импорт. Теперь прога будет в последний раз сопротивляться при попытке снять дамп в LordPE.

Тут можно сделать Correct ImageSize там же в LordPE, после чего программа сдерется запросто, или же юзать PE Tools, там такой шняги нету.
(В Options нужно сначала в групбоксе Task Viewer снять все галки, кроме Delete temp files for PE Editor).

Дамп сняли. Теперь заставим его работать :) Открываем файл в PE Editor из LordPE, лезем в Sections, там каждой секции проставляем:
* RawOffset = VirtualAddress
* RawSize = VirtualSize

Делается это так потому, что мы сняли дамп прямо с памяти, то есть физические адреса и размеры в файле такие же как и в памяти. Еще надо сменить EntryPoint RVA на наш - 1000. Все, жмем Save и OK. Посмотрите, у файла появилась иконка ;)
Восстанавливать импорт бум с помощью ImpRec. На этот раз он все функции нашел, то то же :)

Все здесь конеЦ!

Да, че еще хочецо сказать по поводу такой защиты. Импорт издревле (со времен вин'95) был основной игрушкой самых разных категорий программистов, игрушкой он остался и по сей день. Его ищут вирусы, его шифруют протекторы, мы его восстанавливаем. Такая техника реализована также в популярном ASProtect 2.xx SKE (ну там посложнее чуток, чем в TB :)). В основном ничего нового придумано не было, основной упор сделан на то что если даже распаковщик сможет снять дамп, до системных функций ему не добраться. Это очень сильное заблуждение. Достаточно грамотный и упорный человек достанет все что угодно, и не только импорт. В досе в этом смысле было легче, ничего импортировать не надо было - все работало автономно на прерываниях. Поэтому там использовались в основном антидебаг-трюки, типа установки своего обработчика прерывания или CLI и HLT в самом неожиданном месте.
И о восстановлении импорта еще надо сказать, что необязательно каждый раз использовать ImpRec. Множество людей просто ленятся затереть исходную таблицу импорта и она мирно лежит на своем месте в упакованной программе (в философском смсле :)). После распаковки достаточно лишь изменить Import Table RVA и Import Table Size на оригинальные. Найти таблицу в файле также не представляет особого труда для человека натренированного. Ищется она просто визуально - dword со смещением из файла, 2 нулевых dword-а, 2 dword-а со смещениями. Чем больше таблица, тем легче ее заметить, если она конечно присутствует )

* http://crackworld.stsland.ru/page/works/tbimport.rar



Обсуждение статьи: Распаковка ThunderBolt 0.02 >>>


Комментарии к статье: Распаковка ThunderBolt 0.02

-= XjekaCR =- 23.11.2007 21:08:13
классая статья
---

Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS