前段时间,干一个活的时候遇到了一个强壳 Themida,简称 TMD 壳。搜了一下资料
这个壳的特点就是会在关键代码处采用 vmp 保护,如 vmp 保护程序入口。
好在我遇到的这个壳没有对 oep 进行处理。所以还是比较好找到 oep的。
脱壳过程中找 oep 是一个关键的的步骤,找 oep 有许多的方法,但是其实大都对 TMD 这种强壳没有什么帮助?(可能是我脱的壳比较少)。另外还有一种常见的方法,就是找关键 api 然后回溯,找到真正的入口,下硬件断点。
我遇到的这个程序是 msvcrt 编写的程序。
我们知道在 MSVC 中程序编译器会为全局和静态函数生成相应的初始化器,并把他们的地址放在一个表(table)中,这个表会在 _cinit() 初始化 CRT 的时候生成。在 PE 结构中,这个表通常在 .data 段的起始位置。
从 Entry Point 到 main 函数过程中,在完成了_setargv() 以及_setenvp() 之后,进入到_cinit 函数。
_cinit 函数很短,大致上分为三个步骤:
_fpmath() 或者 (*_FPinit)();
_initterm( __xi_a, __xi_z );
_initterm( __xc_a, __xc_z );
第一步 是可选的,_FPinit 主要用来初始化浮点运算。只有当用户写的代码中出现了浮点运算,_FPinit 才会被定义。
第二步和第三步 是分别对C和C++程序做初始化。_initterm 接受两个指针作为参数,这两个指针中间的内存区域是一张函数指针表。_initterm 会从第一个指针开始,慢慢向后寻找,直到第二个指针结束,中间如果找到了一块内存表示一个函数指针,则执行该函数。
关键的地方就是在程序需会走到 msvcrt._initterm
,所以我们可以对这个位置下条件断点。
断点
然后下好 条件断点
1 | bp msvcrt._initterm |
寻找 oep
此时程序到达断点,发现此时程序来到了 esp 符合条件的位置。 而此时的 esp 存储的地址就是 oep 附近,我们只需来到 esp 存maty储地址附近,往上回溯即可。
在用x64dbg 脱壳的过程中遇到了很强烈的反调试,然后我尝试用了ScyllaHide这个插件解决了。
另外感谢 pizza 对我的帮助。