2013-05-14 26 views
4

Read eax register中给出的以下建议,我用winapi写了一个简单的调试器。 我的目标是每次在另一个线程中执行汇编指令后读取eax寄存器。 它正在工作,我设法在另一个进程中放置一个硬件断点。在另一个进程中处理断点

当调试线程内部出现断点时,我可以按照预期读取eax寄存器,但仍然找不到恢复线程执行的任何方法。

我的代码:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
// Finding Window 
HWND window = FindWindow(0, _T("Test")); 
if(window == 0) 
{ 
    printf("Process not found!\n"); 
    return 0; 
} 

DWORD_PTR pID = 0; 
GetWindowThreadProcessId(window, &pID); 


// Get Handle 
//HANDLE _handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID); 

DWORD_PTR eax = 0; 
DWORD_PTR address = 0xC31E1B; // address of the instruction after the call for hardware breakpoint 

DebugActiveProcess(pID); // PID of target process 

// Avoid killing app on exit 
DebugSetProcessKillOnExit(false); 

// get thread ID of the main thread in process 
DWORD_PTR dwThreadID = GetProcessThreadID(pID); 

// gain access to the thread 
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID); 

SetDebugPrivilege(true); 

//ctx.Dr6=0;   //clear debug status register (only bits 0-3 of dr6 are cleared by processor) 

CONTEXT ctx = {0}; 
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_INTEGER; 
ctx.Dr0 = address; 
ctx.Dr7 = 0x00000001; 


// hThread with enough permissions 
SetThreadContext(hThread, &ctx); 

DEBUG_EVENT dbgEvent; 
while (true) 
{ 
    if (WaitForDebugEvent(&dbgEvent, INFINITE) == 0) 
     break; 

    if (dbgEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT && 
     dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) // EXCEPTION_BREAKPOINT 
    { 
     if (dbgEvent.u.Exception.ExceptionRecord.ExceptionAddress == (LPVOID)address) 
     { 
      GetThreadContext(hThread, &ctx); 
      eax = ctx.Eax; // eax get 
      std::cout<<eax<<"\n"; 
      // Resume execution 
      ctx.Eip = address + 0x3; 
      SetThreadContext(hThread, &ctx); 
     } 

    } 

    ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE); 
} 
return 0; 
} 

感谢您的帮助!

+1

对于一个断点,您通常使用int 3,其中(至少乍一看)增加3到EIP看起来只有一个字节,所以错误。此外,int 3通常会覆盖现有字节,因此通常会恢复现有字节,设置单步标志,执行一条指令,在该字节中重新设置int 3,并清除单步标志。 – 2013-05-14 03:26:22

+1

他使用硬件断点,所以我认为没有什么可以恢复。 – schlicht 2014-02-21 16:48:58

+0

@alkapone你设法做到这一点吗? – victor 2015-10-20 09:20:00

回答

1

从这个摘自:Hardware breakpoints EXCEPTION_SINGLE_STEP all the time

整个逻辑应该如下:

  1. 添加断点。
  2. 触发后,您将删除断点并在EFLAGS中设置单步标志(0x100)
  3. 下一次调用循环时,将重新启用硬件断点。

所以你的while循环应该是这样的:

while (true) 
{ 
    if (WaitForDebugEvent(&dbgEvent, INFINITE) == 0) 
     break; 

    if (dbgEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT && 
     dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) // EXCEPTION_BREAKPOINT 
    { 
     CONTEXT newCtx = {0}; 
     newCtx.ContextFlags = CONTEXT_ALL; 
     GetThreadContext(hThread, &newCtx); 
     if (dbgEvent.u.Exception.ExceptionRecord.ExceptionAddress == (LPVOID)address) 
     { 
      newCtx.Dr0 = newCtx.Dr6 = newCtx.Dr7 = 0; 
      newCtx.EFlags |= (1 << 8); 
     }else{ 
      newCtx.Dr0 = address; 
      newCtx.Dr7 = 0x00000001; 
      newCtx.EFlags &= ~(1 << 8); 
     } 
     SetThreadContext(hThread, &newCtx); 
    } 
    ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE); 
} 
相关问题