__except() 的处理1 --- 计算 Filter 表达式
现在我们来关注 __except() 块
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return FALSE; } |
__except() 括号里的是 Exception Filter 表达式,表达式的计算结果有 3 个值:
- EXCEPTION_EXECUTE_HANDLER = 1
- EXCEPTION_CONTINUE_SEARCH = 0
- EXCEPTION_CONTINUE_EXECUTION = -1
上一篇文章中提过:__except() 括号里的表达式计算代码就是一个 FilterFunc() 它被 MSVCR100D!_EH4_CallFilterFunc() 调用,当执行当这段 FilterFunc() 代码执行完毕后返回到 _EH4_CallFilterFunc(),返回值就上面所列的三个结果之一。
这段 FilterFunc() 如下:
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 01223444 8B 45 EC mov eax,dword ptr [ebp-14h] 01223447 8B 08 mov ecx,dword ptr [eax] 01223449 8B 11 mov edx,dword ptr [ecx] 0122344B 89 95 20 FF FF FF mov dword ptr [ebp-0E0h],edx 01223451 8B 85 20 FF FF FF mov eax,dword ptr [ebp-0E0h] 01223457 33 C9 xor ecx,ecx 01223459 3D 94 00 00 C0 cmp eax,0C0000094h 0122345E 0F 94 C1 sete cl 01223461 8B C1 mov eax,ecx $LN7: 01223463 C3 ret |
这段代码通过先获得 EXCEPTION_POINTERS 结构的指针,再获到 ExceptionRecord 指针,最后获得 ExceptionCode。将 ExceptionCode 与 0xC0000094 作比较,这个 0xC0000094 值就是 EXCEPTION_INT_DIVIDE_BY_ZERO 异常码。
- 当为 0xC0000094 值时就返回 1,也就是 EXCEPTION_EXECUTE_HANDLER
- 否则返回 0,也就是 EXCEPTION_CONTINUE_SEARCH
这个返回值就是返回给 MSVCR100()!_except_handler4_common() 进行后续处理:
011524f7 e806b4ffff call MSVCR100D!_EH4_CallFilterFunc (0114d902) 011524fc 8945f0 mov dword ptr [ebp-10h],eax 011524ff c645df01 mov byte ptr [ebp-21h],1 01152503 837df000 cmp dword ptr [ebp-10h],0 01152507 7d11 jge MSVCR100D!_except_handler4_common+0xda (0115251a) |
_exception_handler4_common() 测试返回值(也就是 Filter 表达式结果)是否为 EXCEPTION_CONTINUE_EXECUTION(即值为:-1)
[ebp-21h] 这里是一个标志位,置 1 时表示要进行 ValidateLocalCookies() 测试。
然后接着测试是 EXCEPTION_EXCEUTE_HANDLER(值为 1)还是 EXCEPTION_CONTINUE_SEARCH(值为 0):
MSVCR100D!_except_handler4_common+0xda: 0115251a 837df000 cmp dword ptr [ebp-10h],0 0115251e 0f8e8e000000 jle MSVCR100D!_except_handler4_common+0x172 (011525b2) |
如果是 EXCEPTION_CONTINUE_SEARCH 就转到 MSVCR100D!_except_handler4_common+0x172
1. EXCEPTION_EXECUTE_HANDLER 处理
如果是 EXCEPTION_EXECUTE_HANDLER 则:
MSVCR100D!_except_handler4_common+0xe4: 01152524 8b4510 mov eax,dword ptr [ebp+10h] 01152527 813863736de0 cmp dword ptr [eax],0E06D7363h 0115252d 7529 jne MSVCR100D!_except_handler4_common+0x118 (01152558) |
比较 ExceptionCode 是否为 0xE06D7363,最终转到 MSVCR100D!_except_handler4_common+0x118:
MSVCR100D!_except_handler4_common+0x118: 01152558 8b4de0 mov ecx,dword ptr [ebp-20h] ; esp 0115255b 83c108 add ecx,8 ; get prev_struct 0115255e 8b5510 mov edx,dword ptr [ebp+10h] ; ExceptionRecord 01152561 e8ccb3ffff call MSVCR100D!_EH4_GlobalUnwind2 (0114d932) 01152566 8b55e0 mov edx,dword ptr [ebp-20h] ; RegistrationNode 01152569 8b4214 mov eax,dword ptr [edx+14h] ; get TryLevel 0115256c 3b45d8 cmp eax,dword ptr [ebp-28h] ; TryLevel == eax 0115256f 7416 je MSVCR100D!_except_handler4_common+0x147 (01152587) |
这里将执行全局展开操作 MSVCR100D!_EH4_GlobalUnwind2(),给这个函数传道了两个参数:
- 前一个 EXCEPTION_REGISTRATION_RECORD 结构指针
- EXCEPTION_RECORD 的指针,这个指针是传给 except_handler4_common() 的参数
这里可以看到,当 Filter 值为 EXCEPTION_EXECUTE_HANDLER 时将会执行一个被称作“全局展开”的操作。
2. EXCEPTION_CONTINUE_EXECUTION 处理
如果值为 EXCEPTION_CONTINUE_EXECUTION 时:
MSVCR100D!_except_handler4_common+0xc9: 01152509 c745f400000000 mov dword ptr [ebp-0Ch],0 01152510 e9a2000000 jmp MSVCR100D!_except_handler4_common+0x177 (011525b7) |
先放下对 [ebp-0Ch] 认识,转到 MSVCR100D!_except_handler4_common+0x177 执行:
MSVCR100D!_except_handler4_common+0x177: 011525b7 eb25 jmp MSVCR100D!_except_handler4_common+0x19e (011525de) |
最后来到:
MSVCR100D!_except_handler4_common+0x19e: 011525de 0fb64ddf movzx ecx,byte ptr [ebp-21h] 011525e2 85c9 test ecx,ecx 011525e4 7414 je MSVCR100D!_except_handler4_common+0x1ba (011525fa) MSVCR100D!_except_handler4_common+0x1a6: 011525e6 8b55e8 mov edx,dword ptr [ebp-18h] 011525e9 52 push edx 011525ea 8b45d4 mov eax,dword ptr [ebp-2Ch] 011525ed 50 push eax 011525ee 8b4d0c mov ecx,dword ptr [ebp+0Ch] 011525f1 51 push ecx 011525f2 e819000000 call MSVCR100D!ValidateLocalCookies (01152610) 011525f7 83c40c add esp,0Ch MSVCR100D!_except_handler4_common+0x1ba: 011525fa 8b45f4 mov eax,dword ptr [ebp-0Ch] 011525fd 8be5 mov esp,ebp 011525ff 5d pop ebp 01152600 c3 ret |
标志位 [ebp-21h] 在 MSVCR100D!_EH4_CallFilterFunc() 返回后置为 1 因此这里需要进行 VialidateLocalCookies() 的测试
最后返回 [ebp-0Ch] 的值。
3. EXCEPTION_CONTINUE_SEARCH 处理
最后来看看 Filter 值为 EXCEPTION_CONTINUE_SEARCH 时的处理:
MSVCR100D!_except_handler4_common+0xda: 0115251a 837df000 cmp dword ptr [ebp-10h],0 0115251e 0f8e8e000000 jle MSVCR100D!_except_handler4_common+0x172 (011525b2) ... MSVCR100D!_except_handler4_common+0x172: 011525b2 e9fffeffff jmp MSVCR100D!_except_handler4_common+0x76 (011524b6) |
代码来到 MSVCR100D!_except_handler4_common+0x76 处:
MSVCR100D!_except_handler4_common+0x76: 011524b6 8b4dec mov ecx,dword ptr [ebp-14h] ; ScopeRecord.EnclosingLevel 011524b9 894dd8 mov dword ptr [ebp-28h],ecx ; MSVCR100D!_except_handler4_common+0x7c: 011524bc 837dd8fe cmp dword ptr [ebp-28h],0FFFFFFFEh 011524c0 0f84f1000000 je MSVCR100D!_except_handler4_common+0x177 (011525b7) MSVCR100D!_except_handler4_common+0x86: 011524c6 8b55d8 mov edx,dword ptr [ebp-28h] 011524c9 6bd20c imul edx,edx,0Ch 011524cc 8b45d4 mov eax,dword ptr [ebp-2Ch] ; ScopeTable 011524cf 8d4c1010 lea ecx,[eax+edx+10h] ; ScopeRecord 011524d3 894de4 mov dword ptr [ebp-1Ch],ecx 011524d6 8b55e4 mov edx,dword ptr [ebp-1Ch] 011524d9 8b4204 mov eax,dword ptr [edx+4] ; get FilterFunc 011524dc 8945d0 mov dword ptr [ebp-30h],eax 011524df 8b4de4 mov ecx,dword ptr [ebp-1Ch] 011524e2 8b11 mov edx,dword ptr [ecx] ; EnclosingLevel 011524e4 8955ec mov dword ptr [ebp-14h],edx ; EnclosingLevel 011524e7 837dd000 cmp dword ptr [ebp-30h],0 ; FilterFunc == NULL ? 011524eb 0f84c1000000 je MSVCR100D!_except_handler4_common+0x172 (011525b2) MSVCR100D!_except_handler4_common+0xb1: 011524f1 8b55e8 mov edx,dword ptr [ebp-18h] 011524f4 8b4dd0 mov ecx,dword ptr [ebp-30h] 011524f7 e806b4ffff call MSVCR100D!_EH4_CallFilterFunc (0114d902) 011524fc 8945f0 mov dword ptr [ebp-10h],eax 011524ff c645df01 mov byte ptr [ebp-21h],1 01152503 837df000 cmp dword ptr [ebp-10h],0 01152507 7d11 jge MSVCR100D!_except_handler4_common+0xda (0115251a) |
这个 [ebp-14h] 是局部 _EH4_SCOPETABLE_RECORD 结构变量 ScopeRecord,而 [ebp-28h] 是局部变量 TryLevel
3.1 提取 EnclosingLevel 值
MSVCR100D!_except_handler4_common+0x76: 011524b6 8b4dec mov ecx,dword ptr [ebp-14h] ; ScopeRecord.EnclosingLevel 011524b9 894dd8 mov dword ptr [ebp-28h],ecx ; |
_EH4_SCOPETABLE_RECORD 结构用 C 描述如下:
typedef struct _EH4_SCOPETABLE_RECORD { ULONG EnclosingLevel; LONG (*FilterFunc)(); union { void (*HandlerAddress)(); void (*FinallyFunc)(); } u; } EH4_SCOPETABLE_RECORD; |
EnclosingLevel 实际上是上一层的 TryLevel 值,关于 TryLevel 请看上一篇文章
3.2 测试 EnclosingLevel 值
MSVCR100D!_except_handler4_common+0x7c: 011524bc 837dd8fe cmp dword ptr [ebp-28h],0FFFFFFFEh 011524c0 0f84f1000000 je MSVCR100D!_except_handler4_common+0x177 (011525b7) |
将 TryLevel 设为 EnclosingLevel 值,如果 EnclosingLevel 为 0xFFFFFFFE 则说明它已经是最外层 __try{} 结构了,这样的话就退出
3.3 提取 FilterFunc 函数并执行
接下来的步骤和上一篇文章所述的一样。找到 FilterFunc() 函数交由 MSVCR100D!_EH4_CallFilterFunc() 执行。
但是这里的 FilterFunc() 已经上一层的 __try{} 结构中的 FilterFunc() 函数
3.4 再判断 Filter 值
这重复判断 Filter 值的工作,可见 EXCEPTION_CONTINUE_SEARCH 的处理是从里往外遍历执行每一层的 FilterFunc 直至最外层(EnclosingLevel 为 0xFFFFFFFE)就停止
于是,我们对 EH4 stack 又有了新的认识:
以 2-level 的 __try{} 结构为例,在 1-level 的 ScopeRcord 结构中的 EnclosingLevel 将指向 0-level,它的值就是 0,而最外层的 EnclosingLevel 值就是 0xFFFFFFFE
如下面代码所示,图中的 Handler() 就是:
__except(Filter()) { // Handler() } |
红色粗体部分,当 Filter() 返回的值是 EXCEPTION_EXECUTE_HANDLER 时表示需要进行处理,那么 Handler() 将被执行。
Handler() 是怎样被执行的,后续文章将为您揭晓 :)
上一页 目录 下一页
版权 mik 所有,转载请注明出处