Здравствуйте, я в реверсировании начинающий, поэтому такой вопрос. читаю сейчас книгу Касперски "Искусство дизассемблирования", ковыряю примерчик с идентификацией объектов. вроде ничего непонятного нету, пока не начнешь все это делать на практике своими руками. вобщем скомпилировал пример (в аттаче), при открытии его в IDA попадаю, как водится, в Entry Point, где лежат инструкции вида: Код (Text): .text:0040138F call sub_403E34 .text:00401394 jmp loc_40123D ходил в обоих направлениях. по пути попадались системные вызовы (простите, я линуксоид) типа GetComandLineA (ну еще бы, приложение-то консольное). нигде ничего похожего на мою main не было видно. подскажите как найти? хочется вживую поковырять, а не на бумагу смотреть. спасибо.
попробуй в IDA найти строку "MyClass\n" и перейти по перекрестной ссылке. попадешь в MyClass, а оттуда уже в main
Entry Point – call – jmp? Немаловероятно, что первый call – это вызов __security_init_cookie. Для поиска main надо сразу перейти по jmp и просто смотреть по коду (страницу или две): у main три параметра, достат. кол. системных вызовов необходимо для формирования этих параметров. Ещё помнить, что зачастую библиотечный код (в т.ч. стартовый код до вызова main) размещается линкером _после_ пользовательского.
milo вызви из main MessageBox, потом в иде его легко найти будет. Увидишь, что там откуда вызывается.
а можно еще загрузить (если сама не загрузилась) flirt-сингатуру: File - Load file - FLIRT signature file. там в списке ищете подходящий компилятор.
у меня есть одна особенность при чтении книг: первые пару сотен страниц я читаю за два дня, остальные (700) я растягиваю на ближайшие пару лет а к тому времени забываю все, что прочитал ранее. ну так вот, вчера на сон грядущий решил полистать оглавление и... вот она глава - "идентификация стартовой функции". сегодня вечером после работы попробую и отпишусь, если кому интересно.
вот контекстным поиском нашел свою main-функцию. Код (Text): .text:00401050 probably_main proc near ; CODE XREF: .text:00401333p .text:00401050 .text:00401050 var_8 = dword ptr -8 .text:00401050 var_4 = dword ptr -4 .text:00401050 .text:00401050 push ebp .text:00401051 mov ebp, esp ; çàïîìèíàåì êàäð ñòåêà .text:00401053 sub esp, 8 ; ðåçåðâèðóåì ìåñòî ïîä îáúåêò. .text:00401053 ; ìîé îáúåêò êàê ðàç çàíèìàåò 8 áàéò (áåç ôóíêöèé) .text:00401056 push 8 ; íåêèé àðãóìåíò .text:00401058 call inner_func1 ; âðÿä ëè new, ò.ê. íåò ïðîâåðîê âîçâðàùåííîãî ðåçóëüòàòà .text:0040105D add esp, 4 ; î÷èùàåò ñòåê .text:00401060 mov [ebp+var_8], eax .text:00401063 mov eax, [ebp+var_8] .text:00401066 mov [ebp+var_4], eax .text:00401069 mov ecx, [ebp+var_4] ; ecx - ÿâíî óêàçàòåëü íà this .text:0040106C call demo ; ôóíêöèÿ ÷ëåí-êëàññà demo() .text:00401071 mov ecx, [ebp+var_4] .text:00401074 mov dword ptr [ecx], 777h .text:0040107A xor eax, eax .text:0040107C mov esp, ebp .text:0040107E pop ebp .text:0040107F retn .text:0040107F probably_main endp как видно из первого аттача, в main'е сначала выделяется память и потом вызывается конструктор. Как пишет Крис в "Искусстве дизассемблирования" результат оператора new, как правило, проверяется на 0 (память выделить не удалось) и лишь затем вызывается конструктор класса. очевидно, что inner_func1 возвращает указатель на this. вопрос: где тут оператор new и конструктор, если после вызова inner_func1 сразу идет вызов метода класса? inner_func1 изнутри выглядит так: Код (Text): .text:004011AF inner_func1 proc near ; CODE XREF: probably_main+8p .text:004011AF .text:004011AF var_C = byte ptr -0Ch .text:004011AF arg_4 = dword ptr 8 .text:004011AF .text:004011AF mov edi, edi .text:004011B1 push ebp .text:004011B2 mov ebp, esp .text:004011B4 sub esp, 0Ch ; ðåçåðâèðóåò 12 áàéò .text:004011B7 jmp short first_jump .text:004011B9 ; --------------------------------------------------------------------------- .text:004011B9 .text:004011B9 second_jump: ; CODE XREF: inner_func1+22j .text:004011B9 push [ebp+arg_4] ; = 8 .text:004011BC call sub_402A1C .text:004011C1 pop ecx .text:004011C2 test eax, eax .text:004011C4 jz short loc_4011D5 ; åñëè åùå ðàç 0 .text:004011C6 .text:004011C6 first_jump: ; CODE XREF: inner_func1+8j .text:004011C6 push [ebp+arg_4] .text:004011C9 call new_or_constr ; âåðîÿòíûé îïåðàòîð new .text:004011CE pop ecx .text:004011CF test eax, eax .text:004011D1 jz short second_jump ; åñëè âîçâðàùåííûé ðàííåå âûçâàííîé ôóíêöèåé ðåçóëüòàò ðàâåí 0 .text:004011D1 ; òî èäåò êóäà-òî îáðàáàòûâàòü .text:004011D3 leave .text:004011D4 retn причем если new_or_constr и есть new, то где, конструктор? или его нету потому что я его не написал руками? хотя, я всегда думал, что конструктор по умолчанию генерируется компилятором (так и есть!), если он явно не задан. вопросов море...
а конструктор не обязательно должен вызываться call'ом. Он может быть прямо в коде main (inline-функция). ну, а данные класса могут в стеке находится. (в стеке main).
milo в твоем классе определены две переменные. а что мы видим в probably_main? Код (Text): .text:00401050 var_8 = dword ptr -8 .text:00401050 var_4 = dword ptr -4
а в probably_main мы видим, что у нас есть два указателя. значение одного из них находится на 4 байта ниже ebp, другого на 8. ну а какие значения там хранятся можно посмотреть, я думаю, дебаггером. вот только мне непонятно зачем он швыряет эти данные туда обратно вот тут: Код (Text): .text:00401060 mov [ebp+var_8], eax .text:00401063 mov eax, [ebp+var_8] .text:00401066 mov [ebp+var_4], eax .text:00401069 mov ecx, [ebp+var_4] ну последняя строчка предельно ясна - готовит this указатель. а в первых двух-то зачем туда-сюда швыряться?
с оптимизацией я убьюсь разбираться TSS, первая строчка: копирует eax в [ebp+var_8], вторая: копирует [ebp+var_8] в eax. тоже самое, но наоборот. зачем?? ну а с третим понятно, потому что не умеет. вопрос в том, зачем первые две швыряет туда сюда?
Судя по дебажной информации, переменной var_8 не существует (последняя строчка вывода): Код (Text): C:\desktop>dia2dump -sym main main3.pdb SymIndex: 0x1 SymTag: 0x5 Name: main ... Function : static, [00001080][0001:00000080], len = 00000030, _main Function attribute: Function info: asyncheh FuncDebugStart : static, [00001086][0001:00000086] FuncDebugEnd : static, [000010AC][0001:000000AC] Data : ebp Relative, [FFFFFFFC], Local, Type: class MyClass *, zzz C:\desktop> По всей видимости, это просто особенность работы компилятора при отключённой оптимизации. Вот как выглядит эта функция при включённой оптимизации: Код (Text): C:\desktop>cl /Fm /Zi /Ox main3.cpp C:\desktop>dumpbin /disasm main3.obj _main: 00000040: 56 push esi 00000041: 6A 08 push 8 00000043: E8 00 00 00 00 call ??2@YAPAXI@Z 00000048: 68 00 00 00 00 push offset $SG3850 0000004D: 8B F0 mov esi,eax 0000004F: E8 00 00 00 00 call _printf 00000054: 68 00 00 00 00 push offset $SG3845 00000059: E8 00 00 00 00 call _printf 0000005E: 83 C4 0C add esp,0Ch 00000061: C7 46 04 66 06 00 mov dword ptr [esi+4],666h 00 00000068: C7 06 77 07 00 00 mov dword ptr [esi],777h 0000006E: 33 C0 xor eax,eax 00000070: 5E pop esi 00000071: C3 ret Полезные ключи компилятора для исследований: Код (Text): cl /Fm – создать map-файл (показано расположение функций и глобальных переменных) cl /Zi – включить отладочную информацию (сгенерируется файл с инфой – main3.pdb) cl /Ox – включить оптимизацию (там много ключей на самом деле, но этого хватает для подчистки всяких швыряний) Для использования отладочной инфы старыми версиями IDA Pro может понадобится плагин к ней – Determina PDB Loader (хотя локальные переменные всё равно не будут отображаться).
Sol_Ksacap, какая версия IDA у тебя стоит? а то, я смотрю, у тебя библиотечные функции нормально разпознаются (call ??2@YAPAXI@Z) а у меня нет, что начинающему никак не облегчает жизнь.
потому что без включенной оптимизации компилятор делает все постепенно. ему понадобилось записать значение eax в [ebp+var8] и он это сделал, потом (по исходнику) ему понадобилось перекинуть [ebp+var8] в [ebp+var4] и он тоже это сделал. но без оптимизации он даже не подумал о том, что можно просто в обе переменные записать eax, не говоря уже о том, что они просто могут не понадобится и хватит одних регистров.
Это не из IDA Pro листинг – это скопированный из вывода cmd.exe результат выполнения "dumpbin /disasm main3.obj", а main3.obj получен выполнением "cl /Fm /Zi /Ox main3.cpp". Т.е. достаточно указать компилятору "/Zi", и сгенерируется pdb (отладочная инфа) – IDA Pro для полученного таким образом exe-файла выдаст ещё более подробную информацию. То ли с версии 5.4, то ли с 5.3 IDA поддерживает pdb полностью, более ранние её версии – частично.
Sol_Ksacap отлично, спасибо. вот только, я думаю, не всегда будут исходники исследуемой проги, поэтому надо будет учиться обходиться без отладочной информации а насчет map-файлов - у меня старенькая бесплатная IDA, думал пока учиться хватит мне.