为什么部分虚拟地址需要连续?

时间:2015-09-03 14:11:16

标签: windows reverse-engineering portable-executable

我目前正在开展工作,需要我从PE格式的可执行文件中删除该部分。首先,我刚刚删除了IMAGE_SECTION_HEADER,更改了IMAGE_FILE_HEADER中的NumberOfSections字段,重新计算了IMAGE_OPTIONAL_HEADER中的SizeOfImage / SizeOfHeaders,并将以下部分的原始地址移动了已删除部分的原始大小。但是,Windows拒绝加载文件,并显示错误消息" XXX不是有效的Win32应用程序"。我已经苦苦挣扎了一段时间,但试图通过删除部分的虚拟大小移动以下部分的虚拟地址,一切正常。

虚拟地址需要连续且没有任何差距的原因是什么?我试图阅读官方PE文档,但没有成功。我一直认为,只要SizeOfImage具有正确的值,单个部分的地址就不重要。

1 个答案:

答案 0 :(得分:2)

大多数应用程序不需要在各个部分之间有大的间隙 - 那些部分可以使用单独的DLL或通过VirtualAlloc动态分配内存。

更新:经过更多测试后,我发现部分之间的间隙必须是对齐下一部分以满足SectionAlignment所需的间隔。因此,间隔两个4096字节的区间0x20000字节需要将整个exe的SectionAlignment字段设置为0x20000。 (间隔为,例如,0x12000是不可能的。)这个128kB的间隙不会出现在进程的内存映射中,也不会消耗内存,但如果你试图在间隙内分配内存,VirtualAlloc仍会因ERROR_INVALID_ADDRESS而失败。

以下是GCC / MinGW的最小测试用例,证明 Win32 exe中的各个部分必须是连续的

testcase.S:

.global _main
.section .text
_main:
    push $1
    call _Sleep@4
    xor %eax, %eax
    ret

.section .bss
    .lcomm buf, NUMBYTES

这会生成一个有效的可执行文件:

gcc -m32 -Wl,--image-base=0x00400000 -Wl,-Ttext=0x00401000 -Wl,-Tbss=0x00402000 -DNUMBYTES=0xfe000 -Wl,--section-start=.idata=0x00500000 -s -nostartfiles -o contiguous.exe testcase.S

这会产生无效的可执行文件(gap.exe不是有效的Win32应用程序):

gcc -m32 -Wl,--image-base=0x00400000 -Wl,-Ttext=0x00401000 -Wl,-Tbss=0x00402000 -DNUMBYTES=0x200 -Wl,--section-start=.idata=0x00500000 -s -nostartfiles -o gap.exe testcase.S

与十六进制编辑器和objdump相比,两个文件之间只有16个字节的差异。改变了:

  1. 时间戳(4字节更改)。
  2. 校验和(4字节更改)。
  3. .bss部分的大小(8字节更改)。在contiguous.exe中,.bss部分为0xfe000字节大,而在gap.exe中.bss部分为0x200字节大,在它与.idata部分之间创建大小为0xfc000字节的间隙。