-
-
[原创]拿Win7系统下的notepad.exe文件用19个实例来猜测Win7PE加载器的一些行为
-
发表于:
2013-6-13 11:36
6537
-
[原创]拿Win7系统下的notepad.exe文件用19个实例来猜测Win7PE加载器的一些行为
这只是我之前的实例操作,总有哪天回过期的,我的结论如果有错误的地方,希望大牛拍砖、指正。
首先记下notepad.exe文件的四个值:
SizeOfCode(DWORD)包含代码节总长度(0x0000A800)
SizeOfInitializedData(DWORD)已初始化的数据总长度(0x00022400)
SizeOfUninitializedData(DWORD)未初始化的数据总长度(0)
AddressOfEntryPoint(DWORD)程序入口RVA(0x00003689 )
BaseOfCode(DWORD)代码的第一个字节的RVA(0x00001000)
BaseOfData(DWORD)数据的第一个字节的RVA(0x0000C000)
SectionAlignment(DWORD)节的内存对齐粒度(0x00001000)
FileAlignment(DWORD)节的文件对齐粒度(0x00000200 )
SizeOfImage(DWORD)PE内存中的映像尺寸(0x00030000)
实例操作1 :修改 SizeOfCode(DWORD)包含代码节总长度 值为 (0x0000A601,因为0x0000A601与0x0000A800按文件对齐值是一样的)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfCode 值 也许没有用于 PE文件格式的判定、也许PE文件格式的判定过程中这个值不需要按文件对齐值是一样的
实例操作2 :修改 SizeOfCode(DWORD)包含代码节总长度 值为 (0x0000A5FF,因为0x0000A5FF与0x0000A800按文件对齐值是不一样的)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfCode 值 应该没有用于 PE文件格式的判定
实例操作3 :修改 SizeOfCode(DWORD)包含代码节总长度 值为 (0)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfCode 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载
实例操作4 :修改 SizeOfCode(DWORD)包含代码节总长度 值为 (0x0000A801,因为0x0000A801与0x0000A800按文件对齐值是不一样的)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
**1 - 4实例操作结论:SizeOfCode 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载,它什么值应该都可以的,应该也不会影响调试器调试程序的,这个字段应该是被废弃了
实例操作5 :修改 SizeOfInitializedData(DWORD)已初始化的数据总长度 值为 (0x00022201,因为0x00022201与0x00022400按文件对齐值是一样的)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfInitializedData 值 也许没有用于 PE文件格式的判定、也许PE文件格式的判定过程中这个值不需要按文件对齐值是一样的
实例操作6 :修改 SizeOfInitializedData(DWORD)已初始化的数据总长度 值为 (0x000221FF,因为0x000221FF与0x00022400按文件对齐值是不一样的)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfInitializedData 值 也许没有用于 PE文件格式的判定、也许PE文件格式的判定过程中这个值不需要按文件对齐值是一样的
实例操作7 :修改 SizeOfInitializedData 值为 (0)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfInitializedData 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载
实例操作8 :修改 SizeOfInitializedData 值为 (0x00022401,因为0x00022401与0x0000A800按文件对齐值是不一样的)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
**5 - 8实例操作结论:SizeOfInitializedData 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载,它什么值应该都可以的,应该也不会影响调试器调试程序的,这个字段应该是被废弃了
实例操作9 :修改 SizeOfUninitializedData(DWORD)未初始化的数据总长度 值为 (0x00030001 比PE内存中的映像尺寸还大)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:SizeOfUninitializedData 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载,这个字段应该是被废弃了
**9实例操作结论:SizeOfUninitializedData 这个字段应该是被废弃了。
实例操作10 :修改 AddressOfEntryPoint(DWORD)程序入口RVA 值为 (0)
结果:notepad.exe 启动错误,“xxx 指令引用的 xxx 内存。该内存不能为写”。MDebug调试器启动调试直接停在ntdll.dll领空调用RtlImageNtHeaderEx 后的反汇编代码处,加载的模块列表只有notepad.exe和ntdll.dll
猜想:AddressOfEntryPoint 值不影响PE文件格式的判断,它应该不只用于它的本意,PE加载器应该有判断这个RVA的是否存在,因为他是EXE文件。
实例操作11 :修改 AddressOfEntryPoint(DWORD)程序入口RVA 值为 (0x0000C000 这个是数据节的RVA)
结果:notepad.exe 启动错误,“xxx 指令引用的 xxx 内存。该内存不能为写”。MDebug调试器启动调试直接打印加载模块一闪就关闭了。用OD打开就可以显示入口反汇编指令了。
猜想:程序应该在 AddressOfEntryPoint 处执行到指令错误了。
**10 - 11 实例操作结论:AddressOfEntryPoint(DWORD)程序入口RVA,对于EXE必须存在、不管值是指向什么属性的节。(这个猜测有待进一步验证)
实例操作12 :修改 BaseOfCode(DWORD)代码的第一个字节的RVA 值为 (0或1)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:BaseOfCode 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载,这个字段应该是被废弃了
实例操作13 :修改 BaseOfData(DWORD)数据的第一个字节的RVA 值为 (0或1)
结果:notepad.exe 正常启动,MDebug调试器启动调试没有发现问题
猜想:BaseOfData 值 肯定没有用于 PE文件格式的判定、也不影响PE加载器对PE文件的加载,这个字段应该是被废弃了
**12 - 13 实例操作结论:BaseOfCode 和 BaseOfData 应该是都被废弃了
查看.text 节头数据
Misc.VirtualSize 值:0x0000A68C 原始节数据长度
VirtualAddress 值:0x00001000 节的RVA(DWORD)
SizeOfRawData 值:0x0000A800 节在文件中对齐后大小
PointerToRawData 值:0x00000400 节在文件中的偏移地址(DWORD)
实例操作14 :修改.text 节头数据 Misc.VirtualSize 为
结果:notepad.exe 正常启动。
猜想:因为0x0000A68C和0x0000A800按内存对齐的值是一样的,所以只要有一个可以让PE加载器算出该节的正确内存映像尺寸即可。
实例操作15 :恢复Misc.VirtualSize数据,修改.text 节头数据 SizeOfRawData 为 0
结果:错误对话框提示 notepad.exe 程序无法正常启动,MDebug调试器没有办法启动调试
猜想:PE加载器应该是没有怀疑PE文件格式有问题,但是在把.text 节数据读进映像时发现没有数据
实例操作16 :修改.text 节头数据 SizeOfRawData 为 0x00003689 - 0x00001000 = 0x00002689
结果:还是错误对话框提示 notepad.exe 程序无法正常启动,MDebug调试器没有办法启动调试
猜想:PE加载器应该是没有怀疑PE文件格式有问题,但是在把.text 节数据读进映像时发现什么不对了呢?
实例操作17 :修改.text 节头数据 SizeOfRawData 为 0x00003000(比0x00002689大一点看看,但是按内存对齐值是一样的)
结果:还是错误对话框提示 notepad.exe 程序无法正常启动,MDebug调试器没有办法启动调试
猜想:PE加载器应该是没有怀疑PE文件格式有问题,但是在把.text 节数据读进映像时可能是发现 SizeOfRawData 值并按文件对齐后的值加上 PointerToRawData 的和值不等于后面一个节.data的 PointerToRawData ,所以节头表需要有最后一项全部为0
实例操作18 :修改.text 节头数据 SizeOfRawData 为 0x0000A601(0x0000A601 与 0x0000A800 按文件对齐的值是一样的)
结果:notepad.exe 正常启动。菜单功能我没有发现问题。MDebug调试器调试时查看内存.text节的偏移0x0000A601以后的0x200数据证明是从文件中读取的。
说明:实例操作4 的猜想是对的。
**14 - 18 实例操作可以确定结果:PE加载器在把一个节数据读进映像时,需要检查 SizeOfRawData 按文件对齐后加上 PointerToRawData 必须等于后面一个节的 PointerToRawData ,PE加载器是要重新计算 SizeOfRawData 按文件对齐后的长度,然后把文件节数据读进映像内存。而对于 Misc.VirtualSize 的值是多少已经不重要了,应该只要不大于 SizeOfRawData 值即可,是 0 都无所谓了。
再往下查看.data 节头数据
Misc.VirtualSize 值:0x00002164 原始节数据长度(DWORD)此字段已经不准确
VirtualAddress 值:0x0000C000 节的RVA(DWORD)
SizeOfRawData 值:0x00001000 节在文件中对齐后大小(DWORD)
PointerToRawData 值:0x0000AC00 节在文件中的偏移地址(DWORD)
发现 Misc.VirtualSize 的值尽然大于 SizeOfRawData 的值 ?
计算一下 0x00002164 按内存对齐的大小是 0x00003000 。加上 VirtualAddress 正好等于下一个节.rsrc 节的 VirtualAddress (0x0000F000) 。关注 SizeOfRawData 按内存对齐的大小是 0x00001000 而不是 0x00003000 ,好就来看看实例操作6 。
实例操作19 :修改.data 节的 Misc.VirtualSize 为 0x00001FFF (因为 0x00001FFF 的内存对齐值只有 0x00002000)
结果:notepad.exe 就没有办法启动,错误提示:notepad.exe不是有效的 Win32 应用程序
说明:PE加载器应该在判断一个PE格式文件的时候一定有检查:在 Misc.VirtualSize 与 SizeOfRawData 之间取大值,然后按内存对齐的值加上 VirtualAddress 必须等于后面节的 VirtualAddress ,否则判定不是有效的 Win32 应用程序。如果到最后一个节会怎么样?不用猜测 肯定是: 最后一个节的 VirtualAddress + (Misc.VirtualSize 与 SizeOfRawData 之间取大并按内存对齐值) == SizeOfImage(DWORD)PE内存中的映像尺寸,如果这个条件不成立,肯定判定不是有效的 Win32 应用程序。
**总结14 - 19实例操作得出最后结论只有3个:
1.PE加载器判定为有效的 Win32 应用程序一定至少检查:每一个节的 VirtualAddress + (Misc.VirtualSize 与 SizeOfRawData 之间取大并按内存对齐值) == 后面节的 VirtualAddress ,对于最后一个节:最后一个节的 VirtualAddress + (Misc.VirtualSize 与 SizeOfRawData 之间取大并按内存对齐值) == SizeOfImage(DWORD)PE内存中的映像尺寸
2.PE加载器从文件节读取数据到映像节的数据长度是:SizeOfRawData 按文件对齐后的长度
3.各个节的 Misc.VirtualSize 值不必是按内存对齐的值 , 各个节的 SizeOfRawData 值也不必是按文件对齐的值,只要他们的组合符合如下两个公式即可:
Misc.VirtualSize 与 SizeOfRawData 取大后并按内存对齐的值 == 该节在内存中的实际映像尺寸
SizeOfRawData 按文件对齐的值 == 该节数据在PE文件中占用的实际字节数
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)