第8章:Windows 下的异常处理——WinDbg 总结性调试

ntdll!RtlInitializeExceptionChain

在当前的 Win 10 最新版ntdll_RtlUserThreadStart 

    ntdll!RtlInitializeExceptionChain:
77588950 8bff           mov     edi, edi
77588952 55             push    ebp
77588953 8bec           mov     ebp, esp  // 下面的 ECV 猜测是 Exception Chain Validation
77588955 833dbcb8637701 cmp     dword ptr [ntdll!RtlpProcessECVPolicy (7763b8bc)], 1  
7758895c 7428           je      ntdll!RtlInitializeExceptionChain+0x36 (77588986)
7758895e 648b0d18000000 mov     ecx, dword ptr fs:[18h]  // 获得 TEB 地址 
77588965 8b5508         mov     edx, dword ptr [ebp+8]   // 栈地址
77588968 a1d0c66377     mov     eax, dword ptr [ntdll!RtlpFinalExceptionHandler (7763c6d0)]
7758896d 830aff         or      dword ptr [edx], 0FFFFFFFFh // Next 置 -1
77588970 894204         mov     dword ptr [edx+4], eax    // FinalHandler 
77588973 8339ff         cmp     dword ptr [ecx], 0FFFFFFFFh
77588976 750e           jne     ntdll!RtlInitializeExceptionChain+0x36 (77588986)
77588978 b800020000     mov     eax, 200h
7758897d 8911           mov     dword ptr [ecx], edx     // 安装好的 SEH 写入 FS:[0]
7758897f 660981ca0f0000 or      word ptr [ecx+0FCAh], ax   // 将 Teb->SameTebFlags 增加一个属性值 LoaderWorker
77588986 5d             pop     ebp               // SameTebFlags(4字节) 指示该线程有哪些属性
77588987 c20400         ret     4

在 Win 10 下的 UEF 函数

过滤函数下断点,下面 cmp CookieValue,esi 的跳转会实现

经过一小段跳转后来到,只要将 eax 返回值置为0,即没有调试端口,程序最终将执行 NtTerminateProcess 

若不置0,继续执行,则程序回到外层 UEF 的第一层

然后会返回到

最终会回到异常分发函数  ntdll!RtlDispatchException ,异常处理函数最后找到 UEF ,DebugPort 存在,则返回 Exception_Continue_Search ,循环这个过程

ntdll!RtlDispatchException 

使用的为书上提供的程序—— NoSEH.exe 

首先对经历对局部变量的分配后,检查 Exception_Code 是否为 C0000006

检测发生异常的地址是否为在执行 ValidateUserCallTarget 时出现的内存访问异常,若不是则继续执行

对 PEB.NtGlobalFlag 进行检验,不允许记录异常则不跳转并继续执行

可以记录异常则会调用记录函数并返回继续执行

该程序在编译时是否选择了 CFG ,若函数返回 0,则没有,返回1则有,并会跳转

CFG Enble 则会对栈进行检测,栈合格则返回继续执行,不合格则会 ret 29 ,退出 Dispatch 函数

接下来将会执行书上出现的 CallVectoredHandlers 函数

获取栈的内存范围,存储在传入的两个参数地址(局部变量指针)中

执行 NtQueryInformationProcess,后首先对函数本身的返回值进行校验,然后检测返回值是否为 ExecuteOptionFlags 中的MEM_EXECUTE_OPTION_DISABLE_EXCEPTIONCHAIN_VALIDATION(0x40),若为40 则跳过下面 RtlIsValidExceptionHandler 函数的执行

若函数执行失败,将 Buffer 里的值置 0 ,返回继续执行

// ExecuteOptionFlags on Win7,参数为 PrcessExecuteFlags(0x22) 时,
// Buffer存储的值的含义,全是与 DEP 相关
#define MEM_EXECUTE_OPTION_DISABLE 0x1   // 开启 DEP #define MEM_EXECUTE_OPTION_ENABLE 0x2 //关闭 DEP #define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4 #define MEM_EXECUTE_OPTION_PERMANENT 0x8     //设置后进程的 DEP 设置不能被修改 #define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE 0x10 //是否允许代码在不可执行页上执行 #define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE 0x20 //是否允许在加载模块内存空间外执行 #define MEM_EXECUTE_OPTION_DISABLE_EXCEPTIONCHAIN_VALIDATION 0x40 //是否禁用了 SEHOP #define MEM_EXECUTE_OPTION_VALID_FLAGS 0x7f         

校验该进程是否开启了 SEHOP,若开启,则跳过下面函数的执行,若没有开启则会对 ExceptionChain 进行合格性检验

接下来进入循环执行 Handler 阶段:首先对栈进行检验(地址对齐、地址范围检验等)

RtlIsValidHandler 是操作系统层面对异常回调函数的验证(SafeSEH),正常返回后检测程序是否记录异常信息

若没有通过验证则会跳转到,将 ExceptionFlags 置为 8,然后执行 VEH 函数并退出

//Exception Flags
#define EXCEPTION_NONCONTINUABLE 0x1    // Noncontinuable exception
#define EXCEPTION_UNWINDING 0x2         // Unwind is in progress
#define EXCEPTION_EXIT_UNWIND 0x4       // Exit unwind is in progress
#define EXCEPTION_STACK_INVALID 0x8     // Stack out of limits or unaligned
#define EXCEPTION_NESTED_CALL 0x10      // Nested exception handler call
#define EXCEPTION_TARGET_UNWIND 0x20    // Target unwind in progress
#define EXCEPTION_COLLIDED_UNWIND 0x40  // Collided exception handler call

RtlIsValidHandler 执行完后即执行异常处理函数

对 ecx 的检验没有看明白,在程序的执行过程中 [esp+28] 始终是 0

异常处理程序返回1,表示程序并未对异常进行处理,随后取得 Next 指针中的值(一个存储着下一个Next的值)

再次跳转,继续对值进行检测后,继续执行 Handler 。最后会退出

 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

需要注意的是,执行完 UEF 的返回值是 0(eax),紧接着各种 ret ,回到分析 UEF 出现的图片

退出到 ntdll!_except_handler4_common 代码段内,因为有调试器,因此 FilterFunc 会返回 Continue_Search

经过多次返回后,程序执行到

原文地址:https://www.cnblogs.com/Rev-omi/p/13961988.html