2017-04-26 207 views
2

我在C++中做了一個非常簡單的調試器,除非我調用WaitForDebugEvent以及dwMilliseconds之外的任何值,它不會立即暫停調試器。調試器不會暫停異常C++

我有一個if語句,它檢查異常地址是否與我設置的斷點地址if(ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == lpBreakpoint)相匹配。

值減eipwow64cntxt.Eip --;),替換原有的指令(WriteProcessMemory)斷點(int3)字節,刷新指令緩存(FlushInstructionCache),然後設置eip指向我與原來的指令替換斷點(Wow64SetThreadContext )。

然後它返回到主調試循環(break)並繼續調試(ContinueDebugEvent)。

case EXCEPTION_BREAKPOINT: 
{ 
    WOW64_CONTEXT wow64cntxt = {0}; 

    wow64cntxt.ContextFlags = WOW64_CONTEXT_ALL; 

    if(!Wow64GetThreadContext(hThread, &wow64cntxt)) 
    { 
     printf("Error getting thread context: %lu\n", GetLastError()); 
    } 

    //lpFunction is the address of a mov instruction I set a breakpoint on 
    if(excDbgInfo.ExceptionRecord.ExceptionAddress == lpBreakpoint) 
    { 
     printf("EIP-Before: 0x%X\n", wow64cntxt.Eip); 

     //Decrement eip value to point back to the opcode I wrote over with int3 
     wow64cntxt.Eip --; 

     printf("EIP-After: 0x%X\n", wow64cntxt.Eip); 

     //original opcode I replaced with int3(0xCC) 
     instr = 0x89; 

     //replace the breakpoint with the original instruction 
     if(!WriteProcessMemory(hProcess, lpBreakpoint, &instr, sizeof(CHAR), NULL)) 
     { 
      printf("Error reversing breakpoint: %lu\n", GetLastError()); 
     } 

     //Flush the instruction cache 
     FlushInstructionCache(hProcess, lpBreakpoint, 1); 

     //Set eip to previous instruction 
     if(!Wow64SetThreadContext(hThread, &wow64cntxt)) 
     { 
      printf("Error setting thread context: %lu\n", GetLastError()); 
     } 

    } 
    system("pause"); 
    //Return to main debug loop, ContinueDebugEvent... 
    break; 
} 

如果我用比INFINITEWaitForDebugEvent然後eip設置爲執行我設置的斷點一段時間後的地址以外的任何其他。

問題是,如果我不使用WaitForDebugEventINFINITE,則當調試器捕獲到異常時,eip已經超過了斷點。即使我有WaitForDebugEvent等待0毫秒,立即返回,這位移動者仍然跑過斷點。

這會導致訪問衝突,我猜測是因爲用斷點替換的指令的另一半變成了修改內存的新操作碼,所以不允許。

這是我的主要調試循環:

while(1) 
{ 
    WaitForDebugEvent(&dbgEvent, INFINITE); 

    ProcessDebugEvent(&dbgEvent); 

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

的任何信息,洞察力,技巧,講解等將不勝感激。謝謝。

+0

難說你的代碼出了什麼問題,但是當斷點異常處於wow64代碼調試器視圖STATUS_WX86_BREAKPOINT(0x4000001F)而不是STATUS_BREAKPOINT(0x80000003)時,你可以使用「普通」上下文Get [Set] ThreadContext即使WOW64代碼 – RbMm

+0

但是(STATUS_WX86_BREAKPOINT或STATUS_BREAKPOINT依賴是你的調試器64位或32位) – RbMm

+0

順便說一句,我upvoted這個時候我做了壓痕編輯。究其原因是因爲,即使這是一個簡單的面部掌樣的問題,你問得很好,並提出所有必要的信息,以允許其他人來回答。感謝您這樣做,並閱讀我們的幫助。歡迎來到堆棧溢出! (我想這樣說是因爲我看到有人downvoted它,我要你忽略,因爲這是一個完全有效的問題。如果你繼續問這樣的問題,你將有一個美好的時光在這裏。) –

回答

2

dwMilliseconds參數告訴WaitForDebugEvent()多久等待調試事件的出現:

dwMilliseconds [中]
等待調試事件的毫秒數。如果此參數爲零,則函數將測試調試事件並立即返回。如果參數是無窮的,該函數不返回,直到調試事件發生

您需要檢查的WaitForDebugEvent()返回值,以確保你確實有需要處理的實時調試事件:

如果函數成功,則返回值不爲零。

如果函數失敗,返回值爲零。要獲得更多的錯誤信息,請致電GetLastError

例如:

while (1) 
{ 
    if (WaitForDebugEvent(&dbgEvent, AnyValueHere)) // <-- 
    { 
     ProcessDebugEvent(&dbgEvent); 
     ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE); 
    } 
    ... 
} 

話雖這麼說,在dwMilliseconds參數對當遇到斷點調試對象等待多久沒有影響。當中斷點被擊中時,攻擊者立即停止,並通知你的調試器。這是在文檔中明確提出:

Debugging Events

當系統通​​知調試事件的調試器,它也暫停所有的線程在受影響的過程。直到調試通過ContinueDebugEvent繼續調試事件的線程不會恢復執行。

所以有機會,ProcessDebugEvent()根本就沒有正確處理斷點,然後進程被喚醒,只有當你處理完之後,調用ContinueDebugEvent()

+0

非常感謝。現在我發現我應該檢查'WaitForDebugEvent'的返回值。 ** **捂臉。現在運行良好,非常感謝。 :) – EggHead