标准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
结构及成员含义如下:
#define IMAGE_SIZEOF_FILE_HEADER 20
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //程序运行平台
WORD NumberOfSections; //PE中节(IMAGE_SECTION_HEADER)的数量
DWORD TimeDateStamp; //时间戳,文件创建日期和时间
DWORD PointerToSymbolTable; //COFF符号表的文件偏移.(用于调试)
DWORD NumberOfSymbols; //符号表中的符号数量(用于调试)
WORD SizeOfOptionalHeader; //扩展PE头(IMAGE_OPTIONAL_HEADER)大小
WORD Characteristics; //PE文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
Machine
该成员用来指定PE文件运行的平台.定义如下:
#define IMAGE_FILE_MACHINE_UNKNOWN 0 // 适用于任何机器
#define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001
#define IMAGE_FILE_MACHINE_I386 0x014c // intel386处理器或后续兼容处理器
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS小尾处理器
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS小尾WCEv2处理器
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // Hitachi SH3处理器
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 // Hitachi SH3 DSP处理器
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // Hitachi SH4处理器
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // Hitachi SH5处理器
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM小尾处理器
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM或Thumb处理器
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARMv7(或更高)处理器的Thumb模式
#define IMAGE_FILE_MACHINE_AM33 0x01d3 // MatsushitaAM33处理器
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // PowerPC小尾处理器
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 // 带浮点支持的PowerPC处理器
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel Itanium处理器系列
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS16处理器
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // 带FPU的MIPS处理器
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // 带FPU的MIPS16处理器
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI字节码处理器
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // x64处理器
#define IMAGE_FILE_MACHINE_M32R 0x9041 // MatsushitaM32R小尾处理器
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
NumberOfSections
该成员表示了PE文件中节的总数(虽然是2字节,但是节最大值不能超过96),如果需要新增节或者合并节需要修改此值.这个值既不能比实际内存中存在的节多,也不能比它少,否则装载时会发生错误.
TimeDateStamp
该成员为时间戳,编译器创建此文件时的时间戳.32位存放的值是自1970年1月1日00:00时开始到创建时间为止的总秒数.该数值可以随意修改而不会影响程序运行.所以有的链接器在这里填入固定值,有的则随意写入任何值,这对用户创建的文件并没有实际的意义.另外这个时间值与操作系统文件属性里看到的三个时间(创建时间、修改时间、访问时间)也没有任何联系.
利用现成库函数可以计算出PE文件创建时间.
DWORD dwFileSize = 0;
PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
//strftime格式化时间显示
setlocale(LC_ALL, "zh-CN");
struct tm Time = { 0 };
gmtime_s(&Time, (time_t*)&pFil->TimeDateStamp);
char szBuf[0x64] = { 0 };
strftime(szBuf, sizeof(szBuf), "%#c", &Time);
printf("%s\n", szBuf);
SizeOfOptionalHeader
该成员指定了IMAGE_OPTIONAL_HEADER结构的大小即扩展PE头大小,32位PE文件扩展PE头大小默认为0xE0,64位PE文件扩展PE头大小默认为0xF0.可以自己定义这个值的大小(扩充大小后需要维持文件中的对齐特性).
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 | 大尾方式 |
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#Reserved words
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
00000000 00000000 00010000 00000000
- 当第1位为1时,表明此映像文件是合法的,可以运行.如果未设置此标志,表明出现了链接器错误.
- 当第7位为1时,表示文件为小尾方式,即内存中最低有效位LSB位于最高有效位MSB的前面.
- 当第10位为1时,如果此映像文件在可移动存储介质上,那么加载器将完全加载它并把它复制到内存交换文件中.
- 当第11位为1时,如果此映像文件在网络上,那么加载器也将完全加载它并把它复制到内存交换文件中.
- 当第13位为1时,表明此映像文件是动态链接库(DLL).这样的文件总被认为是可执行文件,尽管它们并不能直接运行.
0x0103转换为二进制为: 0000 0001 0000 0011 对应属性为IMAGE_FILE_RELOCS_STRIPPED(0),IMAGE_FILE_EXECUTABLE_IMAGE(1),IMAGE_FILE_32BIT_MACHINE(8).
代码定位IMAGE_FILE_HEADER如下
读取文件代码:
PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
{
//打开文件
FILE* pFile = fopen(szFilePath, "rb");
if (!pFile)
{
printf("FileToMem fopen Fail \r\n");
return NULL;
}
//获取文件长度
fseek(pFile, 0, SEEK_END); //SEEK_END文件结尾
DWORD Size = ftell(pFile);
fseek(pFile, 0, SEEK_SET); //SEEK_SET文件开头
//申请存储文件数据缓冲区
PCHAR pFileBuffer = (PCHAR)malloc(Size);
if (!pFileBuffer)
{
printf("FileToMem malloc Fail \r\n");
fclose(pFile);
return NULL;
}
//读取文件数据
fread(pFileBuffer, Size, 1, pFile);
//判断是否为可执行文件
if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
{
printf("Error: MZ \r\n");
fclose(pFile);
free(pFileBuffer);
return NULL;
}
if (*(PDWORD)(pFileBuffer + *(PDWORD)(pFileBuffer + 0x3C)) != IMAGE_NT_SIGNATURE)
{
printf("Error: PE \r\n");
fclose(pFile);
free(pFileBuffer);
return NULL;
}
if (dwFileSize)
{
*dwFileSize = Size;
}
fclose(pFile);
return pFileBuffer;
}
读取标准PE头数据代码
VOID PrintFilHeader()
{
//读取文件二进制数据
DWORD dwFileSize = 0;
PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
if (!pFileBuffer)
{
return;
}
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
printf("IMAGE_FILE_HEADER->Machine [0x%04x] \r\n", pFil->Machine);
printf("IMAGE_FILE_HEADER->NumberOfSections [0x%04x] \r\n", pFil->NumberOfSections);
//strftime格式化时间显示
setlocale(LC_ALL, "zh-CN");
struct tm Time = { 0 };
gmtime_s(&Time, (time_t*)&pFil->TimeDateStamp);
char szBuf[0x64] = { 0 };
strftime(szBuf, sizeof(szBuf), "%#c", &Time);
printf("IMAGE_FILE_HEADER->TimeDateStamp [0x%08x] [%s] \r\n", pFil->TimeDateStamp, szBuf);
printf("IMAGE_FILE_HEADER->PointerToSymbolTable [0x%08x] \r\n", pFil->PointerToSymbolTable);
printf("IMAGE_FILE_HEADER->NumberOfSymbols [0x%08x] \r\n", pFil->NumberOfSymbols);
printf("IMAGE_FILE_HEADER->SizeOfOptionalHeader [0x%04x] \r\n", pFil->SizeOfOptionalHeader);
printf("IMAGE_FILE_HEADER->Characteristics [0x%04x] \r\n", pFil->Characteristics);
}
原文链接:https://blog.csdn.net/m0_46125480/article/details/120954398