Assembler для Windows


Глава 4. Описание работы с дизассемблером W32Dasm и отладчиком ICE

В данной главе я попытаюсь рассказать о двух моих любимых средствах анализа программ.

I

Программа W32Dasm (Windows Disassembler) представляет собой симбиоз довольно мощного дизассемблера и отладчика. Версия 8.93 программы, наиболее распространенная в настоящее время, может работать не только с РЕ-модулями, но и DOS-, NE-, -LE- модулями. Я намерен довольно полно описать работу с этой программой.

Начало работы. Внешний вид программы показан на Рис. 4.4.1. Меню дополняется панелью инструментов, элементы которой активизируются в зависимости от ситуации.

Рис. 4.4.1. Внешний вид программы W32Dasm.

Как уже было сказано, программа является дизассемблером и отладчиком в одном лице. Это отражено также в двух пунктах меню: "Disassembler" и "Debugger". Соответственно, имеются отдельные настройки для дизассемблера и отладчика. Для дизассемблера имеется всего три опции, касающиеся анализа перекрестных ссылок в условных переходах, безусловных переходах и вызовах процедур. По умолчанию все три опции установлены. Отмена этих опций нежелательна, т.к. снижает информативность дизассемблированного текста. В принципе, это может понадобиться при дизассемблировании очень большой программы, так это несколько ускоряет процесс анализа.

Опций отладчика несколько больше, но они все очевидны. Окно установки опций отладчика изображено на Рис. 4.4.2, все они касаются особенностей загрузки процессов, потоков и динамических библиотек.

Рис. 4.4.2. Опции отлпдчика

Для начала работы с исполняемым модулем достаточно выбрать нужный файл в меню "Disassembler\0pen File...". После этого программа производит анализ модуля и выдает дизассемблированный текст, а также весьма полную информацию о секциях модуля54. W32Dasm весьма корректно распознает API-функции и комментирует их (см. Рис. 4.4.3).

После работы с модулем можно создать проект работы при помощи пункта "Disassembler\Save Disassembler...". По умолчанию проект сохраняется в подкаталог "wpjfiles", который расположен в рабочем каталоге W32Dasm и состоит из двух файлов: с расширением "alf" - дизассемблированный текст, с расширением "wpj" - собственно сам проект. При повторном запуске можно открывать уже не модуль, а проект с помощью пункта "Project\0pen...".

* Possible Reference to String Resource ID=00001: "! >>1I5=85"
|
:00401013 6A01 push 00000001
:00401015 FF3518304000 push dword ptr [00403018]
* Reference To: USER32.LoadStringA, Ord:01A8h
|
:0040101B E8AE000000 Call 004010CE

Puc. 4.4.3. Фрагмент дизассемблированного текста.

Передвижение по дизассемблированному тексту. При передвижении по тексту текущая строка подсвечивается другим цветом, при этом особо выделяются переходы и вызовы процедур. Передвижение облегчается также с помощью пункта меню "Goto":
Goto Code Start - переход на начало листинга;
Goto Program Entry Point - переход на точку входа программы, наиболее важный пункт меню;
Goto Page - переход на страницу с заданным номером, по умолчанию число строк на странице составляет пятьдесят;
Goto Code Location - переход по заданному адресу, в случае отсутствия адреса учитывается диапазон и близость к другим адресам.

Другим способом передвижения по дизассемблированному тексту является пункт "Search" - поиск. Здесь нет никаких отличий от подобных команд других программ.

В случае, если текущая строка находится в команде перехода или вызова процедуры, с помощью кнопок, расположенных на панели инструментов, можно перейти по соответствующему адресу. Такое передвижение можно продолжать, пока Вы не обнаружите нужный фрагмент программы. Но самое приятное здесь то, что можно передвигаться и в обратном направлении. При этом нужные кнопки на панели инструментов автоматически подсвечиваются.

Кроме того, те адреса, куда производится переход, содержат список адресов, откуда производятся переходы. Подсветив строку, где расположен адрес, и дважды щелкнув правой кнопкой мыши по этому адресу, мы перейдем к соответствующей строке.

Данные. Есть несколько вариантов работы с данными.

Во-первых, имеется пункт меню "HexData\Hex Display of Data...", где можно просмотреть содержимое сегментов данных в шестнадцатеричном и строковом варианте. Кроме того, сам код программы также можно просматривать в шестнадцатеричном виде. Для этого используется пункт "HexData\Hex Display of Code...".

Во-вторых, имеется пункт меню "Refs\String Data References". Это весьма мощное и полезное средство. При выборе этого пункта появляется список строк, на которые имеются ссылки в тексте программы. Во всяком случае, это то, что сумел определить дизассемблер при анализе программы. Выбрав нужную строку, можно двойным щелчком перенестись в соответствующее место программы. Если ссылок на данную строку несколько, то, продолжая делать двойные щелчки, мы будем переходить во все нужные места программы. На Рис. 4.4.4 изображено окно ссылок на строковые типы данных.

Рис. 4.4.4. Окно ссылок на строки.

Как видно из рисунка, можно скопировать в буфер выбранную строку или все строки.

Импортированные и экспортированные функции. Список импортированных функций и модулей находится в начале дизассемблированного текста (см. Рис. 4.4.5). Кроме того, список импортированных функций можно получить из меню "Functions\Imports". Выбрав нужную функцию в списке, двойным щелчком можно получить все места программы, где вызывается эта функция. Экспортированные функции также можно получить в соответствующем окне, выбрав пункт "Functions\Exports".

Ресурсы. В начале дизассемблированного текста также описаны и ресурсы, точнее два основных ресурса-меню и диалоговое окно. Со списком этих ресурсов можно работать и в специальных окнах, получаемых с помощью пунктов меню программы "Refs\Menu References" и "Refs\Dialog references". Строковые ресурсы можно увидеть в уже упомянутом окне просмотра перечня строковых ссылок (см. Рис. 4.4.4). Остальные ресурсы данной версии программы, к сожалению, не выделяются.

Операции с текстом. Строки дизассемблированного текста могут быть выделены и скопированы в буфер либо напечатаны. Выделение строки осуществляется щелком левой кнопки мыши, когда курсор мыши расположен в крайнем левом положении. Для выделения группы строк дополнительно используется клавиша Shift. Выделенный фрагмент копируется специальной кнопкой, которая "загорается", когда фрагмент существует, либо отправляется на печатающее устройство.

Загрузка программ для отладки. Загрузить модуль для отладки можно двумя способами. С помощью пункта "Debug\Load Process" загружается для отладки уже дизассемблированный модуль. Пункт же "Debug\Attach to an Active Process" позволяет "подсоединяться" и отлаживать процесс, находящийся в памяти. После загрузки отладчика на экране появляются два окна. Первое окно информационное (Рис. 4.4.6), в документации оно называется "нижним левым окном отладчика". Второе окно управляющее (Рис. 4.4.7), называемое в документации "нижним правым окном отладчика".

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules = 7 (decimal)
Import Module 001: ADVAPI32.dll
Import Module 002: KERNEL32.dll
Import Module 003: MPR.dll
Import Module 004: COMCTL32.dll
Import Module 005: GDI32.dll
Import Module 006: SHELL32.dll
Import Module 007: USER32.dll
+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++
Import Module 001: ADVAPI32.dll
Addr:000D9660 hint(0000) Name: RegCloseKey
Addr:000D966B hint(0000) Name: RegOpenKeyExA
Addr:000D967B hint(0000) Name: KegQueryValueExA
Addr:000D9692 hint(0000) Name: RegSetValueBxA
Import Module 002: KERNEL32.dll

Рис. 4.4.5. Фрагмент списка импортированных модулей и функций.

Информационное окно содержит несколько окон-списков: содержимое регистров микропроцессора, значение флагов микропроцессора, точки останова, содержимое сегментных регистров, история трассировок, история событий, базовые адреса, два дисплея данных. Ниже мы объясним также значения кнопок этого окна.

Обратимся теперь к управляющему окну. Кнопка "Run" запускает загруженную в отладчик программу, кнопка "Pause" приостанавливает работу программы, кнопка "Terminate" останавливает выполнение программы и выгружает ее из отладчика. Кнопки "Step Over" и "Step Into" используются для пошагового исполнения программы. Первая кнопка, выполняя инструкции, "перескакивает" код процедур и цепочечные команды с повторением, вторая кнопка выполняет все инструкции последовательно. Кроме того, имеются кнопки "AutoStep Over" и "AutoStep Into" для автоматического пошагового выполнения программы. В случае API-функций даже использование "Step Into" не приведет к пошаговому выполнению кода функции в силу того, что код функции не доступен для пользовательских программ. Очень удобно, что при пошаговом выполнении происходит передвижение не только в окне отладчика, но и в окне дизассемблера.

Рис. 4.4.6. Первое информационное окно отладчика.

Отмечу, что если Вы подсоединяетесь к процессу, расположенному в памяти, то при выходе из отладчика процесс также будет выгружен из памяти, что может привести к неправильной работе операционной системы.

Работа с динамическими библиотеками. Для отладки динамической библиотеки можно поступить следующим образом. Загрузить в отладчик программу, которая обращается к динамической библиотеке. Затем обратиться к списку используемых динамических библиотек. Возможно, для работы с данной динамической библиотекой Вам понадобится запустить программу и выполнить какую-либо ее функцию. Дважды щелкнув по нужной библиотеке, Вы получите дизассемблированный код данной библиотеки в окне дизассемблера и возможность работать с кодом библиотеки.

Точки останова. В дизассемблированном тексте можно установить точки останова. Для этого следует перейти к нужной строке и воспользоваться клавишей F2 или использовать левую кнопку мыши при нажатой клавише Ctrl. Установка точки останова в окне дизассемблера тут же отражается в информационном окне и в управляющем окне - у отмеченной команды появляется префикс BP*. Удалить точку останова можно тем же способом, что и при установке. Точку останова можно сделать также неактивной. Для этого нужно обратиться к информационному окну и списку точек останова. Выбрав нужный адрес, щелкните по нему правой кнопкой. При этом "звездочка" у данной точки останова исчезнет, а строка в окне дизассемблера из желтой станет зеленой.

Рис. 4.4.7. Второе управляющее окно отладчика.

Быстрый переход к точке останова можно произвести, выбрав ее из списка (информационное окно) и сделав двойной щелчок мышью. Наконец можно установить точки останова на определенные события, такие как загрузка и выгрузка динамической библиотеки, создание и удаление потока и т.д. Все это делается при помощи установки соответствующего флага в информационном окне.

Модификация кода, данных и регистров. Отладчик позволяет модифицировать загруженный в него код. Сделать это можно, обратившись к кнопке "Patch Code" в управляющем окне (см. Рис. 4.4.8). Важно отметить, что модификации подвергается только код, загруженный в отладчик, а не дизассемблированный текст. Найдя нужное место в отлаживаемом коде, и модифицировав его, вы можете тут же проверить результат модификации, запустив программу. Если модификация оказалась правильной, можно приступать уже к модификации самого модуля.

Для модификации регистров и ячеек памяти исполняемого процесса, существует специальная кнопка "Modify Data" на панели информационного окна. Окно расположено на Рис. 4.4.9. Окно несколько загромождено элементами, но, присмотревшись, Вы поймете, что все элементы на своем месте. В верхней части окна расположены текущие значения основных флагов микропроцессора, которые Вы можете изменить. Для того чтобы модифицировать содержимое регистра или ячейку памяти следует вначале установить модифицирующую величину - "Enter Value". Далее следует выбрать нужный регистр и нажать кнопку слева от нее. Чтобы установить старое значение, следует нажать кнопку "R" справа от регистра. Чтобы изменить содержимое ячейки памяти, следует вначале записать адрес ячейки в поле "Mem Lock", а затем воспользоваться кнопкой "Mem". Другие операции, предоставляемые данным окном, также достаточно очевидны.

Рис. 4.4.8. Окно модификации отлаживаемого кода.

Отладчик позволяет выдавать дополнительную информацию о выполняемых API-функциях. Чтобы воспользоваться этим, необходимо сделать следующее. В управляющем окне установите флаги: "Enable Documented API Detail", "Stop Auto On API". Далее запустите программу на выполнение клавишей F5. При прохождении API-функции будет производиться остановка и на экране будет появляться окно с информацией о данной функции,

Поиск нужного места в программе. Часто требуется найти в дизассемблированном коде место, соответствующее месту исполняемой программы. Наиболее эффективно это можно сделать следующим образом. Загружаем в отладчик данный модуль. Запускаем его, доходим до нужного места и нажимаем кнопку "Terminate". В результате подсвеченная строка в дизассемблированном коде окажется как раз в нужном месте. Нужно только иметь в виду, что некоторые программы делают изменения, которые потом продолжают действовать. К таковым относятся, в частности, горячие клавиши.

Рис. 4.4.9. Окно модификации регистров и ячеек памяти. Дополнительные возможности для работы с API.

К использованию программы W32Dasm мы еще вернемся в последующих главах.


54 Хотя W32Dasm работает с разного типа модулями, мы рассматриваем только модули формата РЕ.


II

Отладчик SoftIce (версия 4.05) или просто Ice рассчитан для работы в Windows 9x и Windows NT. 55. Отладчик состоит из собственно отладчика (в английском варианте это "kernel-mode debugger", что можно перевести как "отладчик на уровне ядра"), кроме этого, в пакет SoftIce входит еще символьный загрузчик для загрузки в отладчик исполняемых модулей. Загрузчик позволяет прочитать отладочную информацию для продуктов фирмы Microsoft и Borland.

Итак, что дает отладка при помощи SoftIce?

  • символьная и обычная отладка 32-битных приложений;
  • отладка драйверов для Windows NT и для Windows 9x, отладка 16-битных приложений для MS DOS и Windows, отладка внутренних программ операционной системы;
  • установка обычных точек останова на команду, стоящую по определенному адресу;
  • установка точек останова на операции чтения/записи в память, чтения/записи в порты ввода-вывода;
  • установка точек останова на сообщения Windows;
  • установка условных точек останова, т.е. точек останова, срабатывающих при выполнении определенного условия;
  • получение внутренней информации операционной системы;
  • возможность использования отладчика на удаленной машине и др.

Отладчик SoftIce имеет разные исполнения для Windows 9x и для Windows NT. В первом случае он представляет собой VXD-драйвер и запускается из autoexec.bat (программа WINICE.EXE). В Windows NT он представляет собой драйвер уровня ядра - NTICE.SYS.

Начальная установка. Установка пакета достаточно проста. Основной вопрос, который возникает при установке - выбор видеоадаптера и мыши. Что касается видеоадаптера, то обычно рекомендуют выбрать стандартный VGA-адаптер, и с видеосистемой не будет никаких проблем. Отладчик SoftIce предполагает использование мыши для управления. Однако мышь является второстепенным средством управления, и можно обойтись без нее.

После установки и перезапуска Вам, скорее всего, понадобится еще некоторая настройка файла WINICE.DAT. Вот основные рекомендации.

  1. Строка PHYSMB=32 определяет реальный объем физической памяти в мегабайтах. Укажите реальный объем памяти на Вашем компьютере.
  2. Строка INIT= - определяет оконные установки. Лично мне нравятся установки, определяемые строкой:INIT="SET FONT 1; SET ORIGIN 30 30; LINES 65; WIDTH 90; WR; WF; WD 4; WL; WC 30; X;". Впрочем, Вы сами сможете подобрать параметры по Вашему вкусу. Но главное заключается в том, что, открыв окно отладчика, можно оперативно изменить существующие установки.
  3. В конце файла установок стоят строки типа ;EXP=c:\windows\system\kernel32.dll - снимите с них комментарий. Это необходимо сделать, чтобы отладчик распознавал импортируемые приложением функции стандартных динамических библиотек.
  4. В Windows 9x SoftIce при инсталляции помещает в конце файла AUTOEXEC.BAT строку типа C:\ICE\WINICE.EXE. При желании Вы всегда можете поставить комментарий на эту строку.

Загрузка программы для отладки. Для загрузки приложения в отладчик в пакете SoftIce имеется специальная программа LOADER32.EXE. Она используется для загрузки 32-битных приложений. Для загрузки 16-битных приложений используются утилиты, расположенные в подкаталоге Util16.

Итак, вернемся к программе LOADER32.EXE. Вид загрузчика показан на Рис. 4.4.10. Последовательность действий для загрузки программы в отладчик следующая: открыть модуль, транслировать модуль - преобразование отладочной информации в NMS-файл, загрузить модуль. Если загрузчик разобрался с отладочной информацией, то в окне отладчика появится программный текст, в противном случае Вам придется работать с обычным дизассемблированным текстом. После загрузки модуля, вы можете настроить запуск модуля в отладчике, воспользовавшись пунктом меню Module\Setting (Рис. 4.4.11). Настройка достаточно очевидна, поэтому мы не будем разъяснять смысл пунктов данного окна.

Рис. 4.4.10. Вид загрузчика SoftIce (LOADER32.EXE).

Рис. 4.4.11. Окно настройки запуска модуля в отладчике Softice.

Рис. 4.4.12. Окно отладчика SoftIce.

Обзор команд отладчика

  1. Вызов отладчика. Вызов отладчика осуществляется клавишами Ctrl+D, повторное нажатие этих клавиш приводит к закрытию отладчика. Закрытие окна отладчика можно осуществить и клавишей F5.
  2. Помощь. Для получения списка всех команд наберите в командном окне команду "h". Для получения информации по конкретной команде наберите "h <команда>". Нижняя часть командного окна - панель помощи. В ней появляются подсказки. Например, если Вы введете букву "w" (на эту букву начинаются оконные команды) на панели появится список команд, начинающихся на "w".
  3. Работа с окнами. При вызове отладчика на экране появляется его окно (см. Рис. 4.4.12.), разделенное на несколько окон, каждое из которых несет на себе определенную информационную нагрузку. Количество и размер этих окон определяется начальной установкой (см. начало), но может меняться по нашему желанию. Для ввода команд существует командное окно. Обычно курсор находится именно в командном окне. Каждое окно имеет свое мнемоническое обозначение, например "c" - окно кода, "d" - окно данных, "r" - окно регистров, "f" - окно сопроцессора, "w" - окно наблюдения за переменными, "s" - окно стека, "l" - окно локальных переменных, "x" - окно регистров Pentium III. В часть окон можно перейти командой Alt+"мнемоническое обозначение окна". Перейти можно в каждое такое окно, выяснить это, как Вы понимаете, достаточно просто. Обратный переход осуществляется той же командой. Для создания соответствующего окна, если оно отсутствует, используются команды, в которых первым идет символ "w", вторым символом является символ, обозначающий окно. Например, если у Вас нет на экране окна данных, то создать его можно командой wd, та же команда удалит окно данных из перечня показываемых окон. Высота окна определяется параметром данной команды, например wc 20. Запомните еще несколько полезных команд. Ctrl+"стрелка вверх-вниз" - скроллинг окна кода, Alt+"стрелка вверх-вниз" - скроллинг окна данных, Alt+Ctrl "стрелка вверх-вниз, вправо-влево" - передвижение самого окна отладчика.
  4. Просмотр кода и данных. Один способ передвижения, а значит и просмотра, Вы уже знаете: скроллинг окна кода осуществляется клавишами Ctrl+<стрелка вниз, стрелка вверх> (Alt для окна данных). Наиболее удобной является команда "U". Общий формат этой команды: U [address [length]] | [name]. Address - адрес непосредственный или определяемый через регистр, length - число выводимых байт, name - осуществлять скроллинг, пока не встретится данное имя. Например, u ebx -20 - вывести инструкции, начиная с адреса за 20 байт до адреса CS:EBX. Пустая команда u выводит коды, начиная с CS:EIP. Если вторым параметром идет l, то вывод осуществляется в командное окно. Аналогично для окна данных работает команда D, формат которой имеет вид: D [address], [length]. Например, d 100, 100 или d eax. Положим, видя команду типа MOV EAX,[EBX-10], мы можем посмотреть область данных, откуда берется значение EAX: d ebx-10.
  5. Просмотр - модификация регистров. Переход к окну регистров, как уже было сказано, может быть осуществлено командой Alt+r. Находясь в окне. Вы можете вместе с тем менять содержимое регистров. К аналогичному результату можно прийти, просто выполнив в командной строке команду "R". Возможна также команда вида r reg=знач. Например, r еах=10. Ключ -d позволяет выводить содержимое регистров в командное окно. Команда r есх переводит курсор прямо к нужному регистру, a r fl - прямо к регистру флагов. Команда вида r fl=o+a-p — устанавливает флаги "o" и "a" и сбрасывает флаг "p".
  6. Трассировка кода. Горячие клавиши: F8 - выполнение инструкции с заходом в процедуру, F10 - выполнение инструкции с обходом процедуры, F7 - выполнить инструкции до текущей команды (если Вы находитесь в окне кода). Нажатие клавиши F7 эквивалентно команде HERE. Клавиша F12 - выполнять код, пока не встретится команда RET (команда P с параметром RET). F11 - вернуться к последней выполненной команде CALL. В командной строке Вы можете использовать команду T, которая имеет следующий формат: Т [=address] [count]. Здесь address - адрес, с которого начинается выполнение, count - количество шагов.
  7. Точки останова. Самое мощное и удобное средство отладки программы SoftIce.
    1. Обычные точки останова. Список точек останова можно просмотреть при помощи команды BL. Каждой точке останова ставится в соответствие номер, который Вы увидите в списке. Удалить точку останова из списка можно командой ВС <номер или список>. Все точки останова можно удалить командой ВС *. Находясь в окне кода, Вы можете поставить точку останова, нажав клавишу F9, строка при этом будет подсвечена. Повторное нажатие клавиши F9 снимает точку останова с текущей строки. Команда BD снимает точку останова, но не удаляет ее из списка, команда BE вновь активизирует точку останова. Поставить точку останова можно также командой bpx addess.
    2. Точки останова на функции API. Например, bpx MessageBoxA поставит точку останова на любой вызов данной функции. Для того чтобы проверить, распознает отладчик функции данной группы, выполните команду exp MessageBox, при этом в командное окно будет выведен соответствующий список.
    3. Точки останова с условием. Общий формат команды bpx имеет вид: BPX [address] [if expression] [do "command1; command2.."]. Таким образом, точка останова сработает только при выполнении условия. При этом будет выполнена последовательность команд отладчика. Например, возможно такое выражение: BPX eip if eax=10 do "db bx".
    4. Точки останова на сообщения. Точку останова на сообщения можно поставить при помощи команды bmsg. При этом надо знать дескриптор окна. Но на это есть специальная команда hwnd, которая дает список окон, их дескрипторов и адресов их процедур. Например, BMSG 0b0f wm_destroywindow означает установить точку останова на сообщение WM_DESTROYWTNDOW, приходящее на окно с дескриптором 0b0fh. Поскольку сообщения представляют собой определенные целые числа, можно через пробел указывать диапазон сообщений. Кроме того, точка останова может быть дополнена условием (if) и набором команда (do).
  8. Другие команды. Команд в SoftIce неисчислимое количество, точнее около 200. Вы можете посмотреть описание их в документации, которая прилагается к пакету, либо выполнив в командной строке команду h(F1). Поражает обилие команд для получения системной информации. Думаю, что во всех этих возможностях Вы разберетесь сами.

Примеры использования программ W32Dasm и SoftIce вы найдете в последующих главах.

55 Автору не известно о возможностях использования отладчика в Windows 2000 либо новых версиях, обладающих такими возможностями.