2017-04-26 203 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