скрыть

скрыть

  Форум  

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

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



Google  
 

Новогодний трейсер часть 2. Брейкпоинты.



Автор: Hex

Все, кажись протрезвел... Снова готов к бою. Ну я там и наворотил в первой части. Будем исправлять. :)

Трассировать мы уже можем. Терь нам бы брейкпоинтов понаставить... Как ставятся брейкпоинты в обычных (не в айсе) дебагерах? Да очень просто! Вот к примеру решили мы поставить 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;

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);
const
  b: array[0..1] of byte = (0, $CC);
var
  f: file of longint;
  x: longint;
  i: cardinal;
begin

  assignfile(f, 'C:\w\notepad.exe');
  reset(f);
  seek(f, $2A); //читаем OEP из PE
  read(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}
  while true do
  begin
    if not WaitForDebugEvent(de, 0) then
      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);
        {Эти брейкпоинты не тока мы генерим, но и маздай так что
        приходится проверку делать: 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}
  while true do
  begin

    if not WaitForDebugEvent(de, 0) then
      application.ProcessMessages;

    if de.dwDebugEventCode = EXCEPTION_DEBUG_EVENT then
      if DE.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT then
      begin
        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
        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 доступа :(






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




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