我在C ++中创建了一个非常简单的调试器,它似乎工作正常,除非我WaitForDebugEvent
除dwMilliseconds
之外的任何值INFINITE
,它不会暂停debugee立即
我有一个if
语句,用于检查异常地址是否与我设置的断点地址if(ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == lpBreakpoint)
匹配。
递减eip
(wow64cntxt.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
设置为在我设置的断点后执行一段时间的地址。
问题在于,如果我不将WaitForDebugEvent
与INFINITE
一起使用,那么当调试器捕获异常时,eip
已经超过了断点。即使我WaitForDebugEvent
等待0毫秒,立即返回,debugee仍然会超过断点。
这会导致访问冲突,我猜测是因为我用断点替换的另一半指令变成了一个新的操作码,它修改了不允许的内存。
这是我的主要调试循环:
while(1)
{
WaitForDebugEvent(&dbgEvent, INFINITE);
ProcessDebugEvent(&dbgEvent);
ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE);
}
任何信息,见解,提示,解释等都将不胜感激。感谢。
答案 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立即停止,并通知您的调试器。这在文档中明确说明:
当系统通知调试器调试事件时,它还会挂起受影响进程中的所有线程。在调试器使用
dwMilliseconds
继续调试事件之前,线程不会继续执行。
很可能,ContinueDebugEvent
根本没有正确处理断点,然后只有在完成处理后调用ProcessDebugEvent()
时才会唤醒调试对象。</ p>