-
-
[原创]用SMC让EXE文件的重定位表起作用
-
发表于: 2007-5-5 21:34 9720
-
写了《通过ReverseMe学习PE文件结构-重定位表》之后我就在想解决这个问题的办法除了我那个不是办法的办法,还有没有是办法的办法?:)
想到SMC,想到重定位的原理,就想出了这个办法。
=====
重定位表的使用方法为(我自己的理解):
文件的实际装入地址-文件的建议装入地址=修正值
实际装入地址+VirtualAddress+重定位项中的地址=需要重定位的代码在内存中的位置
修正值+需要重定位的代码=正确的代码(只需要把地址加上修正值)
只需要定位到需要重定位的代码在内存中的位置把该处的代码修改成正确的代码即可。
注:上面说的代码应该是用于立即寻址的地址。
=====
算法:
1.计算修正值(修正值=文件的实际装入地址-文件的建议装入地址)
2.读取一个IMAGE_BASE_RELOCATION结构
3.VirtualAddress字段为0则算法结束
4.对所有重定位项执行步骤5-6后跳到2
5.计算需要重定位的地址在内存中的位置
6.修正地址(将需要修正的地址加上修正值)
=====
OllyDBG里的代码:
0040101B 55 push ebp
0040101C 8BEC mov ebp, esp
0040101E A1 1D404000 mov eax, dword ptr [<&Reversed_.MyMe>; 获得需要重定位的文件的装入基址
00401023 66:33C0 xor ax, ax
00401026 8BC8 mov ecx, eax
00401028 0340 3C add eax, dword ptr [eax+3C] ; 获得目标模块的建议装入基址
0040102B 8B50 34 mov edx, dword ptr [eax+34]
0040102E 8BD9 mov ebx, ecx
00401030 2BDA sub ebx, edx ; 计算修正值,放在EBX中
00401032 8BF1 mov esi, ecx
00401034 8BD1 mov edx, ecx ; EDX中是实际装入基址
00401036 03B0 A0000000 add esi, dword ptr [eax+A0] ; 定位目标模块的重定位表,ESI是当前处理的重定位项地址
0040103C 8B06 mov eax, dword ptr [esi] ; EAX中是VirtualAddress
0040103E 83C6 04 add esi, 4 ; 2.读取一个IMAGE_BASE_RELOCATION结构
00401041 85C0 test eax, eax ; 3.VirtualAddress字段为0则算法结束
00401043 74 29 je short 0040106E
00401045 03C2 add eax, edx ; EAX中是 实际装入地址+VirtualAddress
00401047 8B0E mov ecx, dword ptr [esi]
00401049 83C6 04 add esi, 4
0040104C 85C9 test ecx, ecx
0040104E ^ 74 EC je short 0040103C ; 4.对所有重定位项执行步骤5-6后跳到2
00401050 83E9 08 sub ecx, 8
00401053 D1C9 ror ecx, 1
00401055 85C9 test ecx, ecx
00401057 ^ 74 E3 je short 0040103C
00401059 33FF xor edi, edi ; 5.计算需要重定位的地址在内存中的位置
0040105B 66:8B3E mov di, word ptr [esi]
0040105E 83C6 02 add esi, 2
00401061 03F8 add edi, eax
00401063 81EF 00300000 sub edi, 3000 ; EDI中是需要修正的地址的地址
00401069 011F add dword ptr [edi], ebx
0040106B 49 dec ecx
0040106C ^ EB E9 jmp short 00401057
0040106E 5D pop ebp
0040106F C3 retn
=====
这个方法稍微有点通用性了,不过还需要手工给出一个目标模块中的一个函数的入口地址,虽说只是一个地址(见0040101E处的语句),毕竟还是有手动部分。要改成全自动的:)
观察一下0040101E处的语句,发现该处命令的地址参数实际上是输入表中的一项,如此便简单了:我们遍历当前模块的输入表,查找文件名后缀名不是"DLL"或"dll"的输入表项,然后从该表中取一个输入函数即可。
0040101D 55 push ebp
0040101E 8BEC mov ebp, esp
00401020 E8 00000000 call 00401025 ; 获得基址
00401025 58 pop eax
00401026 66:33C0 xor ax, ax
00401029 8BD0 mov edx, eax ; EDX中是基址
0040102B 0340 3C add eax, dword ptr [eax+3C] ; PE文件头
0040102E 66:8B80 80000>mov ax, word ptr [eax+80] ; 输入表
00401035 8B38 mov edi, dword ptr [eax]
00401037 85FF test edi, edi
00401039 74 74 je short 004010AF ; 遍历整个输入表,直到找到满足条件的输入文件
0040103B 8BD8 mov ebx, eax
0040103D 83C0 14 add eax, 14
00401040 83C3 0C add ebx, 0C
00401043 8BFB mov edi, ebx
00401045 8B3F mov edi, dword ptr [edi]
00401047 03FA add edi, edx
00401049 8A0F mov cl, byte ptr [edi]
0040104B 80E9 2E sub cl, 2E ; 定位文件后缀名
0040104E 74 03 je short 00401053
00401050 47 inc edi
00401051 ^ EB F6 jmp short 00401049
00401053 8B0F mov ecx, dword ptr [edi]
00401055 81E9 2E646C6C sub ecx, 6C6C642E ; 判断后缀名是否是"DLL"或"dll"
0040105B ^ 74 D8 je short 00401035
0040105D 81C1 2E646C6C add ecx, 6C6C642E
00401063 81E9 2E444C4C sub ecx, 4C4C442E
00401069 ^ 74 CA je short 00401035
0040106B 83E8 04 sub eax, 4 ; 找到了目标文件,开始找导入函数
0040106E 66:8B00 mov ax, word ptr [eax]
.....;后面与上面的那个版本从00401023开始的相同,略去了
OllyDBG中用于二进制复制/粘贴的代码:
E8 00 00 00 00 58 66 33 C0 8B D0 03 40 3C 66 8B 80 80 00 00 00 8B 38 85 FF 74 74 8B D8 83 C0 14
83 C3 0C 8B FB 8B 3F 03 FA 8A 0F 80 E9 2E 74 03 47 EB F6 8B 0F 81 E9 2E 64 6C 6C 74 D8 81 C1 2E
64 6C 6C 81 E9 2E 44 4C 4C 74 CA 83 E8 04 66 8B 00 A1 1D 40 40 00 66 33 C0 8B C8 03 40 3C 8B 50
34 8B D9 2B DA 8B F1 8B D1 03 B0 A0 00 00 00 8B 06 83 C6 04 85 C0 74 29 03 C2 8B 0E 83 C6 04 85
C9 74 EC 83 E9 08 D1 C9 85 C9 74 E3 33 FF 66 8B 3E 83 C6 02 03 F8 81 EF 00 30 00 00 01 1F 49 EB
E9 5D C3
=====
这样子就有通用性了,以后给目标程序建立重定位表之后,只需要把这段代码粘贴到调用目标程序的程序中就可以了。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [求助]怎么在驱动里伪造一个IP包 5983
- [原创]背 4051
- [原创]挑帖子的程序 6579
- [推荐]帮老罗修复了ustrref_v0.12的一个BUG 11279
- [原创]发个简历 5584