FE23  LOOCH  DISASM

ДИЗАССЕМБЛЕР
ДЛЯ ИССЛЕДОВАНИЯ ПРОГРАММ

(empty)
Главная Загрузка Инструкция Карта сайта

 

БЫСТРЫЙ СТАРТ

УРОК ТРЕТИЙ


Содержание


1. Постановка учебной задачи

По-прежнему нашим учебным исследуемым файлом будет файл ( fe23.exe ). Мы продолжаем с помощью программы FE23 изучать внутреннее устройство программы FE23. Теперь мы поставим перед собой такую задачу. Мы хотим получить общее представление обо всей программе, сколько в ней всего процедур и где они в файле расположены, узнать адреса всех процедур. Для этого нам нужно всего-навсего сделать "первый проход дизасма" по всем процедурам.

Загляните еще раз на страницу   "Основные понятия",   вспомните, что означает в программе FE23 это понятие - "первый проход дизасма".

После того, как мы пройдем дизасмом все процедуры, мы сможем получить распечатку с ассемблерным текстом (асм. текстом) для любой процедуры, которая нас заинтересует.

Но, быть может, мы замахнулись на слишком сложную задачу - узнать адреса абсолютно всех процедур. Хорошо, пусть задача будет немного попроще. Мы пройдем дизасмом столько процедур, сколько у нас получится. Но все же мы хотим пройти как можно больше процедур.

Примечание
Все распечатки на этой странице были получены с использованием программы FE23, версия 1.0, дата сборки 05.07.2010. Файл программы ( fe23_10.exe ). И этот же файл является исследуемым файлом. Воможно, что в том файле программы FE23, которым Вы располагаете, конкретные адреса будут отличаться.
Далее на этой странице мы будем имя файла записывать в общем виде ( fe23.exe ), убрав из этого имени номер версии. И только в распечатках будет видно имя файла ( fe23_10.exe ).


2. Где начало и где конец

Неплохо бы для начала соориентироваться. Узнать, где в файле ( fe23.exe ) находится самая первая процедура и где самая последняя процедура. Речь идет о собственных процедурах программы. О тех процедурах, которые есть в исходниках. Мы хотим их как-то отделить от тех библиотечных процедур, которые компилятор добавляет в EXE файл.

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

Вы уже знаете ( Урок второй ) что в программе FE23 можно по команде ( Probe --> Probe ) главного меню получить распечатку с адресами некоторых процедур. В этой распечатке есть такие строчки:


Общие габариты всех собственных процедур 
    Самая первая процедура 
        =aaa_empty=          00401000 
    Самая последняя процедура 
        =zyx_empty=          00417200 

Итак, мы теперь знаем, где начало и где конец всех собственных процедур. Адреса в этой распечаке - виртуальные, с добавлением базового адреса ( image_base ).

Еще в этом нашем уроке нам пригодятся вот эти строчки из той же распечатки "Probe":


    Головная процедура 
        =WinMain=            00401010 

    Оконная процедура главного окна 
        =MainWndProc=        004013E

Головная процедура WinMain расположена в самом начале, сразу за "самой первой" процедурой пустышкой.


Нам пора уже запускать программу FE23. Задаем имя исследуемого файла ( fe23.exe ) и делаем подготовку исследуемого файла к работе. Как это делается, Вы уже знаете ( Урок первый ).

Открыт исследуемый файл H:/FE/C/23/Release/fe23_10.exe Это исполняемый файл - Win32 - PE Размер файла = 0x0002B400 (177152) Entry point virt address = 0x00417C00 Entry point file index = 0x00017000 Image base = 0x00400000 Mode = 32 bits Таблица секций исследуемого файла Raw_Addr Raw_Size RVA_Addr RVA_Size Vir_Addr Type <Header> 00000000 00000400 ---- ---- ---- ---- .text 00000400 0001C400 00001000 0001C306 00401000 code .rdata 0001C800 00000400 0001E000 000003B3 0041E000 data .data 0001CC00 0000C400 0001F000 0000E388 0041F000 data .idata 00029000 00000E00 0002E000 00000C80 0042E000 data .rsrc 00029E00 00001600 0002F000 00001498 0042F000 data <EOF> 0002B400

Теперь взгляните на таблицу секций. Обратите внимание, что адрес самой первой процедуры - это самое начало секции кодов ( .text ).

И еще интересный момент. Адрес точки входа в программу ( 00417C00 ) находится за пределами собственных процедур, этот адрес больше адреса самой последней процедуры. То есть, адрес входа в некоторую библиотечную процедуру, добавленную компилятором.

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


3. Выбор параметров дизасма

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

Перед стартом первого прохода дизасма нам нужно не забыть про установку параметров.

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

Если хотите, Вы сами можете поэкспериментировать, задавая разные значения параметров.

Параметр ( looch_size ) - предельный размер луча

Вот основные результаты пробных опытов с этим параметром для файла ( fe23.exe ). В этих пробах задавались круглые числа - степени двойки.

Если поставить ( looch_size = 256 ), то дизасм остановится на 252 луче (при дизасме от точки входа в программу).

При ( looch_size = 512 ) дизасм от точки входа проходит до конца.

Параметр ( looch_nums ) - предельное количество лучей

Поставим ( looch_nums = 150 ). Чуть позже мы поясним, почему именно так было выбрано. Это значение мы специально подбирали для нашего урока. Пройдя дизасмом первые 150 лучей, мы сделаем остановку, чтобы осмотреться. И затем продолжим дизасм. Всего нам потребуется пройти гораздо больше лучей, чем 150.

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

Параметр ( do_calls ) - создавать заявки для CALL

Для этого флага поставим значение ( do_calls = ДА ). Чтобы все найденные процедуры тоже были пройдены дизасмом.

Параметр ( do_asmtext ) - печатать ассемблерный текст

А для этого флага однозначно ставим ( do_asmtext = НЕТ ). Чтобы первый проход дизасма выполнялся побыстрее.


В главном меню есть команда ( Start --> Disasm Settings ), которая вызывает на экран диалог для задания параметров дизасма.

Итак, мы установили в этом диалоге все параметры дизасма.

После выхода из диалога программа сообщит, какие параметры были изменены. Если мы хотим, чтобы в протоколе были зафиксированы значения всех параметров, то следует дать команду ( Start --> Show Disasm Settings ) из главного меню.


Параметры дизассемблирования 
    Предельный размер луча       = 512
    Предельное количество лучей  = 150
    Создавать заявки для CALL    = ДА
    Печатать ассемблерный текст  = НЕТ

Теперь можно стартовать первый проход дизасма.


4. Стартовать дизасм от точки входа

Выбираем в главном меню команду ( Start --> Entry Point ). Прошли 150 лучей.

Вот конец распечатки в протоколе. (Но список оставшихся заявок мы здесь существенно сократили).


    Лучи:  150 пройдено, 150 предел, 193 всего в списке 

    СТОП: Достигнут предел по количеству лучей 
    Пройдено лучей   150

    Остались невыполненные заявки: 

             vir_addr   file_idx   proc  type 
         1   0041BCF6   0001B0F6   015   REQU_NEXT 
         2   0041BCFE   0001B0FE   015   REQU_JCC 
         3   0041BD2B   0001B12B   015   REQU_JCC 
         4   00417710   00016B10   016   REQU_CALL 
         5   0041B670   0001AA70   017   REQU_CALL 
      ..............................................
      ..............................................
        36   0041CA20   0001BE20   048   REQU_CALL 
        37   0041C990   0001BD90   049   REQU_CALL 

    КОНЕЦ ДИЗАССЕМБЛИРОВАНИЯ 

    РАБОТА ЗАКОНЧЕНА 

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


Мы остановились, чтобы немного осмотреться.

Запросим сразу "общие сведения" - команда меню ( Show --> General Data ).


ОБЩИЕ СВЕДЕНИЯ 

    Имя проекта           (---)
    Исследуемый Файл      H:/FE/C/23/Release/fe23_10.exe
    Найдено процедур      49
    Пройдено процедур     15
    Пройдено лучей        193
    Найдено CALL's        113
    Невыполненных заявок  37

Мы прошли 150 лучей. Но в списке лучей их оказалось больше, там уже 193 луча. Так получается из-за того, что некоторые созданные лучи были затем разделены на две части, на два луча. Потому что встретилась команда передачи управления, ведущая внутрь луча.


Еще стоит посмотреть прямо сейчас на список процедур. Даем из главного меню команду ( Show --> Procedure List ). Полученную распечатку воспроизведем здесь полностью. Чтобы зрительно оценить ситуацию.


    Список процедур 

S/N   - порядковый номер, присвоенный процедуре 
Addr  - адрес входа в процедуру 
pass  - первый луч данной процедуры уже пройден дизасмом 
Cnt   - количество вызовов для данной процедуры из других процедур 
Calls - адреса процедур, вызываемых из данной процедуры 

S/N   Addr           Cnt Calls 
001   00417C00 pass   0  19A80 17DA0 1A990 1B940 1B510 1AE70 1B260 
1B170 1AE40 1B110 01010
002   00419A80 pass   1  19AC0
003   00417DA0 pass   5  1BB20 1BB60
004   0041A990 pass   1  17710 17DA0
005   0041B940 pass   1  1B670
006   0041B510 pass   1  17710 17A10
007   0041AE70 pass   2  1AEB0
008   0041B260 pass   1  1B300 17710 17DA0
009   0041B170 pass   1  17710 17DA0 17A10
010   0041AE40 pass   1  1AF60
011   0041B110 pass   1  1B130
012   00401010 pass   1  0EDE0 08950 08BB0 08C10 14F90 03960 091D0 
0D6C0 0F970 11C90 12C00 13A40 15230 15A10 012C0 15250 11CD0 15BD0 
08930 01D00 152D0 02650 01E00 01EA0 10740
013   00419AC0 pass   1 
014   0041BB20 pass   1  1BB60
015   0041BB60 pass   3  1CA20 1C990
016   00417710        7 
017   0041B670        1 
018   00417A10        2 
019   0041AEB0        1 
020   0041B300        2 
021   0041AF60        2 
022   0041B130        1 
023   0040EDE0        1 
024   00408950        1 
025   00408BB0        1 
026   00408C10        1 
027   00414F90        1 
028   00403960        1 
029   004091D0        1 
030   0040D6C0        1 
031   0040F970        1 
032   00411C90        1 
033   00412C00        1 
034   00413A40        1 
035   00415230        1 
036   00415A10        1 
037   004012C0        1 
038   00415250        1 
039   00411CD0        1 
040   00415BD0        1 
041   00408930        2 
042   00401D00        2 
043   004152D0        1 
044   00402650        1 
045   00401E00        1 
046   00401EA0        1 
047   00410740        1 
048   0041CA20        1 
049   0041C990        1 

Поясним, что словом "pass" помечены те процедуры, которые пройдены дизасмом. Точнее, у которых пройден дизасмом хотя бы один луч. Процедуры, которые расположены в конце списка, еше не пройдены дизасмом.

Сразу бросается в глаза, как мало еще мы прошли процедур по сравнению с тем, сколько процедур мы уже обнаружили.

Обратим внимание, что на этой распечатке для каждой процедуры показано, какие процедуры вызываются из данной процедуры. Приведен список адресов вызываемых процедур. (Для компактности в этих адресах убраны старшие цифры).

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

Но больше всего разных процедур вызывается из процедуры с порядковым номером 012. Адрес этой процедуры 00401010 нам уже знаком, зто головная процедура WinMain нашей исследуемой программы. Очень часто для разных программ именно так и бывает, что из головной процедуры идет много вызовов для других процедур. И тогда сразу видно, которая из процедур является головной.

Теперь мы объсним, как было обещано, почему мы для первого запуска дизасма поставили предел именно в 150 лучей. Мы хотели, чтобы после этого первого запуска была уже пройдена процедура 012, то есть, WinMain.


5. Продолжение дизасма для невыполненных заявок

Будем продолжать выполнять первый проход дизасма.

Но перед этим увеличим значенияе параметра ( looch_nums ), поставим предел в 500 лучей.

Теперь параметры дизасма выглядят так:


Параметры дизассемблирования 
    Предельный размер луча       = 512
    Предельное количество лучей  = 500
    Создавать заявки для CALL    = ДА
    Печатать ассемблерный текст  = НЕТ

Мы продолжим дизасм с того места, на котором остановились. Снова будем брать очередные заявки из очереди, из списка заявок, и выполнять эти заявки.

Для продолжения дизасма по оставшимся невыполненным заявкам есть специаьная команда в главном меню ( Start --> Continue ).

Благополучно прошли 500 лучей. Но в очереди остались еще заявки.

Еще раз даем ту же команду ( Start --> Continue ), чтобы пройти следующие 500 лучей.


    Пройдено лучей   374
    Все заявки выполнены 

    КОНЕЦ ДИЗАССЕМБЛИРОВАНИЯ 

    РАБОТА ЗАКОНЧЕНА 

Итак, мы начали от входной точки и прошли все лучи и процедуры, какие удалось пройти в автоматическом режиме.

Всего мы прошли ( 150 + 500 + 374 ), итого это 1024 луча. Если потребуется повторить, мы сразу поставим предел, ну, скажем, 1100 лучей. (Хотя можно, конечно, вообще отключить эту защиту, поставить 999999 ...).


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


    Файл  cmd_01.cmd

    Командный файл
    Программа исследует самое себя

------------------------------------------------

.z.
.z.	exam_file   H:/FE/C/23/RELEASE/fe23_10.exe
.z.
.z.	looch_size	512
.z.	looch_nums	1100
.z.	do_calls
.z.	no_asmtext
.z.
.z.	entry_point
.z.

------------------------------------------------

Те строчки, которые начинаются не с символов ( .z. ), это комментарии.

Пустые строчки, которые начинаются с ( .z. ), вставлены просто для красоты. Это тоже комментарии.

В команде ( exam_file ) Вам нужно поставить тот путь на Вашем диске, который ведет к файлу ( fe23_10.exe )


6. Поговорим о накопленных данных

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

Посмотрим общие сведения о накопленных данных - даем команду ( Show --> General Data ).


ОБЩИЕ СВЕДЕНИЯ 

    Имя проекта           (---)
    Исследуемый Файл      H:/FE/C/23/RELEASE/fe23_10.exe
    Найдено процедур      110
    Пройдено процедур     110
    Пройдено лучей        1309
    Найдено CALL's        411
    Невыполненных заявок  0

У нас сейчас есть 110 процедур и 1309 лучей.


Можно запросить список всех процедур - это команда ( Show --> Procedure List )

Мы уже смотрели на эту распечатку после прохода дизасмом первой порции из 150 лучей. Теперь эта распечатка стала существенно длиннее. И она стала более интересной. Приведем ее здесь полностью.


    Список процедур 

S/N   - порядковый номер, присвоенный процедуре 
Addr  - адрес входа в процедуру 
pass  - первый луч данной процедуры уже пройден дизасмом 
Cnt   - количество вызовов для данной процедуры из других процедур
Calls - адреса процедур, вызываемых из данной процедуры 

S/N   Addr           Cnt Calls 
001   00417C00 pass   0  19A80 17DA0 1A990 1B940 1B510 1AE70 1B260
1B170 1AE40 1B110 01010
002   00419A80 pass   1  19AC0
003   00417DA0 pass   5  1BB20 1BB60
004   0041A990 pass   1  17710 17DA0
005   0041B940 pass   1  1B670
006   0041B510 pass   1  17710 17A10
007   0041AE70 pass   2  1AEB0
008   0041B260 pass   1  1B300 17710 17DA0
009   0041B170 pass   1  17710 17DA0 17A10
010   0041AE40 pass   1  1AF60
011   0041B110 pass   1  1B130
012   00401010 pass   1  0EDE0 08950 08BB0 08C10 14F90 03960 091D0
0D6C0 0F970 11C90 12C00 13A40 15230 15A10 012C0 15250 11CD0 15BD0 
08930 01D00 152D0 02650 01E00 01EA0 10740
013   00419AC0 pass   2 
014   0041BB20 pass   1  1BB60
015   0041BB60 pass   3  1CA20 1C990
016   00417710 pass  14  17730
017   0041B670 pass   1  1B860 1B910 1B8B0
018   00417A10 pass   5  19D60 19DC0
019   0041AEB0 pass   1  1AF60
020   0041B300 pass   2 
021   0041AF60 pass   4 
022   0041B130 pass   1 
023   0040EDE0 pass   1  0F790
024   00408950 pass   1 
025   00408BB0 pass   1  177F0 088A0
026   00408C10 pass   1  178E0 089D0 17890
027   00414F90 pass   1 
028   00403960 pass   1  17710
029   004091D0 pass   1 
030   0040D6C0 pass   1  0D6D0 0DAD0
031   0040F970 pass   1 
032   00411C90 pass   1 
033   00412C00 pass   1 
034   00413A40 pass   1 
035   00415230 pass   1 
036   00415A10 pass   1 
037   004012C0 pass   1  08930
038   00415250 pass   1  08930
039   00411CD0 pass   1  08930
040   00415BD0 pass   1  08930
041   00408930 pass   8 
042   00401D00 pass   2 
043   004152D0 pass   1  15810 157C0 158E0
044   00402650 pass   1  08AD0 08B20
045   00401E00 pass   1  08B20 08AD0
046   00401EA0 pass   1  08B20 08AD0
047   00410740 pass   1  14FE0 08B20 08AD0
048   0041CA20 pass   1 
049   0041C990 pass   1 
050   00417730 pass   1  17780 19A60
051   0041B860 pass   1 
052   0041B910 pass   2 
053   0041B8B0 pass   2 
054   00419D60 pass   2 
055   00419DC0 pass   3  19C90
056   0040F790 pass   2  17490
057   004177F0 pass   1  177C0
058   004088A0 pass   1  174E0 08930
059   004178E0 pass  15  1AE10 1ADB0 1AB90 1A8D0
060   004089D0 pass   1  08960
061   00417890 pass   4  18CD0 1A780 18D70
062   0040D6D0 pass   1 
063   0040DAD0 pass   1 
064   00415810 pass   1 
065   004157C0 pass   1  15170
066   004158E0 pass   1 
067   00408AD0 pass  31  15900 08EE0 08F00
068   00408B20 pass  22  08AD0
069   00414FE0 pass   1  17710
070   00417780 pass   1  19E20
071   00419A60 pass   3 
072   00419C90 pass   1  19C30
073   00417490 pass   1  17DD0
074   004177C0 pass   1  1A480 1A2B0
075   004174E0 pass   1  18DD0 178E0
076   0041AE10 pass   2 
077   0041ADB0 pass   3  17710
078   0041AB90 pass   4  1A8D0 1C660
079   0041A8D0 pass   3  1C8E0 1C660
080   00408960 pass   1 
081   00418CD0 pass   1  1AE10 17710
082   0041A780 pass   1  1A680 1AB90 178E0
083   00418D70 pass   1  1A680
084   00415170 pass   1  17710 17A60
085   00415900 pass   1 
086   00408EE0 pass   1  17890
087   00408F00 pass   1  17890
088   00419E20 pass   3  1A060 19AC0
089   00419C30 pass   1 
090   00417DD0 pass   1  19980 18BA0 18B80 176E0 18B50
091   0041A480 pass   1  17710
092   0041A2B0 pass   1  1C2A0
093   00418DD0 pass   1 
094   0041C660 pass   3 
095   0041C8E0 pass   1 
096   0041A680 pass   3  1AB90
097   00417A60 pass   1  17710 17A10 19D60 1A1E0 19E20 19DC0 19A60
098   0041A060 pass   2 
099   00419980 pass   3  1C170
100   00418BA0 pass   2  18B50 176E0
101   00418B80 pass   3  1BF50
102   004176E0 pass   4  19980
103   00418B50 pass   5  1BE60
104   0041C2A0 pass   1 
105   0041A1E0 pass   1 
106   0041C170 pass   1  1BFE0 17A10
107   0041BF50 pass   1  1ADB0
108   0041BE60 pass   1  1ADB0 1CB30
109   0041BFE0 pass   1  19E20 19A60
110   0041CB30 pass   1  1C660 1A8D0

Заметим, что все процедуры, которые есть в этом списке, отмечены словом "pass", то есть, все они уже пройдены дизасмом.


Мы можем сделать распечатку асм. текста для каждой процедуры. А также распечатку схемы лучей и переходом между лучами, иначе говоря, получить блок-схему для любой процедуры.

О том, как делать такие распечатки для процедур, мы расскажем дальше, в следующем разделе.


Теперь посмотрим еще на один список - список всех вызовов CALL. Такой список тоже собирается во время выполнения первого прохода дизасма.

Этот список у нас получился довольно длинным. В табличке общих сведений сказано, что в этом списке сейчас накоплено 411 элементов.

Получить распечатку с этим списком можно по команде ( Show --> CALL's List ) из главного меню.

Из этого длинного списка мы здесь приводим только отдельные фрагменты.


    Список всех вызовов CALL 

Proc - порядковый номер процедуры, откуда идет вызов 
Addr - адрес команды CALL 
Type - тип вызова 
S/N  - порядковый номер по списку собственных или импортируемых
Name - имя (если известно) или адрес 

      Proc   Addr       Type     S/N   Name 
   1   001   00417c26   import   062   GetVersion
   2   001   00417c57   own      002   p_002  00419A80
   3   001   00417c62   own      003   p_003  00417DA0
   4   001   00417c71   own      004   p_004  0041A990
   5   001   00417c76   own      005   p_005  0041B940
   6   001   00417c7b   import   063   GetCommandLineA
   7   001   00417c86   own      006   p_006  0041B510
   8   001   00417c9f   own      007   p_007  0041AE70
   9   001   00417ca7   own      008   p_008  0041B260
  10   001   00417cac   own      009   p_009  0041B170
  11   001   00417cb1   own      010   p_010  0041AE40
  12   001   00417cdc   own      011   p_011  0041B110
  13   001   00417d12   import   064   GetStartupInfoA
  14   001   00417d33   import   065   GetModuleHandleA
  15   001   00417d3a   own      012   p_012  00401010
  16   001   00417d43   own      007   p_007  0041AE70
  17   002   00419a89   import   056   HeapCreate
  18   002   00419a99   own      013   p_013  00419AC0
  19   002   00419aa8   import   061   HeapDestroy
................................................
................................................
 183   037   004012fa   unknown  ---   unknown
 184   037   0040130c   unknown  ---   unknown
 185   037   00401319   unknown  ---   unknown
 186   037   00401334   import   076   RegisterClassA
 187   037   00401344   own      041   p_041  00408930
 188   037   00401381   unknown  ---   unknown
 189   037   0040138d   unknown  ---   unknown
 190   037   00401394   unknown  ---   unknown
 191   037   004013ab   import   076   RegisterClassA
 192   037   004013bb   own      041   p_041  00408930
 193   038   0041527d   import   073   LoadIconA
 194   038   0041528d   import   077   LoadCursorA
 195   038   004152ac   import   076   RegisterClassA
 196   038   004152bc   own      041   p_041  00408930
 197   039   00411d01   import   073   LoadIconA
 198   039   00411d11   import   077   LoadCursorA
 199   039   00411d30   import   076   RegisterClassA
 200   039   00411d40   own      041   p_041  00408930
 201   040   00415c01   import   073   LoadIconA
 202   040   00415c11   import   077   LoadCursorA
 203   040   00415c20   import   015   CreateSolidBrush
 204   040   00415c3b   import   076   RegisterClassA
 205   040   00415c4b   own      041   p_041  00408930
................................................
................................................
 400   107   0041bf76   own      077   p_077  0041ADB0
 401   108   0041be95   own      077   p_077  0041ADB0
 402   108   0041beb0   own      110   p_110  0041CB30
 403   109   0041c01e   own      088   p_088  00419E20
 404   109   0041c04e   unknown  ---   unknown
 405   109   0041c060   own      071   p_071  00419A60
 406   110   0041cbc7   import   026   ReadFile
 407   110   0041cbd1   import   028   GetLastError
 408   110   0041cc06   own      094   p_094  0041C660
 409   110   0041cca7   import   026   ReadFile
 410   110   0041ccb1   import   028   GetLastError
 411   110   0041cd05   own      079   p_079  0041A8D0

Здесь в колонке "тип вызова" (Type) могут быть указаны следующие типы:

  • "own" - вызываемая процедура находится в самом исследуемом файле. Это либо собственная процедура исследуемой программы, либо библиотечная стандартная функция, включенная в исследуемый EXE файла.

  • "import" - вызываемая процедура - это функция, импортируемая из внешней библиотеки DLL.

  • "jump" - команда CALL передает управление на команду JUMP, расположенную в исследуемом файле, затем эта команда JUMP передает управление на функцию, импортируемую из внешней библиотеки DLL.

  • "unknown" - адрес вызываемой функции неизвестен, так как не удалось автоматически определить этот адрес.


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

    Все сведения на обзорном экране расположены в порядке адресов. Поэтому нужную процедуру следует искать по ее адресу, этот адрес есть в списке процедур.


    7. Кластеры из процедур и распечатки

    Этот раздел можно было бы назвать иначе:
    "Распечатки для отдельных процедур"

    И такое название было бы даже более понятным. Но тут было важно, чтобы в названии этого раздела обязательно присутствовало это слово - "кластер".

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

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


    Распечатки мы сделаем для четырех процедур. Их порядковые номера 037, 038, 039, 040. Далее, по ходу нашего урока, станет понятно, почему мы выбрали именно эти процедуры.

    Для кластера нужно придумать имя. Не будем долго думать, просто возьмем первые буквы слова "cluster" и номер первой процедуры. Имя для кластера будет такое "CLU_037".

    Команда для создания кластеров - это ( Cluster --> New ). По этой команде сначала появится первый диалог - для задания имени кластера. Задаем имя. Затем второй диалог - со списком процедур. Здесь выбираем строчки нужных нам процедур 037, 038, 039, 040.

    Примечание
    Правила работы в этом окошке - стандартные для Windows. Чтобы выбрать не одну строку, а сразу несколько, нужно удерживать нажатой клавишу "Ctrl" и кликать мышкой на нужные строки. Если нужные строки расположены подряд, то можно выбрать мышкой первую строку, затем, удерживая "Shift", выбрать последнюю строку.

    В протоколе при этом появится вот такое сообщение:

    
    Выбор кластера для работы 
        Кластер:  CLU_037 
            Это новый кластер 
        Процедуры кластера: 
            037   004012C0   passed 
            038   00415250   passed 
            039   00411CD0   passed 
            040   00415BD0   passed 
    

    Здесь слово "passed" означает, что для данной процедуры уже был сделан первый проход дизасма (хотя бы для одного первого луча). Распечатки можно получать только для тех процедур, которые пройдены дизасмом.

    Итак, кластер мы приготовили.


    Дальнейшее все очень просто.

    В главном меню выбираем команду ( Cluster --> Asm_Text ). Появится диалог для выбора кластера. Но там уже будет стоять имя только что созданного кластера. Подтверждаем этот выбор и получаем распечатку (в отдельном окне) с ассемблерным текстом для четырех процедур.

    Вот одна из этих процедур (мы скопировали сюда ту, что покороче, это процедура с номером 038).

    Процедура 038 -------- Здесь вход в процедуру -------- 00415250 83EC 28 SUB ESP,00000028 00415253 A1 64B44200 MOV EAX,DS:[0042B464] 00415258 56 PUSH ESI 00415259 33F6 XOR ESI,ESI 0041525B 68 007F0000 PUSH 00007F00 00415260 56 PUSH ESI 00415261 C74424 0C 20000000 MOV SS:[ESP+C],00000020 00415269 C74424 10 D0534100 MOV SS:[ESP+10],004153D0 00415271 897424 14 MOV SS:[ESP+14],ESI 00415275 897424 18 MOV SS:[ESP+18],ESI 00415279 894424 1C MOV SS:[ESP+1C],EAX 0041527D FF15 98E34200 CALL DS:[0042E398] 00415283 68 007F0000 PUSH 00007F00 00415288 56 PUSH ESI 00415289 894424 20 MOV SS:[ESP+20],EAX 0041528D FF15 A8E34200 CALL DS:[0042E3A8] 00415293 8D4C24 04 LEA ECX,SS:[ESP+4] 00415297 894424 1C MOV SS:[ESP+1C],EAX 0041529B 51 PUSH ECX 0041529C 897424 24 MOV SS:[ESP+24],ESI 004152A0 897424 28 MOV SS:[ESP+28],ESI 004152A4 C74424 2C AC844200 MOV SS:[ESP+2C],004284AC 004152AC FF15 A4E34200 CALL DS:[0042E3A4] 004152B2 66:3BC6 CMP AX,SI 004152B5 75 12 JNE SHORT 004152C9 -------- 004152B7 68 84844200 PUSH 00428484 004152BC E8 6F36FFFF CALL NEAR 00408930 004152C1 83C4 04 ADD ESP,4 004152C4 BE 01000000 MOV ESI,00000001 -------- 004152C9 8BC6 MOV EAX,ESI 004152CB 5E POP ESI 004152CC 83C4 28 ADD ESP,00000028 004152CF C3 RET --------

    Затем точно также, но по другой команде ( Cluster --> Diagram ) мы получаем распечатку со схемой лучей и переходов. (Мы опять приводим здесь для примера только одну процедуру 038).

    038-006 00415250 <<<<<<< ENTER [ CALL ] LoadIconA [ CALL ] LoadCursorA [ CALL ] RegisterClassA [ ] [ JCC ] >>>O 004152C9 . . . . v 038-007 004152B7 v [ CALL ] v p_041 00408930 [ ] v [ ANY ] v 038-008 004152C9 <<<O [ ] [ RET ] >>>>>>> RETURN -------- pass by 004152D0 [ ]

    И получим еще распечатку по команде ( Cluster --> Looches ). Это такая же схема лучей, но на ней не показаны переходы (передачи управления). В распечатке все те же четыре процедуры. (Но мы опять воспроизводим только для процедуры 038).

    038-006 00415250 <<< ENTER [ CALL ] LoadIconA [ CALL ] LoadCursorA [ CALL ] RegisterClassA [ ] [ JCC ] 004152C9 . . . . 038-007 004152B7 [ CALL ] p_041 00408930 [ ] [ ANY ] 038-008 004152C9 [ ] [ RET ] >>> RETURN -------- pass by 004152D0 [ ]


    8. Ищем оконную процедуру главного окна

    Отыскать адрес оконной процедуры можно разными способами. Например, с помощью программы MS Spy++, которая входит в состав пакета MS Developer Studio ( Visual C++ ).

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

    Причем эта наша учебная задачка имеет готовый ответ, как это бывает в школьных учебниках. Ведь в самом начале нашего урока мы уже получили распечатку по команде ( Probe --> Probe ) главного меню, где есть, среди прочего, вот такие строчки:

    
        Головная процедура 
            =WinMain=            00401010 
    
        Оконная процедура главного окна 
            =MainWndProc=        004013E0 
    

    Итак, приступаем к решению этой задачи.

    Путь к решению будет такой. Мы знаем, что для создания окна должен быть заранее определен класс этого окна. Чтобы зарегистрировать класс окна применяется API функция RegisterClass. Вот мы и поищем вызовы этой функции. Искать будем в списке вызовов CALL, распечатку этого списка мы уже сделали. (В приведенной выше неполной распечтаке этого списка нужный нам фрагмент есть).

    Увы, по части сервиса в программе FE23 пока не густо. Так что искать придется глазками. Хотя у нас в компьютере есть не только FE23. Если сбросить распечатку в файл, то можно посмотреть на этот файл каким-нибудь редактором, в котором есть поиск.

    Нам повезло. В списке вызовов CALL есть вызовы для функции RegisterClass. Выписываем эти строчки:

    
          Proc   Addr       Type     S/N   Name 
    186   037   00401334   import   076   RegisterClassA
    191   037   004013ab   import   076   RegisterClassA
    195   038   004152ac   import   076   RegisterClassA
    199   039   00411d30   import   076   RegisterClassA
    204   040   00415c3b   import   076   RegisterClassA
    

    Напомним, что в этой таблице колонка Proc - это номер процедуры, а колонка Addr - это виртуальный адрес внутри процедуры, то место, где стоит команда CALL.

    Как раз для этих четырех процедур мы уже сделали распечатку асм. текста. Правда, в этой распечатке не подписаны имена импортируемых функций. (Это одна из многочисленных недоделок программы FE23). Но эти имена функций есть на распечатках со схемами лучей. Так что можно соориентироваться по этим схемам.

    Асм. текст мы можем смотреть не только на распечатках, но еще и на обзорном экране, это кому как больше нравится. По виртуальному адресу мы можем быстро найти нужное место на обзорном экране.

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

    Все, этих сведений вполне достаточно для решения задачи. Смотрим на асм. текст. и выписываем адреса пяти оконных процедур.

    • 037 -- 4013E0
    • 037 -- 415590
    • 038 -- 4153D0
    • 039 -- 411F00
    • 040 -- 415C60

    Наверное будет разумно предположить, что оконная процедура главного окна регистрировалась первой. Тогда ее адрес равен 4013E0. Сверяемся с ответом - смотрим на распечатку "probe". Мы нашли правильный ответ.


    9. Что еще можно сделать, какие будут продолжения

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

  • Мы начали первый проход дизасма от точки входа и прошли все процедуры, какие мы смогли найти в автоматическом режиме. После этого нужно непременно взглянуть на обзорный экран. Нужно оценить, много ли осталось "неизвестных областей" и велики ли эти области.

  • Мы нашли адрес оконной процедуры главного окна, а также адреса еще несколькоих оконных процедур. Для этих процедур тоже можно сделать первый проход дизасма. И тогда оставшиеся неизвестные области еще заметно сократятся.

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

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

     




    Все страницы инструкции

    Основные понятия
    Главное меню программы
    Обзорный экран
    Командный файл
    Работа с проектами
     
    Быстрый старт. Урок первый
    Быстрый старт. Урок второй
    Быстрый старт. Урок третий
     
    Файлы, используемые в программе
    Протокол работы и распечатки
    Настройки дизасма и арифметика адресов



  • Главная Загрузка Инструкция Карта сайта


      Rambler's Top100
    Copyright (C) FE23 Looch Disasm, 2010
    File          - disa33.htm
    File created  - 16 Apr 2010
    Last modified - 27 Jul 2010
    Hosted by uCoz