PE文件硬编码代码注入

以下适合有PE基础的人看,最起码要知道PE的基本结构和rva以及foa之间如何相互转换,不然会看的迷迷糊糊

先决条件

首先我们需要准备一个程序,待会将代码注入这个程序中
随便编写一个简单的程序,将随机基址给关闭
在这里插入图片描述

硬编码

程序编译完成之后就是一堆二进制的数据,如果我们想将代码注入到这个程序中,我们也只能以二进制的形式进行注入,不能像编码高级语言一样,比如我们想将 MessageBoxA(0, 0, 0, 0) 这段代码注入进去,要求是在程序运行时首先运行这段代码,然后再跳转到之前的代码逻辑
我们想将这段代码注入进去的话就只能将这段代码翻译成二进制的形式,然后再到这个exe的某一处地方将这段代码写进去。
那么我们就有必要来了解一下硬编码,首先我们来看看一个程序是如何调用一个函数的,主要关注两个地方,调用函数用到的指令是什么?指令的参数是什么?
我们来看看下面这段代码是如何调用的
在这里插入图片描述
将代码转到反汇编的模式下
在这里插入图片描述

可以看到 调用函数使用的是 E8 指令后面紧跟着 EC F4 FF FF 这是一个地址,可是这个地址并不是真正的函数地址,真正的函数地址是 2415D2(ps 其实这也不是真正的函数地址,这个地址一般情况下指向一个jmp的地址再由jmp地址跳转到真正的函数)

既然根据E8后面的这个地址可以找到真正的函数入口,那么就证明这个地址一定跟函数的地址有着某种联系,他们之前肯定有一个换算的关系,公式如下

E8后面跟着的地址 = 函数的地址 - E8下一行执行的地址

由于 E8指令的长度是5(E8加上4个字节地址)公式又能变形成如下

E8后面跟着的地址 = 函数的地址 - (E8的地址 + 5)

照着上面的地址换算一下

test函数的地址是 2415D2
E8的地址是 002420E1
那么E8后面跟着的地址就是 2415D2 - (002420E1 + 5)= FFFF F4EC
算的时候一定要选择 DWORD类型,因为我们是32位程序,每个地址只占4个字节
在这里插入图片描述
调用函数搞定了,但是调用完我们注入进去的代码后我们要回到之前的代码逻辑,不然的话就会影响程序的正常运行
想要回到程序之前的代码逻辑我们使用 jmp指令硬编码为 E9
E9指令和E8一样后面也是跟着一个地址,且这个地址也要进行换算,换算的规则和E8的换算规则一摸一样

代码注入

搞定了硬编码之后我们就要进行代码注入了
那么代码注入到哪里呢?这里为了方便就直接注入到 .text.段,这里大家都应该明白为什么要注入到 .text段,因为一个正常编译出来的程序默认的代码段就是 .text 当然我们学过PE之后,我们也可以把代码注入到其他段,只需要将这个段的属性改为可执行即可,或者干脆自己新增一个段,然后将代码写入到自己新增的这个段里,我们要注入哪个段就将哪个段的属性该为可执行即可 .text默认就有可执行权限了,所以我们注入到这个段不需要进行任何更改

下面我将使用 010Editor来进行手动的代码注入

首先我们打开要注入的程序
然后找到 .rdata这个段,之后向上滑动
![在这里插入图片描述](https://img-blog.csdnimg.cn/f959aed07bf049589cc976f641e35be5.png在这里插入图片描述
向上滑动后我们就能快速的找到 .text段的结尾
我们在都是0的位置添加我们需要注入的代码
在这里插入图片描述

我们首先需要找到 MessageBoxA函数的地址,以及调用这个函数需要传递什么参数
在这里插入图片描述
先看参数 为了简单我们传递 4个0,且这个传递参数的硬编码是 6A 要传递4个0的话就是 6A 00 6A 00 6A 00 6A 00
再看 MessageBoxA的地址
他的地址在 038111C这个位置存着,我们查看内存就能找到 MessageBoxA的地址
在这里插入图片描述
好了,到这里为止已经把 MessageBoxA的函数地址以及参数都搞定了,接下来就是注入代码了

我们只在程序运行前调用一个MessagaeBoxA 然后再跳回原来的程序入口
那么可以开始写代码了

6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00
首先将这段代码写进去,之后我们就只要修改 E8 以及E9后面的地址了
在这里插入图片描述
首先来计算 E8后面的地址
E8后面跟着的地址 = 函数的地址 - (E8的地址 + 5)
我们要调用MessageBoxA且这个函数的地址我们也知道了 762682A0
重点是这个E8地址是什么,所以首先我们需要查看 文件对齐值和内存对齐值是否一致
接着查看程序的基址也就是IamgegBase是多少才能来计算E8真正的地址

ImageBase为 400000h
内存对齐值为 1000h
文件对齐值为 200h
在这里插入图片描述

首先我们将E8现在处在的文件偏移地址加上 400000h
E8现在在文件中的偏移为 71D248h 加上之后等于 B1D248h
然后由于文件对齐和内存对齐不一致,所以导致程序加载进内存之后这个E8的地址会发生变化,那我们如何知道E8加载进内存之后的地址呢?

因为我们的代码是写在 .text这个段里面的,所以我们需要计算这个段在内存中的开始位置和在文件中的开始位置的差
那就是 36B000 - 400 = 36AC00
也就是说我们在文件中的.text段的地址偏移加上这个 36AC00 就是这个地址在内存中的真正的地址了
在这里插入图片描述
那就是我们上面算出来的这个值B1D248h + 36AC00 = E8 7E48(E8在内存中的真正地址)

那我们E8后面跟着的地址就是 762682A0 - (E8 7E48 + 5) = 753E 0453
这个 753E 0453就是E8后面真正要跟着的地址

在这里插入图片描述
之后就要计算 E9后面跟着地址,我们要找到OEP
在这里插入图片描述
OEP为 36B4BFh 这里值得注意的是这个OEP是一个rva所以我们直接加上 400000(程序的基址) 就得出了 OEP在内存中的地址了

OEP在内存中真正的地址是:76B4BFh

OEP就是我们真正要跳转的地址,接下来就找E9的下一行地址了,可以根据上面算E8下一行地址的步骤来算E9的下一行地址,不过这里有个更快的方法,上面我们算出来了E8下一行的地址,刚好E9就是E8下一行的地址,所以我们之前拿刚刚算出来的地址再加上5就是E9的下一行地址了也就是 E8 7E48 + 5 + 5 = E8 7E52
然后就是 76B4BFh - E8 7E52h = FF8E 366D
那E9后面跟着的地址就是 FF8E 366D
在这里插入图片描述
代码注入到这一步就完成了,但是还差一步,就是程序加载到内存之后首先要运行我们的代码
所以我们要将之前的OEP更改掉
在这里插入图片描述
这段代码开始的位置是 71D240 那么在内存中的偏移就是再加上 36AC00
71D240 + 36AC00 = A8 7E40
注意这里不需要再加上 400000(ImageBase)了,因为OEP是一个RVA,所以我们算出在内存中的偏移就可以了
所以我们直接将OEP更改为 A87E40h 然后就将文件保存
到这里为止整个代码注入就完成了

接下来就是测试
我们运行刚刚我们更改过的程序
就会看到弹窗,这是我们刚刚注入进去的代码就是 MessageBoxA(0, 0, 0, 0)执行的效果
在这里插入图片描述
点击确定后,程序就会和之前一样跑起来
在这里插入图片描述

把程序放到OD里跑起来可以发现确实首先运行的就是我们刚刚注入的代码
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值