А как же без этого?
Еще одна полезная команда - это rs (она же F4), restore the program screen (восстановление экрана программы). А как же без этого? Ведь внешне работа программы заключается вовсе не в выполнении команд процессора и пересылках данных между регистрами ;).
Например в нашем случае программа печатает приглашение ввести строку символов. Мы можем оттрассировать программу до (включительно) строки: 001B:00401046 E8BD000000 CALL _WriteConsoleA и затем нажать на F4, для того чтобы подсмотреть, действительно ли в консольном окне появилась строчка "Type something >". А затем нажать на any key и снова очутиться в отладчике.
Или же, например, выполнив апишную функцию 001B: 00401070 E881000000 CALL _ReadConsoleA
которая "просит" ввести строку символов, нажать на F4 и ввести необходимую строку символов, а по нажатию на Enter (типа "ввод закончен") снова оказаться в отладчике.
Очевидно, что ebp – это некая "точка отсчета", относительно которой адресуются локальные переменные. А что ж у нас в ebp? Смотрим на начало процедуры, и ищем там строчки :00401001 mov ebp, esp :00401003 add esp, 0FFFFFF70h
И медленно ("брюки превращаются... брюки превращаются...") приоткрываем завесу над тайной. "Дело в следующем": ассемблер смотрит, сколько мы задекларировали локальных переменных и какова размерность каждой. На основании этой информации определяется размер фрейма. В нашем случае задекларировано (смотрим исходник): LOCAL InputBuffer[128] :BYTE ;буффер для ввода LOCAL hOutPut :DWORD ;хэндл для вывода LOCAL hInput :DWORD ;хэндл для ввода LOCAL nRead :DWORD ;прочитано байт LOCAL nWriten :DWORD ;напечатано байт
То есть 128 штук байт плюс 4 двойных слова по 4 байта в каждом. Итого для этого всего богатства нужно выделить 144 байт памяти.
Ну и замечательно! Сохраняем адрес вершины стека (память под переменные еще не отведена!) в регистре ebp. Теперь это у нас вовсе не вершина, а "точка отсчёта" для локальных переменных. А саму вершину стека передвигаем на 144 байта "вверх", в сторону младших адресов (там у нас будет область для хранения локальных переменных). Как видите, все очень просто. :)
Задание для медитации: чем будут отличаться генеримые инструкции для директивы addr в случае, если addr будет применяться к аргументам процедуры, а не к локальным переменным.
Если вас смущает то, что для "поднятия планки" используется инструкция add и столь большое число, то вернитесь к выпуску о кодировании отрицательных чисел и особенностях дополнительного кода. Либо поставьте в Иде указатель на смущающее вас число 0FFFFFF70h и нажмите на Ctrl+-, после чего долго и упорно медитируйте. :)
Если подключить фантазию и пару раз протрассировать это безобразие под отладчиком, то получится такая картинка:
Распечатайте её и повесьте над своей кроватью. И пусть она время от времени напоминает вам о смерти...
[C] Serrgio / HI-TECH
© 2002 - all rights reserved and reversed
Содержание раздела