CPU执行指令时可能会触发异常,例如除0错误,内存访问错误,这种称为“硬异常”。
还有一种可以通过软件模拟异常,通过调用windows API函数 RaiseException可以主动触发异常。
如下:
RaiseException(EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_NONCONTINUABLE, 0, NULL);
第二个参数是dwExceptionFlags,如果为EXCEPTION_NONCONTINUABLE说明此异常 不可继续,也就是说异常过滤函数不可以返回EXCEPTION_CONTINUE_EXECUTION,不然会触发嵌套异常STATUS_NONCONTINUABLE_EXCEPTION,对应0xC0000025L
嵌套异常中EXCEPTION_RECORD结构体中变量struct _EXCEPTION_RECORD *ExceptionRecord指向了之前触发的异常。如果第二个参数传入0,那么代表异常处理后可以继续执行代码,过滤函数可以返回EXCEPTION_CONTINUE_EXECUTION。
RaiseException的调用函数大致流程如下
RaiseException->RtlRaiseException->
ntdll!RtlCaptureContext
ntdll!NtRaiseException(之后还有 ntdll!RtlRaiseStatus )
RtlRaiseException中会调用ntdll!RtlCaptureContext,获取上下文,Context中的EIP为RtlRaiseException的返回地址,如果可以继续,那么会直接返回到RaiseException中call RtlRaiseException的后面。
接着RtlRaiseException调用ntdll!NtRaiseException
正常情况下 调用ntdll!NtRaiseException之后是不会返回的
//分几种情况
1、如果捕获异常并EXCEPTION_EXECUTE_HANDLER长跳转 那么必定不会返回 也不会ntcontinue返回内核
2、如果捕获异常处理异常了可以继续执行 那么会NtContinue返回内核 设置eip 返回到RaiseException中调用RtlRaiseException的后面 直接跳的 内核设置eip
3、如果处理不了异常 那么肯定也不会返回了
如果返回那么调用RtlRaiseStatus抛出异常 传入参数为上一个函数的返回值 可能传参出错,此时需要解决的不是原来的异常 而是此时的异常。
软异常存在嵌套异常,即_EXCEPTION_RECORD *ExceptionRecord可以不为空。
当异常触发时如果在过滤函数中再次触发了硬异常,那么还会由当前的SEH节点捕获到异常,造成递归,可能会导致栈上溢。
如果异常返回EXCEPTION_EXECUTE_HANDLER,那么在执行长跳转后执行代码时,此时上面的SEH框架所代表的那个节点已经从节点摘除了(在不存在形式SEH框架的情况下),如果在长跳转后的代码中出现异常,那么异常会由上一层SEH节点捕获到。
标签:返回,EXCEPTION,RaiseException,RtlRaiseException,ntdll,关于,异常 From: https://www.cnblogs.com/ps12345678/p/17010834.html