2013-05-14 28 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); 
} 
相關問題