重定位表 偏移位于 可选头最后一个成员:
0x60_IMAGE_DATA_DIRECTORY DataDirectory[16]; 第6个目录
指向重定位表的偏移 :
IMAGE_DIRECTORY_ENTRY_BASERELOC
struct _IMAGE_DATA_DIRECTORY {
0x00DWORD VirtualAddress; RVA 模块基址/句柄 + VirtualAddress =重定位表在内存中的位置
0x04 DWORD Size; 没用
};
重定位表块(有很多块这种结构) 每一块的开始部分 是下面这种结构:
srurct_IMAGE_BASE_RELOCATION{
0x00 DWORD VirtualAddress; RVA
0x04 DWORD SizeofBlock; 块大小
}
| 结构1 VirtualAddress 4字节 RVA |
| 结构1 SizeofBlock; 4字节 块大小 |
| 结构1:数据.(每个数据2字节) 每个高4位值为3的数据都需要修复 (指向的地址) |
| ..... |
| 结构2 VirtualAddress 4字节 RVA |
| 结构2 SizeofBlock; 4字节 块大小 |
| 结构2:数据. (每个数据2字节) 每个高4位值为3的数据都需要修复 (指向的地址) |
| .... |
| 结束标记:VirtualAddress值为0 |
| 结束标记:SizeofBlock; 值为0 |
重定位表 真正要改的地方是 (VirtualAddress+2字节数据的低12位+模块句柄/模块基址) 指向的地方,而不是表。
结构里的 VirtualAddrsss里面的值,是指这些2字节数据(偏移) 都属于同一个页面( 1页=0x1000)..
举例有两个RVA:
被拆分的RVA:8551 8132
VirtualAddrsss7000
SizeofBlock块大小
那么里面的两个2字节数据 0x1551 0x1132 (忽略了2字节数据的高4位 只是举个例子 实际高4位的值不能加)
那么下一个结构
VirtualAddrsss8000
SizeofBlock 块大小
被拆分的 RVA:9475 9647
那么里面的两个2字节数据 0x1495 0x1647 (忽略了2字节数据的高4位 只是举个例子 实际高4位的值不能加)
....
注意:2个字节的数据 低12位已经足够表示一页(十进制4096)的偏移 高4位挪作它用了
如果高4位是3,代表该位置需要修改,不是3,则不用管它。因为这个数据块内存
对齐(方便找下个块)会补充一些垃圾数据
结构2的地址:是模块基址/句柄 +VirtualAddress(重定位表的偏移(目录6))+结构1的SizeofBlock
一个节区可能会有多个需要重定位的块(如果节区大于0x1000的话).
每个块 2字节数据个数=(块大小-8)除以2
最后是:如何修改重定位表中地址所指向的值,用地址指向的值 - 当前程序(exe or dll)的IMAGEBASE + 你准备贴程序的内存首地址(地址需要是页对齐的)。
重定位表修复后 不清楚IMAGEBASE需不需要修改....
版权声明:本文为Q324411601原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。