一个脱 themida 强壳的特殊方法

前言

前段时间,干一个活的时候遇到了一个强壳 Themida,简称 TMD 壳。搜了一下资料

这个壳的特点就是会在关键代码处采用 vmp 保护,如 vmp 保护程序入口。

好在我遇到的这个壳没有对 oep 进行处理。所以还是比较好找到 oep的。

脱壳

脱壳过程中找 oep 是一个关键的的步骤,找 oep 有许多的方法,但是其实大都对 TMD 这种强壳没有什么帮助?(可能是我脱的壳比较少)。另外还有一种常见的方法,就是找关键 api 然后回溯,找到真正的入口,下硬件断点。

我遇到的这个程序是 msvcrt 编写的程序。

我们知道在 MSVC 中程序编译器会为全局和静态函数生成相应的初始化器,并把他们的地址放在一个表(table)中,这个表会在 _cinit() 初始化 CRT 的时候生成。在 PE 结构中,这个表通常在 .data 段的起始位置。
从 Entry Point 到 main 函数过程中,在完成了_setargv() 以及_setenvp() 之后,进入到_cinit 函数。
_cinit 函数很短,大致上分为三个步骤:

  1. _fpmath() 或者 (*_FPinit)();

  2. _initterm( xi_a, xi_z );

  3. _initterm( xc_a, xc_z );

第一步 是可选的,_FPinit 主要用来初始化浮点运算。只有当用户写的代码中出现了浮点运算,_FPinit 才会被定义。
第二步和第三步 是分别对C和C++程序做初始化。_initterm 接受两个指针作为参数,这两个指针中间的内存区域是一张函数指针表。_initterm 会从第一个指针开始,慢慢向后寻找,直到第二个指针结束,中间如果找到了一块内存表示一个函数指针,则执行该函数。

关键的地方就是在程序需会走到 msvcrt._initterm ,所以我们可以对这个位置下条件断点。

断点

首先找到自己要的关键模块,找到模块的区段地址。

然后下好 条件断点

1
2
bp msvcrt._initterm
bpcnd msvcrt._initterm, [esp]< 0xd2d000+0x1000

寻找 oep

执行,程序到达断点。

此时程序到达断点,发现此时程序来到了 esp 符合条件的位置。 而此时的 esp 存储的地址就是 oep 附近,我们只需来到 esp 存储地址附近,往上回溯即可。

题外

在用x64dbg 脱壳的过程中遇到了很强烈的反调试,然后我尝试用了ScyllaHide这个插件解决了。

另外感谢 pizza 对我的帮助。