调试器不会在异常C ++

时间:2017-04-26 14:30:32

标签: c++ debugging winapi breakpoints

我在C ++中创建了一个非常简单的调试器,它似乎工作正常,除非我WaitForDebugEventdwMilliseconds之外的任何值INFINITE,它不会暂停debugee立即

我有一个if语句,用于检查异常地址是否与我设置的断点地址if(ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == lpBreakpoint)匹配。

递减eipwow64cntxt.Eip --;),用原始指令(int3)替换断点(WriteProcessMemory)字节,刷新指令缓存(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;
}

如果我使用INFINITE以外的WaitForDebugEvent以外的任何内容,则eip设置为在我设置的断点后执行一段时间的地址。

问题在于,如果我不将WaitForDebugEventINFINITE一起使用,那么当调试器捕获异常时,eip已经超过了断点。即使我WaitForDebugEvent等待0毫秒,立即返回,debugee仍然会超过断点。

这会导致访问冲突,我猜测是因为我用断点替换的另一半指令变成了一个新的操作码,它修改了不允许的内存。

这是我的主要调试循环:

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

    ProcessDebugEvent(&dbgEvent);

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

任何信息,见解,提示,解释等都将不胜感激。感谢。

1 个答案:

答案 0 :(得分:2)

BaggingClassifier参数告诉dwMilliseconds等待调试事件到达的时间:

  

dwMilliseconds [in]
  等待调试事件的毫秒数。如果此参数为零,则该函数将测试调试事件并立即返回。如果参数为INFINITE,则在发生调试事件之前函数不会返回

您需要检查WaitForDebugEvent()的返回值,以确保您确实有一个需要处理的实际调试事件:

  

如果函数成功,则返回值为非零值。

     

如果函数失败,则返回值为零。要获取扩展错误信息,请致电WaitForDebugEvent()

例如:

GetLastError

话虽这么说,while (1) { if (WaitForDebugEvent(&dbgEvent, AnyValueHere)) // <-- { ProcessDebugEvent(&dbgEvent); ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE); } ... } 参数对调试对象在命中断点时等待的时间没有影响。当断点被击中时,debugee立即停止,并通知您的调试器。这在文档中明确说明:

Debugging Events

  

当系统通知调试器调试事件时,它还会挂起受影响进程中的所有线程。在调试器使用dwMilliseconds继续调试事件之前,线程不会继续执行。

很可能,ContinueDebugEvent根本没有正确处理断点,然后只有在完成处理后调用ProcessDebugEvent()时才会唤醒调试对象。<​​/ p>