第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
经过多次返回后,程序执行到