Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #78, ИЮНЬ 2005 г.

Дизассемблер своими руками

GPcH (www.dotfix.net)

Хакер, номер #078, стр. 078-114-3


// это инструкция call?

Call : boolean;

// это инструкция jmp?

Jmp : boolean;

// адрес относительный или абсолютный?

RelTarget : boolean;

// сам адрес

Target : pointer;

// указатель на данные в коде

PTarget : pointer;

// указатель на указатель на данные

PPTarget : TPPointer;

// размер данных в байтах (1/2/4)

TargetSize : integer;

// может ли размер опкода быть расширенным?

Enlargeable : boolean;

// адрес начала инструкции

This : pointer;

// адрес следующей инструкции

Next : pointer;

end;

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

function ParseFunction (func: pointer; var disAsm: string) : TFunctionInfo; overload;

Тут все аналогично предыдущей функции, только в данном случае код будет дизассемблироваться не по одной машинной команде, а целиком. При этом компонент попытается сам определить ссылки на API и прочие данные, что, несомненно, огромный плюс. Структура, возвращаемая данной функцией, на порядок больше предыдущей. В ней куча разных членов: размер дизассемблированного кода, данные об ошибках (в том числе в виде строки), о переходах (jmp и call) и т.п.

Есть и еще одна функция — третья, о которой упоминаний совсем мало:

function ParseFunctionEx (func: pointer; var disAsm: string, exceptAddr: Pointer; maxLines: Integer; autoDelimiters: Boolean);

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

exceptAddr — это адрес конца дизассемблируемой функции (указывать необязательно), maxLines — число дизассемблируемых строк (если 0, то все), autoDelimiters — точно не могу сказать, но ориентировочно это флаг, завершать ли функцию первым ret'ом или нет.

[кодим]

Теперь, когда мы разобрались, как управлять компонентом, можно начинать писать дизассемблер. Открывай Delphi, создавай новый проект, добавляй в раздел uses наш madDisAsm и помещай на форму пару Edit'ов, Memo и два CommandButton'а. В результате этих несложных манипуляций у тебя должно получиться нечто похожее на интерфейс проги (см. рисунок).

В первое текстовое поле мы будем вводить имя открываемого для дизассемблирования файла, а во второе — адрес кода. Так как дизассемблер понимает только pointer'ы (указатели) на код, нам нужна функция, которая будет открывать EXE-файл, считывать по указанному смещению код в некоторый буфер и возвращать на него pointer. Ну раз нужна, напишем:

function TfrmMain.GetCode(strFileName: string; strOffset: string): pointer;

var

hFile: integer;

read_bytes: cardinal;

EP_code: array[1..64000] of byte;

begin

//открываем файл

hFile:=CreateFile(pchar(strFileName), GENERIC_READ, FILE_SHARE_READ + FILE_SHARE_WRITE, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

//если файл открыт успешно

if hFile<>-1 then begin

//устанавливаем файловый указатель на начало дизассемблируемого кода

SetFilePointer(hFile,StrToInt(strOffset),NIL,FILE_BEGIN);

Назад на стр. 078-114-2  Содержание  Вперед на стр. 078-114-4