相关笔记代码测试验证记录
手动在代码空白区添加代码 1.获取MessageBox地址,构造ShellCode代码. 下面是测试代码 #include "stdafx.h" #include <windows.h> void fun() { printf("Hello Cntf "); MessageBox(0,0,0,0); } int main(int argc, char* argv[]) { fun(); return 0; } 将上面代码编译执行,发现弹框,说明就是成功验证确认了MessageBox的功能; 上面完成之后,我们再找到一个正常的应用程序设置断点,找出MessageBox在程序执行的起始位置; 在OD工具里面设置断点,bp MessageBoxA,然后在菜单栏找到"B" 点击进去就发现了设置的断点; 然后双击即可查看MessageBox的断点位置,如下: 77D5050B > 8BFF MOV EDI,EDI 最终确认MessageBox在程序中执行的地址如下: 0x77D5050B 2.E8 E9计算公式 公式一: 真正要跳转的地址 = E8这条指令的下一行地址 + X 下面是变形公式: X = 真正要跳转的地址 - E8这条指令的下一行地址 下面是上面写的简单代码进行编译,调试,进入反汇编得到的结果 15: fun(); 00401098 E8 68 FF FF FF call @ILT+0(fun) (00401005) 16: return 0; 0040109D 33 C0 xor eax,eax 解释: E8 ---> call的硬编码 E8后面的4个字节是通过计算的出来的,我们上面的公式就是要验证确认他们的计算方式 根据公式,已知:真正要跳转的地址和E8这条指令的下一行地址; 开始计算 X = 真正要跳转的地址 - E8这条指令的下一行地址 X = 0x00401005 - 0x0040109D = 0xFFFFFF68 开始比对代码中反汇编的地址和计算出来的地址 00401098 E8 68 FF FF FF call @ILT+0(fun) (00401005) 0xFFFFFF68 ---> FF FF FF FF 68 E8 68 FF FF FF 通过上面对比得知他们是一样的;所以最终结果如下: E8 68 FF FF FF @ILT+0(?fun@@YAXXZ): 00401005 E9 16 00 00 00 jmp fun (00401020) 开始E9这个jmp汇编指令后面的4个字节验证 生成的反汇编代码 @ILT+0(?fun@@YAXXZ): 00401005 E9 16 00 00 00 jmp fun (00401020) @ILT+5(_main): 0040100A E9 71 00 00 00 jmp main (00401080) 开始计算 X = 0x00401020 - 0x0040100A = 0x00000016 通过对比生成的反汇编代码,同样可以确认结果是一样的 00401005 E9 16 00 00 00 0x16000000 最终的结果: E9 16 00 00 00 公式二: 要跳转的地方 = (E8当前的地址 + 5) + X X = 要跳转的地址 - (E8的地址 + 5) 下面是反汇编代码生成的关于MessageBox的信息 10: MessageBox(0,0,0,0); 00401045 8B F4 mov esi,esp 00401047 6A 00 push 0 00401049 6A 00 push 0 0040104B 6A 00 push 0 0040104D 6A 00 push 0 0040104F FF 15 8C 52 42 00 call dword ptr [__imp__MessageBoxA@16 (0042528c)] 00401055 3B F4 cmp esi,esp 00401057 E8 F4 00 00 00 call __chkesp (00401150) 11: } 通过上面的反汇编代码得知,在程序执行MessageBox的时候有4个push 0 00401047 6A 00 push 0 00401049 6A 00 push 0 0040104B 6A 00 push 0 0040104D 6A 00 push 0 所以总结下来,需要向程序的代码区域插入如下18个字节的代码即可 6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00 ---> 18个字节大小 3.在代码区手动添加代码 VirtualSize: 0x000001f8 000440A2 [V(VS),内存中大小(对齐前的长度).] VirtualAddress: 0x000001fc 00001000 [V(VO),内存中偏移(该块的RVA).] SizeOfRawData: 0x00000200 00045000 [R(RS),文件中大小(对齐后的长度).] PointerToRawData: 0x00000204 00001000 [R(RO),文件中偏移.] 00045000 - 000440A2 = F5E ---> 此处计算结果必须大于我们上面要插入的18个字节大小,不然会出问题 6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00 打开winhex或者ultraedit编辑器,使用她们打开二进制文件,我们的目的是针对二进制文件; ipmsg.exe的第一个节后面的代码空白区域添加我们的代码;就是在SizeOfRawData -> 0x00045000的后面 理解: 第一个节从PointerToRawData 文件偏移开始--> 0x00001000开始向后数,数到0x00045000结束; 然后根据对齐宽度是1000H,所以向后再加上1000H就是0x00046000是第二个节的开始位置; 这里需要注意,我使用编辑器打开ipmsg.exe文件之后,找到0x00045000的位置发现还有数据; 向后扩展1000H到了0x00046000位置是对的,刚好是下一个节的开始位置,而这期间; 0x00045000 - 0x00046000这里面开头一点还是有数据的,到了一定的位置发现都是00,那么确认此处; 到0x00046000开始的上一个字节位置都是空白区域,都是可以填充数据的; 我这里找到代码空白区域的位置是0x000450a2开始,从这里开始的,我们从此处的下一行开始填充代码; 也就是从0x000450b0位置开始,具体如下: 000450b0h: 6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 000450c0h: 00 00 到了上面,就算完成了一部分了,我们要开始添加执行函数call汇编指令和jmp汇编指令后面的硬编码数据; 需要的MessageBox数据 ----> 0x77D5050B 要使用到的公式 公式二: 要跳转的地址 = (E8当前的地址 + 5) + X 变形: X = 要跳转的地址 - (E8当前的地址 + 5) 根据上面的公式,我们最要确定的是算出要跳转的地址,所以需要使用公式: X = 要跳转的地址 - (E8当前的地址 + 5) 现在我们对比公式填充数据: 要跳转的地址 = 0x77D5050B E8当前的地址 + 5 = 下一个jmp的汇编指令开头 ---> E9的位置 ---> 0x000450bd 得到上面的地址,一定要再考虑(ImageBuffer里面的偏移)内存偏移和 因为我们加入的代码; 最终是要在内存中运行,所以一定是要考虑在内存中偏移和对齐; 要考虑这两个 ---> VirtualAddress和PointerToRawData VirtualAddress: 0x000001fc 00001000 [V(VO),内存中偏移(该块的RVA).] PointerToRawData: 0x00000204 00001000 [R(RO),文件中偏移.] 下面是可选PE头的ImageBase内容 ImageBase: [地址(RAW):0x0000012c] [长度:04h] [偏移量:e_lfanew+0x34] [数据:0x00400000] [基址,程序默认装入的基地址.] 但是本次测试使用的程序很巧,刚好文件和内存中的偏移是一样的,都是1000H 根据ImageBase和内存偏移地址1000H得出地址:0x000450bd + 0x00400000 = 0x004450bd 所以根据公式计算最终地址: X = 要跳转的地址 - (E8当前的地址 + 5) 要跳转的地址 --> 0x77D5050B (这里要跳转的地址就是上面我们找到的MessageBox的地址) (E8当前的地址 + 5) --> 0x004450bd X = 0x77D5050B - 0x004450bd = 0x7790B44E 0x7790B44E --> 77 90 B4 4E --> 小端模式 --> 4E B4 90 77 --> 放入E8的后面 000450b8h: E8 4E B4 90 77 ----> 这就是最终的E8后面的数据 我们开始计算E9后面的数据,要清楚,我们加入代码之后,需要再回到程序的入口处; 所以E9要跳转的地址就是OEP的地址,但OEP的地址更改完成之后需要再将程序执行的OEP地址; 更改为上面为我们添加代码的开始地址; 需要用到的OEP地址信息: AddressEntryPoint --> 0x000441EC ImageBase --> 0x00400000 得到最终的OEP地址 --> 0x000441EC + 0x00400000 = 0x004441EC X = 要跳转的地址 - (E9当前的地址 + 5) 要跳转的地址 --> 0x004441EC (E9当前的地址 + 5) --> 0x004450C2 X = 0x004441EC - 0x004450C2 = 0xFFFFF12A 0xFFFFF12A --> FF FF F1 2A --> 小端模式 --> 2A F1 FF FF --> 放入E9的后面 000450bdh: E9 2A F1 FF FF ----> 这就是最终的E9后面的数据; 上面完成了之后到了最后一步了,修改OEP的值,在修改的时候我们不需要再加上ImageBase的值; 因为程序在运行的时候会帮我们加上,所以我们只要填充我们代码里面的初始值即可,这里我们; 添加了18个字节的代码,开头的还是6A 00 打头的,就是MessageBox的起始地址,添加这个地址; 需要跟OEP对应的地址为:0x000450b0 我们找到原来的OEP地址位置:0x000441EC (这个地址是没加ImageBase的地址,我们直接更改保存); 对应位置是可选PE文件头里面 --> 00000120h: EC 41 04 00 将其更改为这个地址内容 --> 0x000450b0 --> B0 50 04 00 更改后的最终OEP地址: 00000120h: B0 50 04 00 保存执行测试; 测试执行成功; 4.修改OEP,指向ShellCode. 上面第3步已经操作完成;
相关更改后的二进制文件内容信息:
更改的OEP的地址位置
保存运行后的结果