在PE文件间隙中加入自己的代码-全程步骤

本文详细介绍PE文件的结构及如何手动修改PE文件以实现特定功能。通过实例演示了如何在PE文件中添加自定义代码、引入外部函数、以及如何进行重定位表更新等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PE文件的间隙:

PE文件在磁盘上存放时其各个节是按页的倍数对齐的(磁盘一页为200h,内存一页为1000h),当一个节不是页的整倍数时其尾部用0填充,这就是PE的间隙。

 

本示例是在.text节加入了可执行代码,在.idata节加入了外部引用函数,在.reloc节加入了重定位地址。

 

本示例MyPE.exe是用VS2008自动生成的SingleWindow样式的程序。

为方便理解,附上部分源码:

 

 

本示例的目的:

当按下菜单栏的“关于”时,先弹出我们的 确定_取消消息框,点击确定程序继续执行,显示关于对话框,点击取消,不显示。

 

 

 

 

准备工具:

OllyDbg。用于调试、分析程序流程、获取机器码。

Hex workshop:修改PE文件。

Stud_PE:查看PE结构。

SoftICE:查看菜单标识、查看消息常量。

spy++:查看窗口句柄。辅助SoftICE用的。

可选工具:

IDA Pro : 分析程序流程更强悍。

 

 

 

操作步骤:

 

1:找到窗口回调函数中处理“关于”的地址处。

 

首先我们先分析程序流程,当按下菜单时,程序会调用SendMessage向窗口的回调函数发送WM_COMMAND消息。

SendMessage有4个参数:HWND hWnd,  UINT msg, WPARAM wParam, LPARAM  lParam

在这里msg == WM_COMMAND

最后一个参数在这里用不到,忽略。

第三个参数的低字是菜单的标识(ID)。这个ID是在编程时由程序员自己定义的值,我们无法得知。

 

我们可以想象到,在处理关于的地址处肯定有CMP  ***, 111h(WM_COMMAND),如果是COMMAND消息,则继续比较看是否是“关于”的菜单ID。所以我们现在需要得到这个ID。

 

另外WM_COMMAND的常量可以用SoftICE的WMSG 命令得到:

 

我们也可用OllyDbg或IDA Pro查找常量111h,然后直接分析也能找到。但这里我们用SoftICE下消息断点来得到消息ID:

 

首先运行MyPE,再运行Spy++获得MyPE的窗口句柄。

这里得到的窗口句柄是3019E。

 

 

打开SoftICE输入BMSG 3019E WM_COMMAND,然后退出。再点击MyPE的“关于”,这时SoftICE捕捉到WM_COMMAND并中断:

 

 

这里我们就得到了“关于”的标识68。而且代码窗口也准备要跳到回调函数了。

 

然后用OllyDbg找常量111h再找到68h,这样就找打了目标地址。

 

 

 

这里的代码也很容易理解:

从上面分析下来可以确定这里就是“关于”的处理程序处了。

 

4118C4 --- 4118CB:是否等于 == 68,如果是就跳转到4118D8处。

 

4118D8处首先保存ESP,然后几个参数入栈,到了4118EE处调用DialogBoxParam打开“关于”对话框。

 

我们现在只要修改地址4118CB处的机器码,让它跳到我们的代码地址处。然后如果点击了确定就跳到4118DA处。即参数入栈,执行DialgoBoxParamW。点击取消,跳到4118F4处,即跳过了DialogBoxParam的调用。

 

2:插入代码

我们的可执行代码要掉用MessagBoxW这个函数,但MyPE的.idata节内没有引用这个函数,所以我们得自己把这个函数加进去。

 

 

这里先复习下DLL函数引入的原理:

PE可选首部最后的一个成员是一个数组,数组内装了16个IMAGE_DATA_DIRECTORY类型的数据结构。

 

 

 

数组中的第2项是描述引入表的。从这里得到引入表的起始RVA,和字节数。

用图来描述:

 

 

 

好了,复习完毕。现在就开始我们的引入工作。

基本原理是:把上面那个RVA指向我们的新地址,并改变大小。复制旧地址处dll表格到我们的新地址。并把原先为NULL的修改成我们的数据,最后再留5个为0的双字(结束标记)。

 

用Stud_PE打开MyPE,查看.idata的下一个节的RawOffset,这里是:6E00

 

 

 

然后用Hex Workshop 打开MyPE,Ctrl+G跳到这个地址处再往上翻,这些00的地方就可以写入我们的代码。

 

 

这里可以从6B47处开始写,但为了直观我打算隔一行。6B60处。

.idata节的相对偏移为:VAOffset - RawOffset = 18000 - 6200 = 11E00H

6B60的VA: 6B60 + 11E00 = 18960H

 

先修改我之前说到的那个IMAGE_DATA_DIRECTORY结构的内容,让RVA = 18960,SIZE = 原来的内容 + 14H

 

我这里改好后为:

60 89 01 00 64 00 00 00

 

复制旧内容到新地址处:

红色为复制过来的部分。

 

前3个短框:指向INT , 指向DLL名称,  指向IAT

长框是结束标记。

 

 

写入格式:

隔行, DLL名称+一个字节NULL    IAT    间隔一个双字     INT   间隔一个双字     WORD函数名称两个字节NULL.

(函数名称前有个WORD是数据结构的一部分,是函数在DLL中的序号值,这里不重要;且我们存放WORD函数名称的地址高31为必须为0,)

 

 

IAT 和INT都指向函数名称地址RVA。

 

DLL名称起始RawOffset = 6BD0, RVA = 189D0

IAT起始RawOffset = 6BDB, RVA = 189DB ,注意这个RVA,下面汇编时要用它。

INT .....................  = 6BE3,   RVA = 189E3

函数名称.................= 6BEB,   RVA = 189EB,189EB的最高位为0,。

 

再把各项数据填入3个短框内,如图:

 

 

保存。用Stud_PE打开刚保存的PE文件,查看Functions就可以知道是否引入成功。

至此函数引入完毕。

 

 

 

3:写入可执行代码

先找到.text节的间隙。

我这里是4100处。RVA = 14D00。这里写入UNCODE字符串“继续执行?”

4110处写入可可执行代码,RVA = 14D10.

 

先把字符串写到4100处:

E7 7E ED 7E 67 62 4C 88 1F FF 00 00

 

保存。

再在OllyDbg中开始写汇编:

 

 

 

414D1D处已经被自动替换成了函数名称,原本输入的是4189DB

 

 

如果调试成功的话,就把机器码写入到对应的文件地址。

 

 

 

 

 

 

 

保存。基本上可以运行了,但还需把代码中涉及直接寻址的操作数的地址放入重定位表。

机器码的格式是:操作码  操作数

按照OllyDbg给出的机器码,从Hex workshop中查看,跳过操作码,找到操作数的RawOffset,再转换成RVA。

 

需重定位的地址:

 

4118CB处:RVA = 118CB, +操作码占的2个字节为:118CB,, 基址部分:11000

414D16处:..........14D16, ..................1............:14D17,.............:  14000,  

414D1D处:..........14D1D,...................2............:14D1F, .........................

414D26处:..........14D26,....................2............:14D28,  ........................

414D2C处:..........14D2C,....................1.............:14D2D, ..... .. .. . .. ....... 

 

重定位表有由很多块组成的。结构为:

virtualAddress   DWORD  -----基址部分

blockSize           DWORD  -----块占的字节数。减去8个字节,剩下的就是各个项目占的字节,再除以2 = 项目数。

typeOffset           WORD  ------高4位为属性0或者3,低12位为偏移。

NULL                    WORD  -----结束标记

 

各项偏移地址去掉基址部分,再OR 3000H就可以得到TypeOffset了。

 

数据目录的第6个结构是描述重定位表的,这里需要修改的是大小。原内容再加上我们占用的字节数。

 

再把我们的地址加到重定位表中:

 

 

 

 

save。over。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值