скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Новогодний трейсер



Автор: 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 заголовка. Но это жеж не прикольно :)






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook