Delphi World - Новогодний трейсер
Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Новогодний трейсер

Автор: Hex

Очнулся я тут от новогодней пьянки и решил написать чо-нить полезное. Вот к примеру там свой дебагер или еще чо-нить... Ну про дебагер это я загнул. Ну хотя б трейсер.

Чо такое трейсер - прога, которая пошагово выполняет код. Какие перспективы не правда ли? Делаем на основе трейсера загрузчик и прям сказка - можно запросто ломать проги, которые проверяют целостность своих данных - например дойдем до места где jnz не надо выполнять и просто переместим EIP на следующую команду (типа не выполнилось), и все красиво. Целостность не нарушена :)

Итак, как же его писать... Для того чтобы сделать трейсер нам нужны будут Debug API. Вот я тут трейсер написал чтобы находить OEP. Значит ща код трейсера для поиска Entry Point в Notepad, а потом пояснения. КОД:


unit Unit1;

interface

uses
  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);

begin
  CreateProcess(nil, 'c:\w\notepad.exe', nil, nil, false, DEBUG_PROCESS
    or DEBUG_ONLY_THIS_PROCESS, nil, nil, StI, lpPI);

  while true do
  begin
    WaitForDebugEvent(de, INFINITE);
    application.ProcessMessages;
    if de.dwDebugEventCode = EXCEPTION_DEBUG_EVENT then
      if DE.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT then
      begin
        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
      else if DE.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_SINGLE_STEP
        then
      begin
        GetThreadContext(lppi.hThread, cont);
        cont.EFlags := cont.EFlags or $100;
        setThreadContext(lppi.hThread, cont);
        if (cont.eip > $400000) and (cont.eip < $600000) then
        begin
          Showmessage('OEP=' + inttohex(cont.eip, 8));
          halt;
        end;
        ContinueDebugEvent(lppi.dwProcessId, lppi.dwThreadid, DBG_CONTINUE);
      end;

    ContinueDebugEvent(lppi.dwProcessId, lppi.dwThreadid, DBG_CONTINUE);
  end;

end;

end.

Оно работает так: Создается процесс с параметрами DEBUG_PROCESS и DEBUG_ONLY_THIS_PROCESS. DEBUG_ONLY_THIS_PROCESS - нужно для того чтобы перехватывать сообщения только от процесса, который создадим, а не все подряд. После этого создастся процесс который будет отсылать дебаговые сообщения. Делаем бесконечный цикл с WaitForDebugEvent, чтобы отлавливать дебаговые сообщения которые будет отсылать процесс. В этом цикле нам нужно будет обработать событие EXCEPTION_DEBUG_EVENT. Для этого события нам нужно будет обрабатывать 2 Exception кода: EXCEPTION_BREAKPOINT и EXCEPTION_SINGLE_STEP. Код остановки и код одиночного шага(выполнение одной команды). Когда процесс создан для дебага нам нужно будет включить флаг трассировки чтобы программа генерила EXCEPTION_BREAKPOINT и EXCEPTION_SINGLE_STEP после каждой выполненой команды. Получить данные о состоянии регистров выполняемого процесса можно через GetThreadContext, а установить их через SetThreadContext. GetThreadContext возвращает структуру _CONTEXT которая содержит данные о всех регистрах(в ключая EIP) и флагах выполняемого процесса. Но перед тем как читать данные о регистрах в эту структуру, нужно задать свойство ContextFlags=CONTEXT_CONTROL. Иначе будут возвращатся тока ноли. При обработке кодов EXCEPTION_BREAKPOINT и EXCEPTION_SINGLE_STEP нужно постоянно включать флаг трассировки через свойство EFlags структуры _CONTEXT (cont.EFlags:=cont.EFlags or $100;) После обработки каждого сообщения нужно разрешить программе выполняться дальше. Делается это через ContinueDebugEvent. Ну и наконец в обработке EXCEPTION_SINGLE_STEP я читаю текущий eip процесса, чтобы найти EP. Так как в реале, процесс начинает выполнятся не с Entry point а с загрузки всяких DLL и т.д.

Можно конечно было взять его из PE заголовка. Но это жеж не прикольно :)

Проект Delphi World © Выпуск 2002 - 2017
Автор проекта: Эксклюзивные курсы программирования