寻找OEP的方法
通过分析OEP的特征码和API
原理
你要熟记各类程序OEP特征,通过这些特征去定位,比如说vs2017 编译的程序 OEP附近有kernelbase.GetSystemTimeAsFileTime,在这个api上打断点,然后不停运行,命中断点后看返回地址是否在.text节区即可,定位到了API,然后去对比特征验证该程序的编译器类型,最后根据特征找到OEP
这个方法其实有一点看运气,万一一个特征都对不上怎么办,其实也有一些技巧的,一般分析程序时,程序目录中还有其他一些dll,它们可能没加壳,用查壳工具搜一下,即可获取该程序的编译器类型,然后根据该编译器类型编译出来的程序OEP的入口特征搜索或在API打断点,即可定位到OEP
目标程序
下面我以一个实例来演示这个方法
我们这次实践使用这个SreamFab程序,它加了vmp壳,请看下图
这个也看不出来使用的什么编译器
分析编译器类型
我们可以看看其他没加壳的dll
我们查这个dll,因为看起来是开发自己写的程序,请看下图
由上图可知,MediaInfo.dll
是vs2019编译的,那么主程序就有可能也是vs2019编译的
分析编译特征
我自己用vs2019编译一个程序,然后分析它的入口点
选择Release版本,使用x64dbg查看入口点
然后离入口点最近的API是ucrtbase.dll的initterm_e
并且堆栈回溯第二个返回地址就是入口点,请看下图
使用API定位到OEP附近
定位到tls回调函数(因为tls有内存保护检查,所以不能断EP),请看下图
在initterm_e打断点,并删除tls断点(避免内存保护检查),请看下图
直接运行,命中断点
转到函数返回地址
再转到内存布局
的确返回地址是在主模块的.text节区,看到我们找对了
根据特征找到OEP
前面我们分析的时候发现,堆栈回溯第二个返回地址就是OEP附近,请看下图
我们跳转过去
基本上和我们自己使用vs2019写的例子是一致的,那么OEP的地址就是0x00000001423F48A0了
根据堆栈平衡定位OEP
原理
程序加壳有一个原则,程序跑到OEP时,栈地址必须要保持到EP时一致。
由此我们可以在EP处,在栈寄存器指向的地址 - 4 处打硬件写入断点,然后不停的运行,直到程序中断到.text节区中,即可定位到OEP附近
例子
https://wwmf.lanzout.com/i66kC27a0ekj
密码:2hq4
这是一个汇编写的程序,加了vmp壳,所以使用特征码来定位就不太行了
使用x32dbg打开目标程序,中断在EP处,很明显的vmp壳代码
在ESP - 4 处打上4字节的硬件写断点
不断运行,直到中断在.text节区
根据堆栈平衡的原理,很明显401000就是OEP