寻找OEP的方法

通过分析OEP的特征码和API

原理

你要熟记各类程序OEP特征,通过这些特征去定位,比如说vs2017 编译的程序 OEP附近有kernelbase.GetSystemTimeAsFileTime,在这个api上打断点,然后不停运行,命中断点后看返回地址是否在.text节区即可,定位到了API,然后去对比特征验证该程序的编译器类型,最后根据特征找到OEP

这个方法其实有一点看运气,万一一个特征都对不上怎么办,其实也有一些技巧的,一般分析程序时,程序目录中还有其他一些dll,它们可能没加壳,用查壳工具搜一下,即可获取该程序的编译器类型,然后根据该编译器类型编译出来的程序OEP的入口特征搜索或在API打断点,即可定位到OEP

目标程序

下面我以一个实例来演示这个方法
fc7e1b1840e306e6e767c2207e2d0e01
我们这次实践使用这个SreamFab程序,它加了vmp壳,请看下图
ec9d07503b64252c6af3bcd1d8cdd83e

这个也看不出来使用的什么编译器

分析编译器类型

我们可以看看其他没加壳的dll
351ff352301e4ac9f95bf471f6dfc0e9
我们查这个dll,因为看起来是开发自己写的程序,请看下图
bb4c9125c667201c8ea03d07fe88ae0e
由上图可知,MediaInfo.dll是vs2019编译的,那么主程序就有可能也是vs2019编译的

分析编译特征

我自己用vs2019编译一个程序,然后分析它的入口点
f84a9f3dea6be08ed0fdbd66fc27ddb8
选择Release版本,使用x64dbg查看入口点
5d8d849605a9f68cd70bd8d5abdc67f1
然后离入口点最近的API是ucrtbase.dll的initterm_e

并且堆栈回溯第二个返回地址就是入口点,请看下图
2c22a47f743a2eef47ccc27ab25e7b2e

使用API定位到OEP附近

定位到tls回调函数(因为tls有内存保护检查,所以不能断EP),请看下图
928ab5ed513d4ef659c3bb57ec9a8ede

在initterm_e打断点,并删除tls断点(避免内存保护检查),请看下图
b1e601b4a1ce3bade402231065e2f1fa

直接运行,命中断点
9842286040741f0bca6de2d5c6a2b6e6
转到函数返回地址
35af1ab3743ab9c8ac113afadcab1dd4
再转到内存布局
6f866760728b58ea86e297809c9bbc96
的确返回地址是在主模块的.text节区,看到我们找对了

根据特征找到OEP

前面我们分析的时候发现,堆栈回溯第二个返回地址就是OEP附近,请看下图
e9288b0e4a8b5c5a48f1dcaed072fba7
我们跳转过去
ddc33d169548f29d86c2fc937ae12c61
基本上和我们自己使用vs2019写的例子是一致的,那么OEP的地址就是0x00000001423F48A0了

根据堆栈平衡定位OEP

原理

程序加壳有一个原则,程序跑到OEP时,栈地址必须要保持到EP时一致。
由此我们可以在EP处,在栈寄存器指向的地址 - 4 处打硬件写入断点,然后不停的运行,直到程序中断到.text节区中,即可定位到OEP附近

例子

https://wwmf.lanzout.com/i66kC27a0ekj
密码:2hq4
这是一个汇编写的程序,加了vmp壳,所以使用特征码来定位就不太行了

使用x32dbg打开目标程序,中断在EP处,很明显的vmp壳代码
34d477d7de331f0880b710881e869787

在ESP - 4 处打上4字节的硬件写断点
ded8c7287190f8a31c43fa3b3ce7bf14dfd8f75ea2885bdd7fb813688d6a433e

不断运行,直到中断在.text节区
ff5be183089791f9d5d94c4ca0f12d4c

根据堆栈平衡的原理,很明显401000就是OEP

posted @ 2024-08-12 01:36  乘舟凉  阅读(80)  评论(0编辑  收藏  举报