根据PE文件结构标准,DOS头在执行过程中需要检查MZ签名和根据e_lfanew字段定位NT头,因此无论中间的值如何奇怪,可以定位到NT头在地址00 00 00 10处。在upack打包程序中,upack通过修改中间字段使DOS头和NT头混合,e_lfanew字段同时也作为IMAGE_OPTIONAL_HEADER中的BaseofCode使用。 接下来说一下常见的关注点,但在本例中可能不涉及。NT文件头的SizeOfOptionalHeader(可选头大小)定义了标准头结束和节区表开始的位置。当SizeOfOptionalHeader被修改时,程序能够正常执行(其实是有时候可以,可以参考我写的另外一篇Windows加载文件全流程文档),但对于很多分析器像调试器、文件解析工具、反汇编器等将造成影响。修改目的大部分是为了反调试,但也有一些版本的upack壳中在此处扩展字段来插入解码代码。 可选头的NumberOfRvaAndSizes(数据目录项数),通常值为16(0x10),修改后可能干扰工具解析文件,运行时不受影响,但对于工具来说就是分析数据目录项数的解析标杆,可能出现无意义值或者显示不全。我在未打包程序上测试的可修改后正常运行的最小值为0x06。当修改值小于16时,后面的条目将无法被读取,变成程序加载时读取不到的地方。 严格根据e_lfanew + 4(签名) + 20(COFF头) + SizeofOptionalHeader计算节区头的起始位置,本例中计算得到10H + 4H + 14H + 148H = 170H,跳转至170地址处就是节区头。 upack打包程序有三个节区头,根据信息可以知道一些关键信息:节区SizeOfRawDataPointerToRawDataVirtualAdressVirtualSize10x000001F00x000000100x000010000x0000F00020x000053580x000002000x000100000x0000A00030x000001F00x000000100x0001A0000x00001000 在磁盘中upack打包程序的第1、3个节区是重合的,但是在内存中的VirtualAress和VirtualSize却是不同的,说明磁盘中的某个区域被映射了两次,在映射之初肯定是完全相同的,但是在内存中随着程序运行这两个节区一定会发生变化。 接下来查看程序的入口,几乎所有壳都会将原始代码跳转处作为壳代码,将真正的OEP藏在壳代码内部。AddressOfEntryPoint(RVA) = 0x00001018,计算出RAW = 0x18(要考虑FileAlinment影响,PointerToRawData = 10时,取整得0) 0x18地址处的代码片段为:BE B0 11 40 00 mov esi, 0x004011B0 ; 将地址 0x4011B0 加载到 ESI 寄存器AD lodsd ; 从 [ESI] 加载双字到 EAX,然后 ESI+450 push eax ; 将 EAX 的值压入栈FF 76 34 push dword ptr [esi+34h] ; 将 [ESI+0x34] 处的双字压入栈... 这里就是解壳代码。
[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于 2025-9-15 21:57
被Calparrot编辑
,原因:
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288481.htm
[原创]UPack壳的PE头部分析
104 浏览
0 回复
暂无回复,快来抢沙发吧!