二进制文件概述
1. PE文件格式
PE(Portable Exec utable)是 Win32 平台下可执行文件遵守的数据格式。常见的可执行文件(如*.exe文件和*.dll文件)都是典型的 PE 文件
PE 文件格式把可执行文件分成若干个数据节(section),不同的资源被存放在不同的节中。
一个典型的 PE 文件中包含的节如下。
.text 由编译器产生,存放着二进制的机器代码,也是我们反汇编和调试的对象。
.data 初始化的数据块,如宏定义、全局变量、静态变量等。
.idata 可执行文件所使用的动态链接库等外来函数与文件的信息。
.rsrc 存放程序的资源,如图标、菜单等。
除此以外,还可能出现的节包括“.reloc”、“.edata”、“.tls”、“.rdata”等。
#正常的PE大体相同,加壳的PE十分古怪
2. 虚拟内存
windows进程层面:
- 物理内存(复杂,通常看不到)
- 虚拟内存(在用户模式下,我们用调试器看到的内存地址都是虚拟内存)
在这个系统中,每个进程都相信自己拥有4GB的内存空间,但他们实际运行时根本用不到这么多,内存管理器给他们分配一片假地址,让进程们“认为”这些“虚拟地址”都是可以访问的。如果进程不使用这些“虚拟地址”,它们对进程来说就只是一笔“无形的数字财富”;当需要进行实际的内存操作时,内存管理器才会把“虚拟地址”和“物理地址”联系起来。
操作系统中的虚拟内存:是指内存不够用将硬盘的一些空间占用的策略,与此不同
3. PE 文件与虚拟内存之间的映射
在调试漏洞的时候,我们需要做两种操作:
- PE中的文件偏移—>虚拟内存地址(VA)
- VA—>PE文件中对应位置的机器码
因此需要知道PE与虚拟内存的映射关系:
-
文件偏移地址(File Offset):数据在 PE 文件中的地址叫文件偏移地址,作者认为叫做文件地址更加准确。这是文件在磁盘上存放时相对于文件开头的偏移。
-
装载基址(Image Base):PE 装入内存时的基地址。默认情况下,EXE 文件在内存中的基地址是0x00400000,DLL文件是 0x10000000。这些位置可以通过修改编译选项更改。
-
虚拟内存地址(Virtual Address,VA):PE 文件中的指令被装入内存后的地址。
-
相对虚拟地址(Relative Virtual Address,RVA):内存地址相对于映射基址的偏移量。
VA= Image Base+ RVA
文件偏移是相对于文件开始处 0 字节的偏移,RVA(相对虚拟地址)则是相对于装载基址。
但是有一些差异:
-
PE 文件中的数据按照磁盘数据标准存放,以 0x200 字节为基本单位进行组织。当一个数据节(section)不足 0x200 字节时,不足的地方将被 0x00 填充;当一个数据节超过 0x200字节时,下一个 0x200 块将分配给这个节使用。因此 PE 数据节的大小永远是 0x200 的整数倍。
-
当代码装入内存后,将按照内存数据标准存放,并以 0x1000 字节为基本单位进行组织。类似的,不足将被补全,若超出将分配下一个 0x1000 为其所用。因此,内存中的节总是0x1000 的整数倍。
这导致节偏移的出现:
文件偏移地址 = 虚拟内存地址(VA)−装载基址(Image Base)−节偏移= RVA -节偏移
一般 PE 文件的 0 字节将对映到虚拟内存的 0x00400000位置
以表 1-2-1 为例,如果在调试时遇到虚拟内存中 0x00404141 处的一条指令,那么要换算出这条指令在文件中的偏移量,则有:文件偏移量=0x00404141-0x00400000- (0x1000-0x400)=0x3541
地址转换工具:Load PE
一般需要环境,直接下载一个吾爱破解虚拟机算了。
VOFFSET:虚拟内存地址(VA) | ROFFSET:文件偏移地址
4.必备工具
1. OllyDbg
2.IDA PRO
3.010 editor
4.python
5. 一个简单的例子
我们可以使用IDA分析其逻辑
发现其跳转逻辑位于此条,IDA已经为我们计算好了运行时VA,打开OD按快捷键 Ctrl+G 直接跳到由 IDA 得到的 VA:0x0040106E 处查看那条引起程序分支的关键指令
将其直接修改为jz,点击汇编将其写入内存,下断点程序运行至此处,输入密码后会显示有不同的跳转,不输入正确密码也能跳转成功。
题外话:软件破解是另一门自成体系的技术了,在这里不做讨论,这个也是最简单的OD+IDA利用了,其实有很多种方法可以绕过这个密码验证,实在无趣。