Windows用户态调试器原理(三)

2014-11-24 08:19:00 · 作者: · 浏览: 2
对异常进行解析,并且将DBG_CONTINUE或者是DBG_EXECPTION_NOT_HANDLED作为参数传递给ContinueDebugEvent。如果执行DBG_CONTINUE,则操作系统认为该异常已经被妥善处理了。因此从产生异常的地址开始回复程序的执行。如果传入DBG_EXCEPTION_NOT_HANDLED,则告诉操作系统该异常并未被处理,操作系统将继续分发异常。
[cpp]
case EXCEPTION_DBUG_EVENT:
{
std::cout<<”异常码为”<
//在switch判断异常类型,并执行相应操作。
switch(debugEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
break;
case EXCEPTION_SINGLE_STEP:
beak;
return DBG_CONTINUE;
}
break;
}
在调试循环中,从WaitForDebugEvent中返回以及调用ContinueDebugEvent之间的这段时间内,调试目标不会执行,因此它的状态也将保持不变。当调试目标被挂起时,调试器就进入了交互模式,接收用户的各种指令,并按照不同指令执行不同操作。
调试事件到来的顺序
当我们启动调试目标时,调试器接收到的第一个事件是CREATE_THREAD_DEBUG_EVENT。接下来是加载dll的事件。每加载一个,都会产生一个这样的事件。
当所有模块都被加载到进程地址空间后,调试目标就准备好运行了,调试器此时也做好了接收通知的准备。此时是设置断点的最佳时机。
在调试目标退出之前调试器会收到 EXIT_DEBUG_PROCESS_EVENT通知。此后调试器不能收到加载到进程地址空间的dll从进程卸载的UNLOAD_DLL_DEBUG_EVENT通知。
前面介绍的调试事件都是由Windows操作系统发出的,来通知调试器。但是调试目标也会发出自己的异常。调试器在处理这些异常时可以选择与其他调试事件一样的处理方式。
Windows操作系统使用结构化异常处理(SEH)机制将处理器引发的异常传递给内核及用户态程序。每个SEH异常都有一个无符号整形的异常码来唯一标识。这个异常码是由系统在异常发生时指定的。这些异常码使用了操作系统开发人员定义的公开异常码。例如访问违规异常异常码为0xC0000005,断点异常为0xC80000003。为了方便记忆,这些异常码被定义为常量。其名字形如STATUS_XXX。如
#define STATUS_BREAKPOINT ((NTSTATUS)0x80000003L)
由于异常码很难记忆,因此Windows调试器中包含了一些更容易记住的别名来控制调试器的行为。例如断点异常0x80000003 的别名是bpe。C++异常码0xE06D7363别名为eh。