
1) 【一句话结论】Windows结构化异常处理(SEH)通过异常处理链表捕获程序异常,攻击者可利用缓冲区溢出覆盖异常处理函数指针,跳转执行恶意代码;常见防御措施包括数据执行保护(DEP)、地址空间布局随机化(ASLR)等。
2) 【原理/概念讲解】SEH是Windows内核提供的异常处理机制,用于捕获程序运行时发生的异常(如访问违规、除零错误等)。每个线程有一个异常处理链表,由一系列异常处理记录(EXCEPTION_REGISTRATION_RECORD)组成,每个记录包含一个异常处理函数指针和一个指向下一个记录的指针。当异常发生时,系统会按链表顺序调用每个异常处理函数,直到找到能处理该异常的处理程序或链表结束。类比:异常处理链表像一串“异常处理锁链”,每个节点是“锁链环”,异常发生时系统按顺序检查每个环是否能“锁住”异常,若能则执行对应函数,否则继续检查下一个环。
3) 【对比与适用场景】
| 对比项 | Windows SEH | C++ try-catch | 系统级异常处理(如内核) |
|---|---|---|---|
| 定义 | Windows系统级异常处理机制,用于捕获用户态程序异常 | C++语言级异常处理,用于捕获程序逻辑异常 | 内核中处理硬件异常或系统错误 |
| 特性 | 链表结构,用户态和内核态均支持,异常处理函数可执行任意代码 | 语言级,仅用户态,异常处理函数需符合语言规范 | 处理硬件中断、系统调用错误等 |
| 使用场景 | 捕获程序运行时异常(如缓冲区溢出、访问违规) | 处理程序逻辑错误(如数组越界、除零) | 处理系统级错误(如内存不足、硬件故障) |
| 注意点 | 异常处理函数指针可被覆盖,存在漏洞利用风险 | 异常处理函数需正确处理,否则可能导致崩溃 | 内核SEH更复杂,涉及系统稳定性 |
4) 【示例】
伪代码展示缓冲区溢出覆盖SEH指针:
void vulnerable_function() {
char buffer[8];
// 溢出点
strcpy(buffer, "A" * 12); // 假设输入长度为12,缓冲区大小8,导致溢出
// 溢出后,覆盖异常处理函数指针(位于栈上,紧邻缓冲区)
// 假设异常处理函数指针地址为0x7ffdfc0,恶意代码地址为0x7ffdfc4
*(DWORD*)0x7ffdfc0 = 0x7ffdfc4;
}
void malicious_code() {
// 恶意代码,如执行系统命令
system("calc.exe");
}
解释:函数调用时,输入数据溢出缓冲区,覆盖了异常处理函数指针,使其指向恶意代码地址,当发生异常(如访问违规)时,系统调用恶意代码。
5) 【面试口播版答案】(约90秒)
“面试官您好,关于Windows SEH的工作原理,核心是系统通过异常处理链表捕获程序异常。每个线程有一个链表,由EXCEPTION_REGISTRATION_RECORD结构组成,每个记录包含异常处理函数指针和下一个记录的指针。当异常发生时,系统按链表顺序调用处理函数,直到找到匹配的处理程序。漏洞利用方面,缓冲区溢出可覆盖异常处理函数指针,跳转执行恶意代码。比如,函数中缓冲区溢出后,将异常处理函数指针改写为恶意代码地址,异常发生时执行恶意代码。防御措施包括数据执行保护(DEP)防止代码执行,地址空间布局随机化(ASLR)随机化异常处理函数地址,以及堆栈保护(如/GS编译选项)防止溢出覆盖SEH指针。总结来说,SEH是异常处理机制,攻击者可利用溢出覆盖其指针实现代码执行,而DEP、ASLR等是常见防御手段。”
6) 【追问清单】
EXCEPTION_ACCESS_VIOLATION)匹配异常处理函数,不同异常类型对应不同的处理逻辑,处理函数需检查异常码并决定是否处理。EIP、ESP等),异常处理函数执行时使用这些上下文,处理完异常后恢复寄存器并继续执行。7) 【常见坑/雷区】