我在对特定的 Delphi Pascal .exe 进行逆向工程时遇到了麻烦(旧的 vsn.,1995 年之前,所以可能是 v.3)。从系统调用中我知道这可能是一个try..except..finally
块,但我无法通过代码找到“正常”路由,except
以及(可能)finally
块是什么。
程序集如下所示:
782CFC 33 C0 xor eax, eax
782CFE 55 push ebp
782CFF 68 (782E37) push _FINALLY_A_0_782E37
782D04 64 FF 30 push dword ptr fs:[eax]
782D07 64 89 20 mov dword ptr fs:[eax], esp
_try_0_782D0A:
782D0A 8B D3 mov edx, ebx
782D0C 8B C6 mov eax, esi
782D0E E8 D1 F3 FF FF call ...unrelated...
782D13 8D 56 1C lea edx, [esi+1Ch]
.. lots of regular code here ..
.. ending with ..
782E17 8B 18 mov ebx, dword ptr [eax]
782E19 FF 53 20 call dword ptr [ebx+20h]
finally_1_782E1C:
782E1C 33 C0 xor eax, eax
782E1E 5A pop edx
782E1F 59 pop ecx
782E20 59 pop ecx
782E21 64 89 10 mov dword ptr fs:[eax], edx
782E24 68 (782E3E) push _end_1_782E3E
@block_L:
782E29 8D 45 F4 lea eax, [ebp + local_0C]
782E2C BA 02 00 00 00 mov edx, 2
782E31 E8 12 E3 F7 FF call System.@LStrArrayClr
782E36 C3 retn
_FINALLY_A_0_782E37:
782E37 E9 B4 E2 F7 FF jmp System.@HandleFinally
_FINALLY_B_0_782E3C:
782E3C EB EB jmp @block_L
; -------
_end_1_782E3E:
782E3E 5F pop edi
782E3F 5E pop esi
782E40 5B pop ebx
782E41 8B E5 mov esp, ebp
782E43 5D pop ebp
782E44 C3 retn
-- 这是我自己的反汇编器的输出,但我认为其中没有错误。标签已自动命名,但我仍然无法遵循从一个块到下一个块的“逻辑”(如果有)。特别是下半部分,就在函数结语之前,让我感到困惑。
这些片段是否足以重建原始的try
..finally
块?
阅读伊戈尔的回答后:是的。考虑这些流程图:左图,在特殊处理 try/finally 块之前的原始流程图,右图,之后。
在最初的流程图中,我把从一个基本块到另一个基本块的每一次跳转都看作一个链接,代码流在每个retn
. if
(E-(F)-K) 和if-else
(GH/IJ) 结构可以清楚地辨别。然而,推送返回地址和异常处理的其他“技巧”,打败了这一点,正如悬空块 N 和 O 所见——它们从无处“进入”——以及一个单独的块“M”,它来了不知从何而来。
在右边,我将异常块的初始化与主代码(添加一个新块 B)分开,并将finalize结构连接成一个新块(M),它最终跳转到一个 AFTER_TRY(这恰好是最后一个退出块)。现在很明显
- 在序言之后, a
try
被启动; - 所有代码都在
finally
块 M处结束,其中 - 那么代码总是存在于一个固定点。