怀德维宁

大邦维屏,大宗维翰。怀德维宁,宗子维城。

0%

【翻译】windbg调试0xef异常(1)

停止码0xEF出现的可能原因如下:

(1)硬件故障,尤其是内存和磁盘;

(2)安全软件例如杀毒软件;

(3)windows自身原因;

第一个原因是以上三个原因中最普遍的原因,尤其是加载到内存中的程序因为一些未处理的异常而中止自身运行是最典型的情况。之后造成操作系统突然panic并抛出0xEF停止码。另一方面,如果安全软件不信任二进制运行文件并中止其运行。如果对应的程序是critical关键进程(例如scvhost.exe),这会造成灾难性的后果。但是第二种情况较少出现。

然而,在这篇文章中,我将会将注意力集中到第三个原因上,当启动了影子栈shadow stack功能,并且监测到影子栈与调用栈间存在差异,windows系统会中止运行进程,并进而导致0xEF停止码被抛出。这也是我把windows自身作为0xEF异常产生原因的理由,尽管这种情况也有可能是因为异常的驱动程序或内存引起的。

如果启用了基于硬件的栈保护,处理器会保持两份调用栈的拷贝,第二份拷贝就是知名的影子栈。该栈旨在控制线程的运行流,如果任一栈的返回地址存在异常,则一个特殊的硬件异常被抛出进而造成进程被windows中止。

CRITICAL_PROCESS_DIED (ef)

        A critical system process died

Arguments:

Arg1: ffffaf08b56a90c0, Process object or thread object

Arg2: 0000000000000000, If this is 0, a process died. If this is 1, a thread died.

Arg3: 0000000000000000

Arg4: 0000000000000000
3: kd> knL

# Child-SP          RetAddr               Call Site

00 ffff8c0a`14b3ed38 fffff801`0ed0d122     nt!KeBugCheckEx

01 ffff8c0a`14b3ed40 fffff801`0ec0c7a3     nt!PspCatchCriticalBreak+0x10e

02 ffff8c0a`14b3ede0 fffff801`0ea99290     nt!PspTerminateAllThreads+0x172917

03 ffff8c0a`14b3ee50 fffff801`0ea9908c     nt!PspTerminateProcess+0xe0

04 ffff8c0a`14b3ee90 fffff801`0e80f8f8     nt!NtTerminateProcess+0x9c << Terminate our svchost.exe process which then bugchecks the system

05 ffff8c0a`14b3ef00 fffff801`0e800ca0     nt!KiSystemServiceCopyEnd+0x28

06 ffff8c0a`14b3f098 fffff801`0e860d9d     nt!KiServiceLinkage

07 ffff8c0a`14b3f0a0 fffff801`0e8106a4     nt!KiDispatchException+0x17941d

08 ffff8c0a`14b3f8e0 fffff801`0e80e03c     nt!KiFastFailDispatch+0xe4

09 ffff8c0a`14b3fac0 00007ffc`f18833c6     nt!KiControlProtectionFault+0x2fc << Throws #CP (Control Protection) exception

0a 0000002f`4637f820 000001b1`ae000340     ntdll!RtlpGetActivationContextData+0x52

0b 0000002f`4637f828 000001b1`ae002480     0x000001b1`ae000340

0c 0000002f`4637f830 00000000`00000001     0x000001b1`ae002480

0d 0000002f`4637f838 000001b1`000000f0     0x1

0e 0000002f`4637f840 00000000`00000002     0x000001b1`000000f0

0f 0000002f`4637f848 00000050`00000000     0x2

10 0000002f`4637f850 00000000`00000002     0x00000050`00000000

11 0000002f`4637f858 00000000`000000f0     0x2

12 0000002f`4637f860 00000000`00000000     0xf0

如果检查传递给nt!KiDispatchException函数的第一个参数,就可以看到抛出的异常类型信息。

07 ffff8c0a14b3f0a0 fffff8010e8106a4 nt!KiDispatchException+17941d (perf)

    Parameter[0] = ffff8c0a14b3fa18

    Parameter[1] = 0000000000000000

    Parameter[2] = ffffffffffffff80

    Parameter[3] = 0000002f4637f820
3: kd> .exr ffff8c0a14b3fa18

ExceptionAddress: 00007ffcf18833c6 (ntdll!RtlpGetActivationContextData+0x0000000000000052)

ExceptionCode: c0000409 (Security check failure or stack buffer overrun)

ExceptionFlags: 00000001

NumberParameters: 1

Parameter[0]: 0000000000000039

Subcode: 0x39 FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS Shadow stack violation

进一步检查异常,当启用了cet(Control-flow Enforcement Technology,控制流执行技术)时,运行调用指令,两个返回地址被压入栈:一个进入了调用栈,另一个进入影子栈。之后当返回指令运行时,会检查并比较两个返回地址,如果两个地址不匹配,则cp异常就会像之前提到的那样被抛出。但是cet仅在使用call调用指令时起作用,当使用压栈指令将地址压栈时,cet不起作用,因此影子栈中也不存在返回地址。考虑到这一点,推荐使用cfg保护的jmp跳转指令。cfg的行为与cet类似,如果发现了异常,则中止违规进程。如果进程是critical关键进程,抛出0xEF停止码。

参考链接:

1.https://techcommunity.microsoft.com/t5/windows-os-platform-blog/developer-guidance-for-hardware-enforced-stack-protection/ba-p/2163340;

2.https://learn.microsoft.com/en-us/windows/win32/secbp/control-flow-guard;

原文链接:https://bsodtutorials.wordpress.com/2023/12/09/debugging-stop-0xef-critical_process_died/