шестой. Дизассемблер & отладчик в связке
"Кот с улыбкой - и то редкость, но уж улыбка без кота - это я прямо не знаю что такое"
Льюис Кэрролл. Алиса в стране чудес
Существует два способа исследования программ, распространяющихся без исходных текстов: дизассемблирование (статический анализ) и отладка (динамический анализ). Вообще-то, любой отладчик обязательно включает в себя дизассемблер, – иначе отлаживать программу пришлось непосредственно в машинных кодах!
Однако тот дизассемблер, что включен в отладчик, обычно слишком примитивен и не может похвастаться богатыми функциональными возможностями. Во всяком случае, дизассемблер, встроенный в популярнейший отладчик Soft-Ice, недалеко ушел от DUMPBIN, с недостатками которого мы уже имели честь столкнуться. Насколько же понятнее становится код, если его загрузить в IDA!
Чем же тогда ценен отладчик? Дело в том, что дизассемблер в силу своей статичности имеет ряд ограничений. Во-первых, исследователю приходится выполнять программу на "эмуляторе" процессора, "зашитом" в их собственной голове, следовательно, необходимо знать и назначение всех команд процессора, и все структуры операционной системы (включая недокументированные), и… Во-вторых, начать анализ с произвольного места программы не так-то просто – требуется знать содержимое регистров и ячеек памяти на данный момент, а как их узнать? С регистрами и локальными переменными еще бы куда ни шло – прокрутим экран дизассемблера вверх и посмотрим какие значения им присваиваются, но этот фокус не пройдет с глобальными переменными, модифицировать которые может кто угодно и когда угодно. Вот бы установить точку останова… но какая же в дизассемблере может быть точка останова? В третьих, дизассемблирование вынуждает на полную реконструкцию алгоритма каждой функции, в то время как отладка позволяет рассматривать ее как "черный ящик" со входом и выходом. Допустим, имеется у нас функция, которая расшифровывает основной модуль программы. В дизассемблере нам придется сначала разобраться в алгоритме шифрования (что может оказаться совсем не просто), затем "переложить" эту функцию на IDA-Си, отладить ее, запустить расшифровщик… В отладчике же можно поручить выполнение этой функции процессору, не вникая в то, как она работает, и дождавшись ее завершения, продолжить анализ расшифрованного модуля программы.
Можно перечислять бесконечно, но и без того ясно, что отладчик отнюдь не конкурент дизассемблеру, а партнер.
Опытные хакеры всегда используют эти два инструмента в паре. Алгоритм реконструируется в дизассемблере, а все непонятные моменты оперативно уточняются, прогоном под отладчиком. При этом возникает естественное желание видеть в отладчике все те символические имена, которые были внесены в дизассемблерный листинг.
И IDA Pro действительно позволяет это сделать! Выберем в меню "Fail" подменю "Produce output file", а в нем пункт "Produce MAP file" (или нажмем "горячую" клавишу <Shift-F10>). На экране появится окно с запросом имени файла (введем, например, "simple.map"), а затем возникнет модальный диалог, уточняющий какие именно имена стоит включать в map-файл. Нажмем <Enter>, оставив все галочки в состоянии по умолчанию (подробно о назначении каждой из них можно прочитать в моей книге "Образ мышления – дизассемблер IDA"). Парой секунд спустя на диске образуется "simple.map" файл, содержащий всю необходимую отладочную информацию, представленную в map-формате Borland. Отладчик Soft-ice не поддерживает такой формат, поэтому, перед его использованием файл необходимо конвертировать в sym-формат специально на то предназначенной утилитой idasym, которую можно бесплатно скачать с сайта www.idapro.com или получить у дистрибьютора, продавшего вам IDA.
Набрав в командной строке "idasym simple.map" и, с удовлетворением убедившись, что файл "simple.sym" действительно создан, запустим загрузим исследуемое приложение "simple.exe" в отладчик любым возможным способом. Дождавшись появления Soft-Ice на экране, отладим ему команду "SYM" для отображения содержимого таблицы символов. Если все было сделано правильно, ответ Soft-Ice должен выглядеть приблизительно так (ниже приведен сокращенный вариант):
:sym
CODE(001B)
001B:00401000 start
001B:00401074 __GetExceptDLLinfo
001B:0040107C _Main
001B:00401104 _memchr
001B:00401124 _memcpy
001B:00401148 _memmove
001B:00401194 _memset
001B:004011C4 _strcmp
001B:004011F0 _strlen
001B:0040120C _memcmp
001B:00401250 _strrchr
001B:00403C08 _printf
DATA(0023)
0023:00407000 aBorlandCCopyri
0023:004070D9 aEnterPassword
0023:004070E9 aMygoodpassword
0023:004070F9 aWrongPassword
0023:00407109 aPasswordOk
0023:00407210 aNotype
0023:00407219 aBccxh1
Wow! Это функциклирует! Теперь символьные имена не только отображаются на экране, упрощая понимание кода, – на любое из них можно быстро и с комфортом установить точку останова, скажем "bpm aMygoodpassword" и отладчик поймет, что от него хотят! Нет больше нужны держать в серо-мозговой памяти эти трудно запоминаемые шестнадцатеричные адреса!