Windows 为什么节虚拟地址需要是连续的?

Windows 为什么节虚拟地址需要是连续的?,windows,reverse-engineering,portable-executable,Windows,Reverse Engineering,Portable Executable,我目前正在做一些工作,需要我以PE格式从可执行文件中删除部分。首先,我刚刚删除、更改了NumberOfSections字段,重新计算了SizeOfImage/SizeOfHeaders,并将以下部分的原始地址移动了删除部分的原始大小。但是,Windows拒绝加载带有错误消息“XXX不是有效的Win32应用程序”的文件。我已经挣扎了一段时间,但也试图通过删除部分的虚拟大小来移动以下部分的虚拟地址,一切正常 为什么虚拟地址需要是连续的,并且不能有任何间隙?我曾试图通读官方体育文件,但没有成功。我一直

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


为什么虚拟地址需要是连续的,并且不能有任何间隙?我曾试图通读官方体育文件,但没有成功。我一直认为,只要SizeOfImage具有正确的值,各个部分的地址就不重要了。

大多数应用程序不需要在部分之间有很大的间隙——那些确实需要的应用程序可以使用单独的DLL或通过动态分配内存

更新:经过更多的测试,我发现节之间的间隙必须是对齐下一节所需的间隙,以满足节对齐要求。因此,将两个4096字节的部分0x20000字节隔开需要将整个exe的SectionAlignment字段设置为0x20000。(比如说,0x12000的间隔是不可能的。)这个128kB的间隔不会出现在进程的内存映射中,也不会消耗内存,但是如果您试图在间隔内分配内存,VirtualAlloc仍然会失败,并出现错误\u INVALID\u 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 continuous.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字节的差异。改变的是:

  • 时间戳(4字节更改)
  • 校验和(4字节更改)
  • .bss节的大小(8字节更改)。在continuous.exe中,.bss节的大小为0xfe000字节,而在gap.exe中,.bss节的大小为0x200字节,从而在它和.idata节之间创建了一个大小为0xfc000字节的间隙

  • 你试过比较三个文件的
    dumpbin
    结果吗?我刚刚测试过-你可以在节的RVA之间找到差距。事实上,它们甚至可以重叠。但是,RVA必须始终按照顺序排列,如果您只是删除部分,这应该不会是一个问题。我可以问一下您是如何测试这一点的吗?我一直试图重现你提到的行为,但没有成功。