PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头1
本文将讨论PE文件中非常重要的一部分信息。(转载请指明出处)
首先说一下VC中对应的数据结构。“签名、COFF文件头和可选文件头”这三部分信息组合在一起是一个叫IMAGE_NT_HEADERS的结构体。
Machine字段为0x014C,其对应的信息是“Intel 386或其后续处理器及兼容处理器”。
NumberOfSections是个非常重要的字段,它表示节的数目。PE文件是由一系列“节”构成的,比较常见的是.text和.data等节,这样的独立的区块是用来存储“代码”、“数据”和“资源”等信息的。如xp上notepad,从数据中我们可以看到它有3个节,我们用其他工具分析得到它确实存在如下3个节。
TimeDateStamp字段记录的是文件创建时间离1970年1月1日00:00的秒数。PointerToSymbolTable字段记录了该PE文件中调试信息符号表。目前微软推荐是:将映像文件调试符号表信息独立的放在PDB文件中,所以不会在PE文件中再保存调试符号表信息,于是这个字段应该为0。
NumberOfSymbols字段记录了该PE文件中调试信息符号表元素个数。对于映像文件,该字段为0,,理由在PointerToSymbolTable中已经说明。对于Object文件,可以通过NumberOfSymbols和PointerToSymbolTable找到字符串表,因为字符串表紧跟在符号表之后。
SizeOfOptionalHeader字段用于描述“可选文件头”的大小。我们之后会看到“可选文件头”的大小是固定的,但是此处还是要指定该PE文件使用了多少“可选文件头”,因为可能部分数据是该PE文件所不会使用的,链接器也不会将这样的数据写入PE文件。这儿就引入一个问题,就是我们不能从“签名”位置开始,就直接memcpy一段IMAGE_NT_HEADERS大小的空间到一个IMAGE_NT_HEADERS对象中。因为“可选文件头”还要看“COFF文件头”中的SizeOfOptionalHeader数据。
Characteristics字段用于标记该文件属性,notepad.exe该字段值为0x010F。下面我们来解释下该组合属性
标志 值 说明 IMAGE_FILE_RELOCS_STRIPPED0x0001仅适用于映像文件。它表明此文件不包含机制重定位信息,于是它只能被加载到其首选基地址。如果首选基地址不可用,则加载器会报错。链接器默认会移除可执行文件中的重定位信息。一般情况下,Exe文件会设置该值(如notepad.exe,但ntoskrnl.exe就没设置),而因为DLL文件为了其良好的兼容性是不会去设置这个值的(如Kernel32.dll、User32.dll等)。IMAGE_FILE_EXECUTABLE_IMAGE0x0002仅适用于映像文件。它用于表明该文件是合法的,可以被运行。如果没有设置,则代表链接出现问题。这个一般都会设置。IMAGE_FILE_LINE_NUMS_STRIPPED0x0004COFF行号信息已经被移除。不赞成使用该标志。但是我发现notepad.exe、Kernel32.dll、User32.dll等都设置了该标志。而一般我们编译的PE文件是不设置该项的。IMAGE_FILE_LOCAL_SYMS_STRIPPED0x0008COFF符号表中有关局部符号的项已经被移除。不赞成使用该标志。但是我发现notepad.exe、Kernel32.dll、User32.dll等都设置了该标志。而一般我们编译的PE文件是不设置该项的。IMAGE_FILE_AGGRESSIVE_WS_TRIM0x0010该标志已经被废弃。IMAGE_FILE_LARGE_ADDRESS_ AWARE0x0020应用程序可以处理大于2GB的地址。 0x0040为未来保留的字段。IMAGE_FILE_BYTES_REVERSED_LO0x0080小尾,LSB在MSB前面。不赞成使用该标志。windows xp就是小尾。IMAGE_FILE_32BIT_MACHINE0x0100适用于32位系统。我的xp系统上DLL和Exe文件基本都设置了该标志。IMAGE_FILE_DEBUG_STRIPPED0x0200调试信息已经从该映像文件中移除。IMAGE_FILE_REMOVABLE_RUN_ FROM_SWAP0x0400如果该文件是在移动介质上,需要将其完全加载到交换文件中。IMAGE_FILE_NET_RUN_FROM_SWAP0x0800如果该文件是在网络介质上,需要将其完全加载到交换文件中。IMAGE_FILE_SYSTEM0x1000该映像文件是一个系统文件,不是一个用户文件。IMAGE_FILE_DLL0x2000此文件是DLL文件。IMAGE_FILE_UP_SYSTEM_ONLY0x4000该文件仅能运行于单处理机器上。IMAGE_FILE_BYTES_REVERSED_HI0x8000大尾,LSB在MSB后面。
我观察了我系统上几个文件,一般Sys和Exe的该属性为0x010E或者0x010F。DLL文件该属性一般为0x210E。DLL文件一般不会设IMAGE_FILE_RELOCS_STRIPPED,因为它为了良好的兼容性,不能设置它必须要被加载的地址。一个Exe可能会加载多个DLL,如果系统“不小心”把某个DLL加载到0x70000000,那么如果有某个DLL设置了IMAGE_FILE_RELOCS_STRIPPED并将其首选加载地址正好也设置为0x70000000,那么系统为该Exe加载这个DLL将会失败。DLL文件肯定要设置IMAGE_FILE_DLL。所以即使某个DLL文件的后缀名改了,你可以结合这个“特征码”来还原其真面目。IMAGE_FILE_32BIT_MACHINE该标志可以用于标志这个文件是适用于32位系统,于是可以通过该状态位判断文件的平台特性。
