и озадачиваем ее нашим исполнимым
Итак, давайте проведем первое знакомство с этим плодом человеческого гения... Запускаем ИДУ и озадачиваем ее нашим исполнимым файлом (File > Open).
Вот что мы увидим:
Существуют две области применения сайса - отладка собственных программ и исследование чужих, так называемый reverse ingeneering. Для начала давайте научимся использовать сайс в качестве инструмента для отладки и изучения собственных приложений.
Что мы имеем в этом случае? Исходные тексты программы, и как следствие - возможность откомпилировать ее отладочную версию, т.е. тот же экзешник, но содержащий, помимо всего прочего, еще и кучу дополнительной информации. Как в самом исполняемом файле, так и в специально для этой цели сгенерированных дополнительных файлах.
Итак, мы должны:
1. Сассемблировать исходник с ключем Zi: ml /c /coff /Zi src.asm
В результате этого мы получим объектный файл, содержащий отладочную информацию для отладчика CodeView. Легко заметить, что размер этого файла намного больше, чем у его "нормального" аналога.
2. Слинковать объектный файл с ключами /DEBUG и /DEBUGTYPE:CV link.exe /SUBSYSTEM:CONSOLE /DEBUG /DEBUGTYPE:CV src.obj
После этого, помимо экзешника, мы получим отладочные файлы src.ilk и simple.pdb, Microsoft Linker Database и Microsoft C/C++ program database соответственно.
Теперь загружаем нашу отладочную версию программы в отладчик. Для этого запускаем Symbol Loader:
Мы привыкли к тому, что извлекать данные из стека можно только повинуясь очередности LIFO. А что, если нам понадобилось обратиться к произвольному элементу стека? Один из возможных способов мы уже рассмотрели: это изменение значения регистра esp/sp плюс команда pop. Это далеко не совсем хорошая идея, и вам не стоит издеваться над стеком таким изощренным способом. Если, конечно же, вы не хотите уподобляться Штирлицу и Мюллеру, которые стреляли по очереди...
Напомню: регистр ebp/bp ведет себя приблизительно таким же образом, как и хорошо нам знакомый ebx/bx. То есть он может выполнять роль базы.
Напомню, что, например, следующий код: mov ebx,12FFC0h mov al,[ebx]
присвоит регистру AL значение байта по адресу 12FFC0 из сегмента, задаваемого регистром DS.
Точно таким же образом можно использовать и регистр ebp/bp. Говоря другими словами, это один из немногих регистров, которые можно "брать в квадратные скобки" не увеличивая при этом размер инструкции :). То есть (и это будут уже третьи слова) он позволяет работать с ячейкой памяти, адрес которой находится в регистре.
Проиллюстрирую это на простом примере. Допустим, занесли вы в стек разных параметров кучу: адрес значение 0012FFC4 77E7EB69 0012FFC8 0047E4AC 0012FFCC 0012DAB4 0012FFD0 7FFDF080
И возжелалось вам в силу какой-нибудь нездоровой производственной необходимости прочитать "здесь и сейчаc", например, предпоследний элемент. В этом случае делаем вот что: mov ebp,esp mov eax,[ebp+4]
Расшифровываю. Мы принимаем адрес самого последнего из записанных в стек элемента за точку отсчета, и путем прибавления к этой "точке отсчета" четвёрок можно легко получить доступ к тому элементу стека, который нашей программерской душеньке возжелался. В принципе, в данном примере можно было бы использовать ESP вместо EBP, но, во-первых, должны же мы были показать использование EBP, :) а, во-вторых, в больших фрагментах кода использование ESP непосредственно имеет свои недостатки (больший размер инструкций и необходимость отслеживать изменение вершины стека).
Вот именно такое безобразие и называется "организация произвольного доступа к данным внутри стека".
Содержание раздела