Все, кажись протрезвел... Снова готов к бою. Ну я там и наворотил в первой части. Будем исправлять. :)
Трассировать мы уже можем. Терь нам бы брейкпоинтов понаставить...
Как ставятся брейкпоинты в обычных (не в айсе) дебагерах? Да очень просто! Вот к примеру решили мы поставить bpx на 401000h. Дебагер подрубается к процессу или запускает процесс для дебага. Потом читает байт по адресу 401000h, запоминает его и записывает на его место число CCh. А CCh - это в свою очередь опкод команды int 3h. Т.е. Debug Break. Как тока программа выполнит этот int 3h, будет сгенерено событие EXCEPTION_DEBUG_EVENT с кодом EXCEPTION_BREAKPOINT. В этот момент дебагер ставит байт по адресу 401000h на место и смещает eip на 1 назад (int 3 оно уже выполнило). Таким образом, скока брейк поинтов - стока и байт нужно будет запомнить. И так теперь можно сделать из нашего трейсера чо-нить типа SoftIce Symbol Loader. Т.е прога, которая открывает в дебагере нужный exe с адреса = Entry point ( тот что указан в PE заголовке).
Собственно код:
unit Unit1;
interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private{ Private declarations }public{ Public declarations }end;
var
Form1: TForm1;
sti: tstartupinfo;
lpPi: tprocessinformation;
DE: _Debug_event;
Cont: _Context;
implementation{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);
const
b: array[0..1] of byte = (0, $CC);
var
f: fileof longint;
x: longint;
i: cardinal;
begin
assignfile(f, 'C:\w\notepad.exe');
reset(f);
seek(f, $2A); //читаем OEP из PEread(f, x);
closefile(f);
x := x + $400000; //типа imagebase//добавим еще Create_suspended чтобы процесс без нас никуда не убежал :)
CreateProcess(nil, 'C:\w\notepad.exe', nil, nil, false, DEBUG_PROCESS
or DEBUG_ONLY_THIS_PROCESS or Create_suspended, nil, nil, StI, lpPI);
readprocessmemory(lppi.hProcess, pointer(x), @b[0], 1, i); //запоминаем байт
writeprocessmemory(lppi.hProcess, pointer(x), @b[1], 1, i); //пишем $cc
resumethread(lppi.hThread);
{цикл ожидания EP}whiletruedobeginifnot WaitForDebugEvent(de, 0) then
application.ProcessMessages;
if de.dwDebugEventCode = EXCEPTION_DEBUG_EVENT thenif DE.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT thenbegin
cont.ContextFlags := CONTEXT_CONTROL;
GetThreadContext(lppi.hThread, cont);
{Эти брейкпоинты не тока мы генерим, но и маздай так что
приходится проверку делать: EIP=Entry Point или нет}if cont.eip - 1 = x then// тошо EXCEPTION_BREAKPOINT генерится после int 3.begin
cont.eip := cont.eip - 1;
cont.EFlags := cont.EFlags or $100; //флаг T
setThreadContext(lppi.hThread, cont);
//ставим байт на место
writeprocessmemory(lppi.hProcess, pointer(x), @b[0], 1, i);
break;
end;
ContinueDebugEvent(lppi.dwProcessId, lppi.dwThreadid, DBG_CONTINUE);
end;
ContinueDebugEvent(lppi.dwProcessId, lppi.dwThreadid, DBG_CONTINUE);
end;
{tracing... 0% complete}whiletruedobeginifnot WaitForDebugEvent(de, 0) then
application.ProcessMessages;
if de.dwDebugEventCode = EXCEPTION_DEBUG_EVENT thenif DE.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT thenbegin
GetThreadContext(lppi.hThread, cont);
cont.EFlags := cont.EFlags or $100;
setThreadContext(lppi.hThread, cont);
{Здесь мог бы быть ваш код :))) }
ContinueDebugEvent(lppi.dwProcessId, lppi.dwThreadid, DBG_CONTINUE);
endelseif DE.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_SINGLE_STEP
thenbegin
cont.ContextFlags := CONTEXT_CONTROL;
GetThreadContext(lppi.hThread, cont);
cont.EFlags := cont.EFlags or $100;
setThreadContext(lppi.hThread, cont);
{Здесь мог бы быть ваш код :))) }
ContinueDebugEvent(lppi.dwProcessId, lppi.dwThreadid, DBG_CONTINUE);
end;
end;
end;
end.
P.S. Я тут Reset и Read юзал для работы с файлом. Но лучше все сделать через апи (createfile, readfile и т.д.), потому что если будет запущена прога которую мы вот ща типа трейсить будем, то делфи будет орать про I/O error. Естественно, тошо делфа не умеет открывать файл для Shared доступа :(
Статья Новогодний трейсер часть 2. Брейкпоинты. раздела Программа и Интерфейс Исследование программ может быть полезна для разработчиков на Delphi и FreePascal.
Комментарии и вопросы
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.