Нахождение OEP [Исследование] Subject: Educational Purpose. Target: Any VC++ programm. URL:www.microsoft.com. Author: aSL! Before starting! Все ниже изложенное предназначено только для образовательных целей. I. Вступление Здравствуйте мои маленькие любители прекрасного! :) Вы, наверное, помните, что я обещал открыть целый цикл статей про нахождение OEP без отладчика. Помните? Вот и ладненько... И как успехи? Ну ладно, давайте же займемся этим вплотную... II. Постановка задачи Необходимо найти OEP у программы, написанной на VC++. III. Исследование Необходимые инструменты: IDA 4.x libc.lib из комплекта VC++. У меня будет от шестых. Итак, приступим... Что мы имеем. Я взял и написал простенькую Win32 программулину на сях. Исходники ее весьма и весьма сложны :))): #pragma comment(linker,"/FILEALIGN:512 /MERGE:.rdata=.text /MERGE:.data=.text /SECTION:.text,EWR /IGNORE:4078") int main(void) { return 0; } Сразу же вопрос: а зачем такая #pragma? Ответ: так я говорю линкеру, что неплохо было бы нашему файлику иметь все в одной секции: экономия на место, однако. После компиляции выходной .exe получился весьма и весьма большим. (Все настройки были по дефолту). К чему я это: Естественно, напрашивается вопрос: а почему? Конечно, как и в случае с делфями тут компилер приделывает туевую хучу своих .lib'ов. Взглянем-ка мы на "Project -> Project Options -> Link -> Object/Library modules". Увидали сколько их всех? Стираем их всех нафиг. Также не забываем поставить галку "Ignore default libraries". Нечего что-то там прилинковывать без нашего участия. Сделали? Жмем на "Rebuild all". Тут нас линкер и обматерил, что: LINK : error LNK2001: unresolved external symbol _mainCRTStartup Угу... Что-то мне подсказывает, судя по названию, что тут-то и собака зарыта :) Почему? Да просто этот код встречается в дефолтных библиотеках типа libc.lib сотоварищи. Нашли эту строчку там? И мне кажется, что именно эта гадость и вызывается где-то в начале. Добавим libc.dll к списку используемых библиотек. Опять давим "Rebuild all". Хм... Судя по именам, что-то он хочет из кернеля вызвать, да не может. Добавим kernel32.lib. О-па! Скомпилировалось. Ну что ж... Будем копать libc.lib. Для этих целей нам понадобится еще lib.exe из состава VC++. Запускаем (для удобности скопировав в отдельную директорию lib.exe и libc.lib): LIB.EXE /LIST LIBC.LIB>1 Получаем длинююююющий список всех .obj, что запрятаны в .lib. Какая же из них наша. Что-то мне подсказывает, что она должна иметь crt и имени. Таких набралось не так-то много. Начнем. Первой я попробую crt0init.obj. Что-то имя мне это нравится... LIB.EXE /EXTRACT:build\intel\st_obj\crt0init.obj LIBC.lib Посмотрим туда. Нет. А зря :) Смотрим дальше. Я выбрал crt0.obj. (Приложение не оконное и wincrt0.obj мне что-то не нравится :))) LIB.EXE /EXTRACT:build\intel\st_obj\crt0.obj LIBC.lib Смотрим вовнутрь. Опа! Она. Загружаем ее в IDA. Получаем следующий листинг: public _mainCRTStartup _mainCRTStartup proc near var_20 = dword ptr -20h var_1C = dword ptr -1Ch var_18 = dword ptr -18h var_14 = dword ptr -14h var_4 = dword ptr -4 push ebp mov ebp, esp push 0FFFFFFFFh push offset $T17244 push offset __except_handler3 mov eax, dword ptr fs:__except_list push eax mov dword ptr fs:__except_list, esp sub esp, 10h push ebx push esi push edi mov [ebp+var_18], esp call dword ptr ds:__imp__GetVersion@0 xor edx, edx mov dl, ah mov dword ptr ds:__winminor, edx mov ecx, eax and ecx, 0FFh mov dword ptr ds:__winmajor, ecx shl ecx, 8 add ecx, edx mov dword ptr ds:__winver, ecx shr eax, 10h mov dword ptr ds:__osver, eax push 0 call __heap_init pop ecx test eax, eax jnz short loc_0_7F push 1Ch call _fast_error_exit pop ecx loc_0_7F: ; CODE XREF: _mainCRTStartup+61j and [ebp+var_4], 0 call __ioinit call dword ptr ds:__imp__GetCommandLineA@0 mov dword ptr ds:__acmdln, eax call ___crtGetEnvironmentStringsA mov ds:__aenvptr, eax call __setargv call __setenvp call __cinit mov eax, dword ptr ds:__environ mov dword ptr ds:___initenv, eax push eax push dword ptr ds:___argv push dword ptr ds:___argc call _main add esp, 0Ch mov [ebp+var_1C], eax push eax call _exit $L17239: ; DATA XREF: .rdata:000000F8o mov eax, [ebp+var_14] mov ecx, [eax] mov ecx, [ecx] mov [ebp+var_20], ecx push eax push ecx call __XcptFilter pop ecx pop ecx $L17241: retn _mainCRTStartup endp ; sp = -34h При дизассемблировании реального .exe я получил такой код: :00401683 55 :00401684 8BEC :00401686 6AFF :00401688 6810134000 :0040168D 6848214000 push ebp mov ebp, esp push FFFFFFFF push 00401310 push 00402148 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040161B(C) :00401692 64A100000000 :00401698 50 :00401699 64892500000000 :004016A0 83EC10 :004016A3 53 :004016A4 56 :004016A5 57 :004016A6 8965E8 :004016A9 FF1504104000 :004016AF 33D2 :004016B1 8AD4 :004016B3 8915743E4000 :004016B9 8BC8 :004016BB 81E1FF000000 :004016C1 890D703E4000 :004016C7 C1E108 :004016CA 03CA :004016CC 890D6C3E4000 :004016D2 C1E810 :004016D5 A3683E4000 :004016DA 6A00 :004016DC E833090000 :004016E1 59 :004016E2 85C0 :004016E4 7508 :004016E6 6A1C :004016E8 E89A000000 :004016ED 59 mov eax, dword ptr fs:[00000000] push eax mov dword ptr fs:[00000000], esp sub esp, 00000010 push ebx push esi push edi mov dword ptr [ebp-18], esp call dword ptr [00401004] xor edx, edx mov dl, ah mov dword ptr [00403E74], edx mov ecx, eax and ecx, 000000FF mov dword ptr [00403E70], ecx shl ecx, 08 add ecx, edx mov dword ptr [00403E6C], ecx shr eax, 10 mov dword ptr [00403E68], eax push 00000000 call 00402014 pop ecx test eax, eax jne 004016EE push 0000001C call 00401787 pop ecx И так далее и тому подобное... Чуете чем пахнет??? Уже можно так составить строку для поиска: 558BEC6AFF68????????68????????64A1????????5064????????????83EC105356578965E8FF 15????????33D28AD4. По моему, хватит :)). При желании добавьте еще... Я специально откомпилировал с разными версиями библиотек и посмотрел, что будет. Ну что я могу сказать... Переборщили мы малость, но код до FF15 везде одинаковый, дальше отличается, но самую малость. Так что финальная версия строки: 558BEC6AFF68????????68????????64A1????????5064????????????83EC105356578965E8 IV. Подводим итоги: Мне действительно нечего сказать, поскольку OEP мы нашли. Также, хочу отметить, что распознать VC++ приложение оччень просто по строке "Microsoft Visual C++ runtime library" в сегменте данных. Далее, я взял UnPack 2.1, который может определять компиляторы по такой же видимо технологии. Он сказал, что мои .exe от "Microsoft Visual C++ 5.0 compiler". Значит, этот код там тоже не менялся. Вот собственно и все! :)