脱壳实践之寻找OEP——两次内存断点法
0x00 前言
对于加壳程序第一件事就是要找到OEP(oringinal Entry point),由于加壳的缘故,当PE文件载入OD或者其他调试软件时进入的的往往是壳程序的入口地址。所以要进行逆向分析第一步就必须找到PE程序的原始入口点。
0x01 壳的加载过程
壳和病毒在某些方面比较类似,都需要比原程序更早获得控制权。壳修改了原程序的的执行文件的组织结构,从而比原程序更早获得控制权,并且并不会影响原程序的正常运行。了解的壳的加载过程对于脱壳加壳异常重要。壳的加载过程如下:
1)保存入口参数
加壳程序初始化时保存各个寄存器的值,外壳执行完毕,再恢复各个寄存器内容,最后再跳到源程序的入口处执行。通常,用pushad/popad,pushfd/popfd指令来保存的和恢复现场环境。
2)获取壳自己所需的API函数
一般的壳输入表只有GetProAddress,GetMoudleHanle,LoadLibrary这几个API函数,甚至只有Kernel32.DLL以及GetProAddress。如果需要其他的API函数,可以通过LoadLibraryA(W)或者LoadLibraryExa(W)将DLL文件映像映射到调用进程的地址空间,函数返回的HINSTANCE值用于标识文件映像到虚拟内存地址。
LoadLibrary函数的原型如下:
HINSTANCE LoadLibrary{
LPCTSTR lpLibFileName //DLL文件名地址
}
返回值:成功时返回模块句柄,失败返回NULL。
当DLL文件已经被映射到调用进程的地址空间里,可以调用GetModuleHanleA(W)函数获得DLL模块的句柄,函数的地址原型如下:
HMODULE GetModuleHandle{
LPCTSTR lpModuleName //DLL文件地址
}
一旦模块被加载,线程就可以调用GetProcAddress函数获取输入函数地址。函数的原型如下:
FARPROC GetProcAddress{
HMODULE hModlue //DLL模块句柄
LPCSTR lpProName //函数名
}
这三个函数异常重要,对于程序加壳帮助很大。后面几篇将会详细介绍用法,这里暂且罗列出来。
3)解密原程序的各个区块的数据
壳出于保护原程序代码和数据的目的,一般都会加密原程序文件的各个区块,在程序时外壳将会对这些数据解密,以让程序能够正常运行。壳一般都是按区块加密的,那么在解密时也是按区块解密的,并且把解密的区块数据按照区块的定义放在合适的内存位置。
4)ITA的初始化
ITA填写,本来应该由PE加载器实现。但是由于加壳时,自己构造了一个输入表,并且让PE文件头输入表指针指向了自建的输入表。所以PE装载器就对自建的输入表进行填写。那么原来PE输入表只能由外壳程序来填写了。外壳所要做的就是将这个新输入表结构从头到尾扫描一遍,对每一个DLL引入的所有函数重新获取地址,并填写在ITA表中。
5)重定位处理
文件执行时将被映像到指定的内存地址中,这个初始地址称为基址。对于EXE文件,windows系统会尽量使用EXE问价所指定的内存地址,比如某EXE问价的基址为40000h,而运行时Windows系统提供给程序使用的基地址也是40000h。这种情况就不需要重定位了。对于DLL文件,windows没办法每一次提供DLL运行时提供相同的基址。对于这种情况,重定位是必须的。此时壳程序也需要提供PE文件的重定位功能。所以加壳DLL文件比加壳EXE文件多一个重定位表。
6)HOOK-API
程序文件中输入表的作用是让windows系统在程序运行时提供API的实际地址给程序使用。在程序的第一行代码执行前,windows系统就完成了这项工作。
壳程序一般都修改了原程序的输入表,然后自己模仿windows系统的工作来填充输入表的中相关数据。在填充过程中,外壳程序可填充HOOK-API的代码地址,这样就可间接的获取程序的控制权。
7)跳转到程序入口点(OEP)
经历过以上步骤后,外壳程序的功能就完成了,随后他会把控制权交给原程序,一般的壳这里会有一个明显的“分界线”。当然现在越来越多的加密壳将OEP一段代码搬到外壳的地址空间里,然后将这段代码清除掉。这种方式称为StolenBytes。这样,OEP与外壳就没有明显的分界线了,这增加了脱壳的难度。
0x02 利用两次内存断点法手动找到OEP
两次内存法的原理就是利用了壳加载过程第三步时需要对各个区段进行解密并将解密后的区段写入各个区段,完毕之后会跳转至原程序的OEP处。当然,如果我们能判断出壳何时跳转至OEP处最好,但是一般这并不容易。但是我们可以先对.data区块下断后再运行程序(因为区段.code比.data先解压,运行到这个断点时.code以及解密完成),随后再对.code(有的编译器是.text)段下断在运行,这样程序就会停在OEP处(因为解密完成后壳程序一定再次返回到OEP处,将控制权交给原程序)。这个方法就是两次内存法。
0x03 实例介绍两次断点法找OEP过程
1)将文件拖入od,alt+m进入内存模板,随后对.data区块按F2下断,如下图:

2)点击F9运行,此时程序停在了下来,如下图:

这里其实马上就要对.data区块进行解密读写操作了,此时再alt+m进入内存模块,对.text(这个就是.code区块,由于编译器不同,有的显示.text区块)区块下断。
3)点击F9运行,此时程序停止,如下图:

其实这里就是原程序的OEP地址了,由于od对PE文件进行了分析,所以显示如上图,我们可以右键,删除模块分析即可得到下图:

标红框的地方就是OEP地址了。
0x04 总结
两次内存断点法虽然简单,但是我们还是要弄清楚其中的原理。它其实就是利用壳加载过程需要对区段进行解密然后返回原程序OEP这一特性。(PS:这种方法对于那种去区段信息改的面目全非的基本无效,我昨天就碰到一个加壳程序,区段信息只留下几个自己写,连code,data这些常用区段都没有,所以使用之前请用lordPE等工具查看一下区段信息)
脱壳实践之寻找OEP——两次内存断点法的更多相关文章
- 脱壳实践之寻找OEP——堆栈平衡法
0x00 前言 上一篇介绍了壳程序的加载过程以及通过两次内存断点法寻找OEP,这篇我们将利用新的的方法——堆栈平衡法来寻找OEP. 0x01 堆栈平衡法原理 堆栈平衡原理就是利用壳程序在运行前后需要 ...
- 菜鸟脱壳之脱壳的基础知识(五)——利用内存断点寻找OEP
经过第一节的基础知识,我们都知道了,加壳程序首先解把原来压缩的代码解压,然后放到所对应的区块中,当外壳程序执行完毕后,跳回到OEP执行,我们都知道,OEP是放在代码段中,也就是当外壳程序处理完毕后,跳 ...
- 两次内存断点法寻找OEP
所谓“两次内存断点法寻找OEP”,按照<加密与解密*第三版>上的解释来说,就是这样的.一般的外壳会依次对.text..rdata..data..rsrc区块进行解压(解密)处理,所以,可以 ...
- 脱壳入门----常见的寻找OEP的方法
一步直达法 所谓的一步直达法就是利用壳的特征.壳一般在执行完壳代码之后需要跳转到OEP处,而这个跳转指令一般是call ,jmp ,push retn类型的指令,而且因为壳代码所在的区段和OEP代码所 ...
- 破解之寻找OEP[手动脱壳](2)
1.使用ESP定律 OD载入后,F8一次,在寄存器窗口的ESP的内容上(如0012FFA4)右键:“在数据窗口中跟随”,到内存数据窗口,将内存数据窗口以HEX 数据形式显示,在刚才的地址起始位置上(如 ...
- 破解之寻找OEP[手动脱壳](1)
OEP:(Original Entry Point),程序的入口点,软件加壳就是隐藏了OEP(或者用了假的OEP), 只要我们找到程序真正的OEP,就可以立刻脱壳. PUSHAD (压栈) 代表程序的 ...
- 寻找OEP
1.使用ESP定律 OD载入后,F8一次,在寄存器窗口的ESP的内容上(如0012FFA4)右键:"在数据窗口中跟随",到内存数据窗口,将内存数据窗口以HEX数据形式显示,在刚才的 ...
- JVM高级特性与实践(一):Java内存区域 与 内存溢出异常
套用<围城>中的一句话,“墙外面的人想进去,墙里面的人想出来”,用此来形容Java与C++之间这堵内存动态分配和垃圾收集技术所围成的“围墙”就再合适不过了. 对于从事C.C++的开发人员而 ...
- C++中两块内存重叠的string的copy方法
如果两段内存重叠,用memcpy函数可能会导致行为未定义. 而memmove函数能够避免这种问题,下面是一种实现方式: #include <iostream> using namespac ...
随机推荐
- android在service中stopself遇到的问题
在service的oncreate中直接调用stopservice停止自己,依然会执行onstartcommand方法后,最后才调用ondestory方法
- 【Spring Cloud 系列】 二、Spring Cloud Eureka 的第一印象
Eureka : 翻译翻译,找到了!(惊讶语气) Spring CLoud 中的 Spring Cloud Eureka,用于 分布式项目中的服务治理.是对Netflix 套件中的Eureka 的二次 ...
- pyqt5 主界面打开新主界面的实现
import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * ###### ...
- 2019-02-05 Linux的一些常用命令学习2
黑马程序员python课的笔记 ls -l 显示文件详细信息 ls -l -h 以k形式显示大小 ls -a 显示指定目录下的所有子目录和文件,包括隐藏文件 ls匹配符 *代表任意个数的字符 ?代表任 ...
- Springboot基于assembly的服务化打包
(1)首先我们编辑 assembly.xml 配置文件,在前文的基础上新增第三方依赖设置(高亮部分),实现将第三方的 jar 包添加到压缩包里的 lib 目录: <?xml version=&q ...
- Windows安装 PyCharm
PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试.语法高亮.Project管理.代码跳转.智能提示.自动完成.单元测试.版本控制. ...
- BootstrapDialog.confirm确认对话框
1. 依赖文件: bootstrap.js bootstrap-dialog.js bootstrap.css bootstrap-dialog.css 2.代码 BootstrapDialog.co ...
- jQuery动态生成<select>下拉框
前一阵在项目里需要动态生成下拉框,找了一下用jQuery实现比较方便,这里整理一下. 下文所述方法只是本人在项目中遇到问题的解决方法,场景较为简单,也希望能帮助有需要的朋友 1.动态生成下拉框的两种方 ...
- js页面跳转的问题(跳转到父页面、最外层页面、本页面)
"window.location.href"."location.href"是本页面跳转 "parent.location.href"是上一 ...
- webpack4.X + react搭建
环境准备工作:windows7.webStorm 2017.1.4.Nodejs 8.7.0.npm 5.4.2 PS:安装的时我们都带上版本,这样即便webpack版本发生变化,也不会出现版本问题. ...