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

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

GPcH (www.dotfix.net)

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


//считываем 64000 байт кода

ReadFile(hFile,EP_Code,64000,read_bytes,NIL);

//закрываем файл

CloseHandle(hFile);

//возвращаем pointer на считанный код

result:=@EP_Code;

end else begin

//если не смогли открыть файл — выходим

exit;

end;

end;

В данной функции мы использовали только Win32 API. В данном случае это значительно удобнее, чем морочиться со встроенными средствами Delphi. Смотри. Функция CreateFile открыла файл, заданный в текстовом поле, и вернула хэндл hFile для работы с ним. SetFilePointer указала, откуда в файле начинать считывать байты, а ReadFile, соответственно, эти байты считала в буфер EP_code (pointer на который мы будем потом использовать). Вот и все. Конечно, по-хорошему надо бы использовать file mapping для получения указателя на код, но для наших целей хватит и того, что есть.

Теперь напишем функцию, которая будет дизассемблировать по одной инструкции код, находящийся по заданному pointer’у:

function TfrmMain.Disasm(strAsm: pointer): string;

var

strDisAsm, strdasm: string;

retval: TCodeInfo;

begin

// strDisAsm — первая строка листинга

retval:=madDisAsm.ParseCode(strAsm,strDisAsm);

// в переменной strdasm мы будем хранить весь листинг

strdasm:=strDisAsm;

//перебираем команды до тех пор, пока не встретим ret

while strpos(pchar(strDisAsm),'ret')= nil do begin

//дизассемблируем очередную команду

retval:=madDisAsm.ParseCode(retval.Next,strDisAsm);

//добавляем ее в конец листинга

strdasm:=strdasm + #13#10 + strDisAsm;

end;

//возвращаем листинг

result:=strdasm;

end;

Функция будет дизассемблировать машинный код до тех пор, пока не встретит ret или ошибку доступа к памяти. Подобная ошибка (exception) может возникнуть, если во всем коде, скопированном в буфер, так и не обнаружится ret. В этом случае наша программа просто вылезет за пределы выделенной памяти, и сработает exception, вызвав у пользователя шквал эмоций («Ваша программа выполнила недопустимую операцию и будет закрыта» или что-нибудь вроде этого). Так что в будущем надо бы добавить обработку этой ошибки, чтобы наша прога не вылетала всякий раз при отсутствии ret’а.

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

[первая кнопка]

procedure TfrmMain.cmdDisasmClick(Sender: TObject);

begin

txtDisasm.Text:=Disasm(GetCode(txtFileName.Text, txtOffset.Text));

end;

[вторая кнопка]

procedure TfrmMain.cmdDisAsmFunctionClick(Sender: TObject);

var

strDisAsm: string;

begin

madDisasm.ParseFunctionEx(

GetCode(txtFileName.Text, txtOffset.Text),

strDisAsm,nil,0,true);

txtDisasm.Text:=strDisAsm;

end;

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

[тестируем]

Давай, чтобы проверить работоспособность нашего дизассемблера, напишем какую-нибудь простенькую программу и скормим ему. Логично, что программу писать надо на ассемблере, иначе мы не поймем, правильно ли он перевел машинный код в ассемблерный листинг. Бери с диска Fasm, один из самых юзабельных на сегодня компиляторов ассемблера, запускай его редактор и вбивай следующий код:

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