__except() 的处理1 --- 计算 Filter 表达式

__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 所有,转载请注明出处

 

当遇到 `lambda x: datetime.strptime(x, ...)` 报错时,这通常是由于尝试将非日期字符串转换成 `datetime` 对象时出现了问题。`strptime` 函数用于解析字符串并将其转换为 `datetime` 格式,但这个函数需要两个参数:待转换的字符串(`x`)以及指定的格式字符串(如 `%Y-%m-%d`)。以下是可能导致错误的一些原因及解决办法: 1. **格式字符串不匹配**: 检查传给 `strptime` 函数的第一个参数 (`x`) 是否按照正确的日期格式编写。例如,如果日期是 "2023-04-01",你需要的格式应该是 `%Y-%m-%d` 而不是 `%d/%m/%Y`。 2. **空值或无效字符串**: 如果 `x` 是 `None` 或空字符串,那么会抛出异常。你需要确保提供的字符串内容有效。 3. **编码问题**: 如果 `x` 来自文本文件或其他源,可能有字符编码的问题。确保字符串已经被正确地解码。 4. **Python版本兼容性**: 如果使用的 Python 版本过低,可能会缺乏某些现代功能,如 `datetime` 类的 `strptime`。检查是否更新到最新版。 5. **lambda表达式错误**:确认 `lambda` 表达式本身是否有语法错误,如括号是否配对,参数列表是否完整。 修复这类问题的一种常见做法是在 `try-except` 语句中处理可能出现的异常,例如: ```python from datetime import datetime month_filter = lambda x: None if x is None else datetime.strptime(x, '%Y-%m-%d') ``` 这将忽略空值,并尝试把其他有效的字符串转换成日期。如果发生错误,程序不会崩溃,而是返回 `None`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值