windows内核研究(异常-未处理异常)
摘要 本文探讨了Windows异常处理机制中未处理异常的情况。研究发现,即使程序没有显式设置异常处理函数,编译器也会在main函数执行前自动创建SEH异常处理链。通过反汇编分析,确认了ntdll.dll会在FS:[0]位置挂载异常链表节点。测试表明,当程序未被调试时,SetUnhandledExceptionFilter注册的回调函数可以处理异常;但在调试状态下,该回调不会执行,导致程序终止。文章
·
异常
未处理异常
在之前学习windows异常处理机制时,windows通过VEH和SEH来处理0环和3环的异常,但如果一个程序没有异常抛出或者,没有处理异常的函数那会怎么样呢?
测试代码
#include<iostream>
int main() {
int i = 5;
return 0;
}
查看反汇编代码

我们可以看下调用堆栈,可以发现我们的main函数并不是一开始就执行的,而是由其他函数来调用的
ntdll.dll!7797d2fb() // 定位到这个位置的调用
看下这里面的第一个CALl做了什么

可以很明显的看到有修改堆栈中FS:[0]位置的代码(挂异常练链表)

看到这里就明白了,即使我们不去创建异常处理函数,在调用时编译器也会为我们创建一个
同理:在主函数中会为我们创建一个SEH,在线程当中也会为我们创建一个SEH,所以无论是进程也好,线程也好,都会有一个默认的SEH
只有程序被调试时,才会存在未处理异常
UnhandledExceptionFilter的执行流程:
- 通过NtQueryInformationProcess查询当前进程是否正在被调试,如果是,返回EXCEPTION_CONTINUE_SEARCH,此时会进入第二轮分发
- 如果没有被调式:
- 查询是否通过SetUnhandledExceptionFilter注册处理函数,如果有就调用
- 如果没有通过SetUnhandledExceptionFilter注册处理函数,弹出窗口让用户选择终止程序还是启动即时调试器
- 如果用户没有启用即时调试器,那么该函数返回EXCEPTION_EXCUTE_HANDLER
代码测试
#include<iostream>
#include<windows.h>
LONG __stdcall callBack(EXCEPTION_POINTERS* pExp) {
pExp->ContextRecord->Ecx = 1;
return EXCEPTION_CONTINUE_EXECUTION; // 从出错的地方继续执行
}
int main() {
SetUnhandledExceptionFilter(callBack);
_asm {
xor edx,edx
xor ecx,ecx
mov eax,0x10
idiv ecx // 除0异常
}
printf("程序正常执行\n");
system("pause");
return 0;
}
直接运行exe程序

在Visual Studio调试模式下启动

- 当程序没有处于调式状态下时,我们SetUnhandledExceptionFilter注册的函数就有机会执行并修改Ecx的值,程序正常执行
- 当程序处于调式状态下时,SetUnhandledExceptionFilter注册的函数将不会执行,程序发生错误终止进程
KiUserExceptionDispatcher函数分析
- 调用RtlDispatchException查找并执行异常处理函数
- 如果RtlDispatchException返回真,调用ZwContinue再次进入0环,但线程再次返回3环时,会从修正后的位置开始执行
- 如果RtlDispatchException返回假,调用ZwRaiseException进行第二轮异常分发
更多推荐


所有评论(0)