TraceDebug

功能简述:可以跟踪exe执行的序列,并记录到文件里。作用主要可以比较exe在不同环境中执行的差异处。从而可以得到差异点。

思路:首先需要用DEBUG_PROCESS标志CreateProcess加载目标程序。然后在每一步下断点,同时得到eip的值,写入文件里(同时记录寄存器的值也可以) 如何下断点呢?其实普通的中断是Int3,也就是在需要中断的地方插入Int3,然后再WaitForDebugEvent循环里判断中断类型。对于每一步都中断的情况,只需要在入口插入int3,然后单步执行就可以了。那么如何插入int3呢?其实也就是修改中断地址的头一个字节为CC,同时保存原来的字节。中断的时候再把原来的字节写回去。调用的api主要是WriteProcessMemory。中断后如何得到eip和寄存器的值呢?使用的是GetThreadContext函数,思路基本清楚了,开始动手把。首先设计一个TBreakPointMgr类,用于管理断点,因为断点可能多个。然后新建一个线程来启动目标程序(你总不希望调试的时候我们的程序挂起吧)

先来看看TBreakPointMgr类。

/// <summary>

/// 断点管理的类,主要作用是设置断点,清除断点,查找断点。里面定义了一个TBreakPointRec

/// 结构的数组,用于存放断点。

/// </summary>

/// <author>bohe</author>

unit untBreakPointMgr;

 

interface

 

uses

  Classes,Windows;

 

type

  TBreakPointRec = packed record

    pAddr: Cardinal;

    Code: char;

  end;

  TBreakPointMgr = class(TObject)

  private

    fhDebug: THandle;    //debug进程结构

    fBreakList: array of TBreakPointRec;  //breakpoint list

  public

    //breakpoint has been setted at pAddr?

    function FindBreakPoint(pAddr: Cardinal; var code: char): boolean;

    constructor Create(hDebug: THandle);

    //adding or deleting a breakpoint will call this function

    function SetBreakPoint(pAdd: Cardinal;Code: char): char;

    //delete a breakpoint

    procedure DelBreakPoint(pAdd: Cardinal);

    //clear all breakpoints

    procedure ClearBreakPoint;

    //add a breakpoint at pAddr

    procedure AddBreakPointAt(pAddr: Cardinal);

  end;

 

implementation

 

{ TMyDebug }

 

 

{ TMyDebug }

 

 

procedure TBreakPointMgr.AddBreakPointAt(pAddr: Cardinal);

var

  Code,tmp: char;

begin

  Code := SetBreakPoint(paddr,chr($CC));

  //断点列表里没有这个地址

  if not FindBreakPoint(pAddr,Code) then

  begin

    SetLength(fBreakList,Length(fBreakList)+1);

    fBreakList[Length(fBreakList)-1].pAddr := pAddr;

    fBreakList[Length(fBreakList)-1].Code := Code;

  end;

end;

 

procedure TBreakPointMgr.ClearBreakPoint;

var

  i: Integer;

begin

  for i := 0 to Length(fBreakList) - 1 do

  begin

    DelBreakPoint(fbreaklist[i].pAddr);

  end;

end;

 

constructor TBreakPointMgr.Create(hDebug: THandle);

begin

  fhDebug := hDebug;

end;

 

procedure TBreakPointMgr.DelBreakPoint(pAdd: Cardinal);

var

  Code: char;

  i,j: Integer;

begin

  if FindBreakPoint(pAdd,code) then

  begin

    SetBreakPoint(pAdd,Code);

  end;

end;

 

function TBreakPointMgr.FindBreakPoint(pAddr: Cardinal; var Code: char): Boolean;

var

  i: Integer;

begin

  Result := false; //chr(0);

  for i := 0 to Length(fBreakList)-1 do

  begin

    if fBreakList[i].pAddr = pAddr then

    begin

      Code := fBreaklist[i].Code;

      result := true;

      exit;

    end;

  end;

 

end;

 

function TBreakPointMgr.SetBreakPoint(pAdd: Cardinal; Code: char): char;

var

  b: byte;

  rc: boolean;

  dwRead,dwOldFlg: Cardinal;

begin

  Result := code;

  // 0x80000000以上的地址为系统共有区域,不可以修改

  if((pAdd >= $80000000) or (pAdd = 0)) then exit;

  // 取得原来的代码

  rc := ReadProcessMemory(fhDebug, Pointer(pAdd), @b, sizeof(BYTE), dwRead);

  // 原来的代码和准备修改的代码相同,没有必要再修改

  if((not rc) or (Chr(b) = code)) then exit;

  // 修改页码保护属性

  VirtualProtectEx(fhDebug, Pointer(pAdd), sizeof(char), PAGE_READWRITE,

  @dwOldFlg);

  // 修改目标代码

  if WriteProcessMemory(fhDebug, Pointer(pAdd), @code, sizeof(char), dwRead) then

    result := Chr(b)

  else Result := Chr(0);

  // 恢复页码保护属性

  VirtualProtectEx(fhDebug, Pointer(pAdd), sizeof(char), dwOldFlg, @dwOldFlg);

end;

 

end.

接着看TTraceDebug类,这是一个线程类。

/// <summary>

/// 线程类,在里面加载目标程序,同时在waitDebugEvent循环里监测目标进程。

/// </summary>

/// <author>bohe</author>

unit untWaitDebug;

 

interface

 

uses

  Classes,windows,SysUtils ,forms, untBreakPointMgr, ComCtrls;

 

 

 

type

  TThreadInfo = record

    ThreadId: Cardinal;

    hThread: THandle;

  end;

  TTraceDebug = class(TThread)

  private

    { Private declarations }

    fLogStr: string;

    m_hDebug: THandle;

    m_hThread: THandle;

    BPMgr: TBreakPointMgr;

    //hThread: THandle;

    //ThreadList: TStringList;

    bStartRec: Boolean;

    NumOfCodeLine: integer;

    MaxCodeLines: Integer;

    LowAddr: DWORD;

    HighAddr: DWORD;

    BreakPointAddress: DWORD;

    flog: TextFile; //   trace file

    logfile: string; //file name of trace

    //lst: TListview;

    function OnDebugEvent(pEvent: DEBUG_EVENT): Boolean;

    function OnDebugException(pEvent: DEBUG_EVENT): Boolean;

    procedure ResumeAllThread(dwThrdID: Cardinal);

    procedure SuspendAllThread(dwThrdID: Cardinal);

    procedure ClearLog;

    procedure AddResultLog();

    //procedure writeTrace(str);

    procedure SyncAddLog(logstr: string);

 

 

  protected

    procedure Execute; override;

 

  public

    exeName: string;

    procedure AddBreakPoint(Addr: Cardinal);

  end;

 

implementation

 

uses untMyDebug, main;

 

{ WaitDebug }

 

procedure TTraceDebug.AddBreakPoint(Addr: Cardinal);

begin

    BPMgr.AddBreakPointAt(Addr);

end;

 

procedure TTraceDebug.AddResultLog();

var

  lst: TListView;

begin

  //if flog<>0 then

  begin

   if not FileExists(logfile) then

      Rewrite(flog)

    else

      Append(flog);

    Writeln(flog,flogstr); 

  end;

 

end;

 

procedure TTraceDebug.ClearLog;

begin

//  frmDebug.lstLast.Items.Clear;

 // frmDebug.lstFirst.Items.Clear;

end;

 

 

procedure TTraceDebug.Execute;

var

  si: _STARTUPINFOA;       {进程启动信息}

  pi: _PROCESS_INFORMATION; {进程信息}

  Flage: DWORD;

  DebugEvent: DEBUG_EVENT;  {调试事件}

  Rc: Boolean;

  CodeCount: DWORD;{运行的指令数}

  ThreadHandle: Thandle;{主线程句柄}

  ThreadIDtoAttach: DWORD; {主线程句柄}

  ThreadContext: TContext;

  bWriteMem: boolean;

  //ProcessHandle: THandle;

  //ProcessIDtoAttach: DWORD;

begin

 

  Synchronize(ClearLog);

  bStartRec := true;

  NumOfCodeLine :=0;

  {建立调试进程}

  CodeCount := 0;

  //ThreadList := TStringList.Create;  //创建线程列表,

  //ConText.ContextFlags := CONTEXT_CONTROL;

  if frmDebug.rgpTrace.ItemIndex=0 then

    logfile := 'trace1.log'

  else logfile := 'trace2.log';

  AssignFile(flog,logfile);

  Rewrite(flog);

  Flage := DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS;

  LowAddr := StrToInt('$'+frmDebug.edtLowAddr.Text);

  HighAddr := StrToInt('$'+frmDebug.edtHighAddr.Text);

  BreakPointAddress := StrToInt('$'+frmDebug.edtEOP.Text);  //入口断点

  MaxCodeLines := StrToInt(frmDebug.edtMaxNum.Text);

  GetStartupInfo(si);    {初始化si结构,不然无法正常建立进程}

  NumOfCodeLine := 0;

  ThreadHandle:=0;

  {if frmDebug.rgpTrace.ItemIndex=0 then

    lst := frmDebug.lstFirst

  else lst := frmDebug.lstLast;  }

  if not CreateProcess(nil, Pchar(exeName), nil, nil,

    False, Flage, nil, nil, si, pi) then

  begin

    fLogStr := '建立被调试进程失败';

    Synchronize(AddResultLog);

    exit;

  end;

  //ProcessHandle := pi.hProcess;

  CloseHandle(pi.hProcess);

  Closehandle(pi.hThread);

  while WaitForDebugEvent(DebugEvent, INFINITE) do

  begin  {根据事件代码进行相应处理}

    rc := OnDebugEvent(DebugEvent);

    if Rc then

      ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId,

         DBG_CONTINUE)

    else

      ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId,

         DBG_EXCEPTION_NOT_HANDLED);

  end;

 

end;

 

 

 

function TTraceDebug.OnDebugEvent(pEvent: DEBUG_EVENT): Boolean;

begin

  Result := true;

  case (pEvent.dwDebugEventCode) of

    CREATE_PROCESS_DEBUG_EVENT:

    begin

     m_hDebug := pEvent.CreateProcessInfo.hProcess;

     m_hThread := pEvent.CreateProcessInfo.hThread;

     //hThread := pEvent.CreateProcessInfo.hThread;

     //ThreadList.Clear;

     //ThreadList.AddObject(IntToStr(pEvent.dwThreadId),Pointer(pEvent.CreateProcessInfo.hThread));

     BPMgr := TBreakPointMgr.Create(m_hDebug);

     AddBreakPoint(BreakPointAddress);

     fLogStr := '被调试进程建立';

     //Synchronize(AddResultLog);

      //m_hDebug := pEvent->u.CreateProcessInfo.hProcess;

      // 记录线程ID和线程句柄的关系

      //m_gthreads[pEvent->dwThreadId] = pEvent->u.CreateProcessInfo.hThread;

    end;

    CREATE_THREAD_DEBUG_EVENT:

    begin

      //ThreadList.AddObject(IntToStr(pEvent.dwThreadId),Pointer(pEvent.CreateThread.hThread));

      // 记录线程ID和线程句柄的关系

      //m_gthreads [pEvent->dwThreadId] = pEvent->u.CreateThread.hThread;

    end;

 

    EXIT_THREAD_DEBUG_EVENT:

    begin

      // 线程退出时清除线程ID

      //m_gthreads.erase (pEvent->dwThreadId);

    end;

 

    EXCEPTION_DEBUG_EVENT:

    begin

      // 中断处理程序

      Result  := OnDebugException(pEvent);

    end;

  end;

end;

 

function TTraceDebug.OnDebugException(pEvent: DEBUG_EVENT): Boolean;

var

  pBreakAdd: Pointer;

  ThreadContext: CONTEXT;

  //hThread: THandle;

  Code: Cardinal;

  tmp: Char;

  callMem: pByte;

  dwRead: Cardinal;

  nMemLen: Integer;

  pMem: Cardinal;

  idx: integer;

  PwdBuf: pchar;

  //dwRead: Integer;

  tmpStr: string;

 

  bWriteMem: boolean;

begin

  Result := false;

 

 

  pBreakAdd := pEvent.Exception.ExceptionRecord.ExceptionAddress;

  code := pEvent.Exception.ExceptionRecord.ExceptionCode;

  //ThreadList.Find(IntToStr(pEvent.dwThreadId),idx);

  //hThread := Cardinal(ThreadList.Objects[idx]);

  ThreadContext.ContextFlags := CONTEXT_FULL;

  GetThreadContext(m_hthread, ThreadContext);

  if(pEvent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_BREAKPOINT) then

    begin

        Result := true;

        if not BPMgr.FindBreakPoint(Cardinal(pBreakAdd),tmp) then exit;

        ThreadContext.ContextFlags:=CONTEXT_CONTROL;      //important

        GetThreadContext(m_hThread,ThreadContext);

        if(abs(ThreadContext.Eip-BreakPointAddress)<2)       then

        begin

          ThreadContext.EFlags:=ThreadContext.EFlags or $100;

          BPMgr.DelBreakPoint(BreakPointAddress);

          ThreadContext.Eip:=BreakPointAddress;

          SetThreadContext(m_hThread, ThreadContext);

          //bWriteMem:=WriteProcessMemory(ProcessHandle,BreakPointAddress,OldCode,1,ByteWriten);

          bStartRec:=true;

          Result := true;

        end;

    end

              else  if((pevent.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_SINGLE_STEP) and bStartRec)  then

    begin

      Result := true;

                     GetThreadContext(m_hThread,ThreadContext);

                     if(Threadcontext.Eip>=LowAddr) and (ThreadContext.Eip <= $ 2c 01000) then

      begin

        //跟踪结束,次数或者结束地址

                            if(NumofCodeLine>=MaxCodeLines) or (ThreadContext.Eip=HighAddr) then

        begin

                                   bStartRec:=false;

          frmDebug.sbar.SimpleText := 'finished!';

          //LoadLstData;

          CloseFile(flog);

          //lst.Items.EndUpdate;

 

          frmDebug.btnRun.Enabled := true;

          //frmDebug.btnCmp.Enabled := frmDebug.rgpTrace.ItemIndex=1;

          frmDebug.rgpTrace.ItemIndex := 1-frmDebug.rgpTrace.ItemIndex;

                                   //break;

                            end

        else begin

                            //pArraytoDump[NumofCodeLine]=ThreadContext.Eip;

          fLogStr := IntToHex(ThreadContext.Eip,8);

          Synchronize(AddResultLog);

                              inc(NumofCodeLine);

        end;

                     end;

                     ThreadContext.EFlags:=ThreadContext.EFlags or $100;

                     SetThreadContext(m_hthread, ThreadContext);

              end

              else  if(pEvent.Exception.ExceptionRecord.ExceptionCode=EXIT_PROCESS_DEBUG_EVENT)    then

    begin

//                   DebugSetProcessKillOnExit(false);

      result := true;

                     exit;

              end

 

 

end;

 

procedure TTraceDebug.ResumeAllThread(dwThrdID: Cardinal);

var

  i: Integer;

  dwID: Cardinal;

begin

 { for i := 0 to ThreadList.Count - 1 do

  begin

    dwID := StrToInt(ThreadList[i]);

    if dwID<>dwThrdID then

      ResumeThread(Cardinal(ThreadList.Objects[i]));

  end;   }

end;

 

procedure TTraceDebug.SuspendAllThread(dwThrdID: Cardinal);

var

  i: Integer;

  dwID: Cardinal;

begin

  {for i := 0 to ThreadList.Count - 1 do

  begin

    dwID := StrToInt(ThreadList[i]);

    if dwID<>dwThrdID then

      SuspendThread(Cardinal(ThreadList.Objects[i]));

  end;  }

 

end;

 

procedure TTraceDebug.SyncAddLog(logstr: string);

begin

  fLogStr := logstr;

  Synchronize(AddResultLog);

end;

 

end.

主界面就没有什么好说的了。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值