先举一个例子:
上图中E9 63210000为硬编码(也叫OpCode),63210000是以小端进行显示的,它实际的结果为0000 21 63,本文中表示地址偏移的硬编码统统设为X
下面介绍一个公式:
真正要跳转的地址 = E8这条指令的下一行地址 + X;这里的X指的就是硬编码;
X = 真正要跳转的地址(其实就是目标地址) - E8这条指令的下一行地址
地址 硬编码 汇编
004011F8 E8 53 FE FF FF call function(0040 1050)
004011FD 33 C0 xor eax , eax
这里验证一下这个公式:
这个例子中E8 (call)这条指令的下一行的指令地址为004011FD ,要跳往的地址为 0040 1050(这两者皆为16进制)
X = 0040 1050 - 004011FD = FFFF FE53 (请用计算器计算)
这里的FFFF FE53用小端写出来就是FFFF FE53 !
00401050 E9 2B 2B 00 00 jmp Function(00403B80) //这是第一条指令
00401055 CC int 3 //这是下一条指令
X = 00403B80 - 00401055 = 00 00 2B 2B
得到硬编码为 2B 2B 00 00
其实E8/E9后面跟了4个字节,故整个长度为5个字节;故:
E8这条指令的下一行地址=E8这条指令的地址+5
所以上面公式变为:
X = 要跳转的地址 - ( E8(E9)这条指令所在地址 + 5) //这里的地址为”拉伸”后的在内存中运行的地址!!!
下面一个例子就是要在一个程序里面添加一段有关Messagebox的代码,
Push 0的硬编码如下:
6A 00 push 0
6A 00 push 0
6A 00 push 0
6A 00 push 0
往代码段添加一段如下的代码:
6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00
首先要看代码段剩下的空间能不能够容纳下这18个字节???(E8 与call 对应,E9 与jmp对应)
用SizeofRawData - VirtualSize即可!这里检测到是可以的
MessageBox的地址为77 E5 42 5F
call message 的下一条指令地址:41A73D(这个地址其实就是E9 所对应的那个地址)
所以X = 77 E5 42 5F-41A73D= 77A3 9B22 对应硬编码为22 9B A3 77
所以E8 00 00 00 00填充为E8 22 9B A3 77
OEP为00 01 83 D7(这是可选头里面的,是一个RVA)
Imagebase为0x40 0000
故入口点位置为00 41 83 D7(目标地址)
而 E9 00 00 00 00这条指令的下一条指令的地址可以通过PE工具找出来,就是你在ImageBuffer里面的那个区段添加了这18个字节的指令之后的那个地址,这里为1A742,再加上40 0000,为41 A7 42,
故这里的X = 00 41 83 D7(目标地址)-41 A742=FFFF DC95 对应硬编码为95 DC FF FF
所以这里E9 00 00 00 00填充为E9 95 DC FF FF
最后要思考的是添加这段代码,我们要实现的效果是 先弹出一个MessageBox的对话框,然后再执行原来的exe程序,
而我们要添加的6A 00 6A 00 6A 00 6A 00 E8 22 9B A3 77 E9 95 DC FF FF这段代码的起始地址是1A730(这里没有加ImageBase),要想实现上面所说的效果,就必须把原来的OEP(1 83 D7)改为1A730即可
实现逻辑:将原来的OEP改为添加的代码的因编码所在地址,这样程序运行的时候就从你添加的代码开始执行了,而添加的代码的硬编码为E9 95 DC FF FF,这句话的逻辑是跳往原来exe的OEP,硬编码计算公式见上
注意:注入的概念是这个代码本身已经在运行了,我把我的代码”扔”进去,而这里在代码为运行之前将代码加进去