标准PE头IMAGE_FILE_HEADER紧跟在PE标记后,即IMAGE_NT_HEADERS.Signature + 4的位置.由此位置开始的20个字节为数据结构标准PE头IMAGE_FILE_HEADER的内容.

该结构在微软的官方文档中被称为标准通用对象文件格式(Common Object File Format COFF)头.它记录了PE文件的全局属性,如该PE文件运行的平台、PE文件类型(EXE / DLL)、文件中存在的节的总数等.

IMAGE_FILE_HEADER

结构及成员含义如下:

  1. #define IMAGE_SIZEOF_FILE_HEADER 20
  2. typedef struct _IMAGE_FILE_HEADER {
  3. WORD Machine; //程序运行平台
  4. WORD NumberOfSections; //PE中节(IMAGE_SECTION_HEADER)的数量
  5. DWORD TimeDateStamp; //时间戳,文件创建日期和时间
  6. DWORD PointerToSymbolTable; //COFF符号表的文件偏移.(用于调试)
  7. DWORD NumberOfSymbols; //符号表中的符号数量(用于调试)
  8. WORD SizeOfOptionalHeader; //扩展PE头(IMAGE_OPTIONAL_HEADER)大小
  9. WORD Characteristics; //PE文件属性
  10. } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

Machine

该成员用来指定PE文件运行的平台.定义如下:

  1. #define IMAGE_FILE_MACHINE_UNKNOWN 0 // 适用于任何机器
  2. #define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001
  3. #define IMAGE_FILE_MACHINE_I386 0x014c // intel386处理器或后续兼容处理器
  4. #define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
  5. #define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS小尾处理器
  6. #define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
  7. #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS小尾WCEv2处理器
  8. #define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
  9. #define IMAGE_FILE_MACHINE_SH3 0x01a2 // Hitachi SH3处理器
  10. #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 // Hitachi SH3 DSP处理器
  11. #define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
  12. #define IMAGE_FILE_MACHINE_SH4 0x01a6 // Hitachi SH4处理器
  13. #define IMAGE_FILE_MACHINE_SH5 0x01a8 // Hitachi SH5处理器
  14. #define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM小尾处理器
  15. #define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM或Thumb处理器
  16. #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARMv7(或更高)处理器的Thumb模式
  17. #define IMAGE_FILE_MACHINE_AM33 0x01d3 // MatsushitaAM33处理器
  18. #define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // PowerPC小尾处理器
  19. #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 // 带浮点支持的PowerPC处理器
  20. #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel Itanium处理器系列
  21. #define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS16处理器
  22. #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
  23. #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // 带FPU的MIPS处理器
  24. #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // 带FPU的MIPS16处理器
  25. #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
  26. #define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
  27. #define IMAGE_FILE_MACHINE_CEF 0x0CEF
  28. #define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI字节码处理器
  29. #define IMAGE_FILE_MACHINE_AMD64 0x8664 // x64处理器
  30. #define IMAGE_FILE_MACHINE_M32R 0x9041 // MatsushitaM32R小尾处理器
  31. #define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
  32. #define IMAGE_FILE_MACHINE_CEE 0xC0EE

NumberOfSections

该成员表示了PE文件中节的总数(虽然是2字节,但是节最大值不能超过96),如果需要新增节或者合并节需要修改此值.这个值既不能比实际内存中存在的节多,也不能比它少,否则装载时会发生错误.
image.png

TimeDateStamp

该成员为时间戳,编译器创建此文件时的时间戳.32位存放的值是自1970年1月1日00:00时开始到创建时间为止的总秒数.该数值可以随意修改而不会影响程序运行.所以有的链接器在这里填入固定值,有的则随意写入任何值,这对用户创建的文件并没有实际的意义.另外这个时间值与操作系统文件属性里看到的三个时间(创建时间、修改时间、访问时间)也没有任何联系.
image.png
利用现成库函数可以计算出PE文件创建时间.

  1. DWORD dwFileSize = 0;
  2. PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
  3. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
  4. PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
  5. PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
  6. //strftime格式化时间显示
  7. setlocale(LC_ALL, "zh-CN");
  8. struct tm Time = { 0 };
  9. gmtime_s(&Time, (time_t*)&pFil->TimeDateStamp);
  10. char szBuf[0x64] = { 0 };
  11. strftime(szBuf, sizeof(szBuf), "%#c", &Time);
  12. printf("%s\n", szBuf);

SizeOfOptionalHeader

该成员指定了IMAGE_OPTIONAL_HEADER结构的大小即扩展PE头大小,32位PE文件扩展PE头大小默认为0xE0,64位PE文件扩展PE头大小默认为0xF0.可以自己定义这个值的大小(扩充大小后需要维持文件中的对齐特性).
image.png

Characteristics

该成员为PE文件属性标志字段(是否可执行,是否为DLL等等)此值每一位都代表不同含义,如下所示:

数据位 常量符号 常量值 为1时的含义
0 IMAGE_FILE_RELOCS_STRIPPED 0x0001 文件中不存在重定位信息
1 IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 文件是一个exe
2 IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 不存在行信息
3 IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 不存在符号信息
4 IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 调整工作集
5 IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 应用程序可处理大于2GB的地址
6 此标志保留
7 IMAGE_FILE_BYTES_REVERSED_LO 0x0080 小尾方式
8 IMAGE_FILE_32BIT_MACHINE 0x0100 只在32位平台上运行
9 IMAGE_FILE_DEBUG_STRIPPED 0x0200 不包含调试信息
10 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 不能从可移动盘运行
11 IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 不能从网络运行
12 IMAGE_FILE_SYSTEM 0x1000 系统文件(如驱动程序),不能直接运行
13 IMAGE_FILE_DLL 0x2000 文件是一个DLL
14 IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 文件不能在多处理器的计算机上运行
15 IMAGE_FILE_BYTES_REVERSED_HI 0x8000 大尾方式
  1. #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
  2. #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references).
  3. #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
  4. #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
  5. #define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set
  6. #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
  7. #Reserved words
  8. #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
  9. #define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
  10. #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
  11. #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file.
  12. #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file.
  13. #define IMAGE_FILE_SYSTEM 0x1000 // System File.
  14. #define IMAGE_FILE_DLL 0x2000 // File is a DLL.
  15. #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
  16. #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
  17. 00000000 00000000 00010000 00000000
  • 当第1位为1时,表明此映像文件是合法的,可以运行.如果未设置此标志,表明出现了链接器错误.
  • 当第7位为1时,表示文件为小尾方式,即内存中最低有效位LSB位于最高有效位MSB的前面.
  • 当第10位为1时,如果此映像文件在可移动存储介质上,那么加载器将完全加载它并把它复制到内存交换文件中.
  • 当第11位为1时,如果此映像文件在网络上,那么加载器也将完全加载它并把它复制到内存交换文件中.
  • 当第13位为1时,表明此映像文件是动态链接库(DLL).这样的文件总被认为是可执行文件,尽管它们并不能直接运行.

image.png
0x0103转换为二进制为: 0000 0001 0000 0011 对应属性为IMAGE_FILE_RELOCS_STRIPPED(0),IMAGE_FILE_EXECUTABLE_IMAGE(1),IMAGE_FILE_32BIT_MACHINE(8).

代码定位IMAGE_FILE_HEADER如下

  1. 读取文件代码:
  2. PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
  3. {
  4. //打开文件
  5. FILE* pFile = fopen(szFilePath, "rb");
  6. if (!pFile)
  7. {
  8. printf("FileToMem fopen Fail \r\n");
  9. return NULL;
  10. }
  11. //获取文件长度
  12. fseek(pFile, 0, SEEK_END); //SEEK_END文件结尾
  13. DWORD Size = ftell(pFile);
  14. fseek(pFile, 0, SEEK_SET); //SEEK_SET文件开头
  15. //申请存储文件数据缓冲区
  16. PCHAR pFileBuffer = (PCHAR)malloc(Size);
  17. if (!pFileBuffer)
  18. {
  19. printf("FileToMem malloc Fail \r\n");
  20. fclose(pFile);
  21. return NULL;
  22. }
  23. //读取文件数据
  24. fread(pFileBuffer, Size, 1, pFile);
  25. //判断是否为可执行文件
  26. if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
  27. {
  28. printf("Error: MZ \r\n");
  29. fclose(pFile);
  30. free(pFileBuffer);
  31. return NULL;
  32. }
  33. if (*(PDWORD)(pFileBuffer + *(PDWORD)(pFileBuffer + 0x3C)) != IMAGE_NT_SIGNATURE)
  34. {
  35. printf("Error: PE \r\n");
  36. fclose(pFile);
  37. free(pFileBuffer);
  38. return NULL;
  39. }
  40. if (dwFileSize)
  41. {
  42. *dwFileSize = Size;
  43. }
  44. fclose(pFile);
  45. return pFileBuffer;
  46. }
  47. 读取标准PE头数据代码
  48. VOID PrintFilHeader()
  49. {
  50. //读取文件二进制数据
  51. DWORD dwFileSize = 0;
  52. PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
  53. if (!pFileBuffer)
  54. {
  55. return;
  56. }
  57. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
  58. PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
  59. PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
  60. printf("IMAGE_FILE_HEADER->Machine [0x%04x] \r\n", pFil->Machine);
  61. printf("IMAGE_FILE_HEADER->NumberOfSections [0x%04x] \r\n", pFil->NumberOfSections);
  62. //strftime格式化时间显示
  63. setlocale(LC_ALL, "zh-CN");
  64. struct tm Time = { 0 };
  65. gmtime_s(&Time, (time_t*)&pFil->TimeDateStamp);
  66. char szBuf[0x64] = { 0 };
  67. strftime(szBuf, sizeof(szBuf), "%#c", &Time);
  68. printf("IMAGE_FILE_HEADER->TimeDateStamp [0x%08x] [%s] \r\n", pFil->TimeDateStamp, szBuf);
  69. printf("IMAGE_FILE_HEADER->PointerToSymbolTable [0x%08x] \r\n", pFil->PointerToSymbolTable);
  70. printf("IMAGE_FILE_HEADER->NumberOfSymbols [0x%08x] \r\n", pFil->NumberOfSymbols);
  71. printf("IMAGE_FILE_HEADER->SizeOfOptionalHeader [0x%04x] \r\n", pFil->SizeOfOptionalHeader);
  72. printf("IMAGE_FILE_HEADER->Characteristics [0x%04x] \r\n", pFil->Characteristics);
  73. }

原文链接:https://blog.csdn.net/m0_46125480/article/details/120954398