上一帖子介绍PE文件大体由PE文件头与节表组成,
PE文件头由DOS头+pe标识+标准PE头+可选PE头+节表+节内容组成。
这帖子在前面帖子代码基础上编写标准PE头方读取,并介绍标准PE文件头结构成员含义。
例程界面如下:
PE文件结构之标准PE头介绍及编程读取
通过界面按钮打开一个可执行文件后,可以点击标准PE头按钮,显示从PE文件的标准PE头读取的信息。
标准PE头对应为一个结构体类型变量IMAGE_FILE_HEADER。
在上一帖子介绍pe标识+标准PE头+可选PE头为PE头部分,对应结构体为IMAGE_NT_HEADERS。
标准PE头在PE文件中,开始地址由DOS_MZ成员e_lfanew指定。
那么PE头的定位代码,在例程中就可以这样写:
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG)pDosHeader+pDosHeader->e_lfanew);
标准PE头成员变量就可以这样访问:
pNtHeaders->FileHeader.Machine;
pDosHeader为DOS头指针,在上一帖子中有介绍是在文件打开时获取。
下面代码为标准PE头成员显示函数:
- void CFileHeaderDlg::UpdateData(PIMAGE_DOS_HEADER pDosHeader,bool bSetGet)
- {
- if(pDosHeader == NULL)
- return;
- PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG)pDosHeader+pDosHeader->e_lfanew);
- CString sText;
- if(bSetGet)
- {
- sText.Format("%04X",pNtHeaders->Signature);
- SetDlgItemText(IDC_EDIT11,sText);
- sText.Format("%04X",pNtHeaders->FileHeader.Machine);
- SetDlgItemText(IDC_EDIT1,sText);
- sText.Format("%04X",pNtHeaders->FileHeader.NumberOfSections);
- SetDlgItemText(IDC_EDIT2,sText);
- sText.Format("%08X",pNtHeaders->FileHeader.TimeDateStamp);
- SetDlgItemText(IDC_EDIT3,sText);
- sText.Format("%08X",pNtHeaders->FileHeader.PointerToSymbolTable);
- SetDlgItemText(IDC_EDIT4,sText);
- sText.Format("%08X",pNtHeaders->FileHeader.NumberOfSymbols);
- SetDlgItemText(IDC_EDIT5,sText);
- sText.Format("%04X",pNtHeaders->FileHeader.SizeOfOptionalHeader);
- SetDlgItemText(IDC_EDIT6,sText);
- sText.Format("%04X",pNtHeaders->FileHeader.Characteristics);
- SetDlgItemText(IDC_EDIT7,sText);
- }
- else
- {
- }
- }
复制代码 主要还是结构体IMAGE_FILE_HEADER成员的含义理解:
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
1.Machine:
单字长度, 用来指定PE文件运行平台。有哪些平台可支持,或有哪些值可供使用?
例程对应代码如下:
- m_Combox.AddString("IMAGE_FILE_MACHINE_UNKNOWN |0X00");
- m_Combox.AddString("IMAGE_FILE_MACHINE_I386 |0x014c");
- m_Combox.AddString("IMAGE_FILE_MACHINE_R3000 |0x0162");
- m_Combox.AddString("IMAGE_FILE_MACHINE_R4000 |0x0166");
- m_Combox.AddString("IMAGE_FILE_MACHINE_R10000 |0x0168");
- m_Combox.AddString("IMAGE_FILE_MACHINE_WCEMIPSV2 |0x0169");
- m_Combox.AddString("IMAGE_FILE_MACHINE_ALPHA |0x0184");
- m_Combox.AddString("IMAGE_FILE_MACHINE_SH3 |0x01a2");
- m_Combox.AddString("IMAGE_FILE_MACHINE_SH3DSP |0x01a3");
- m_Combox.AddString("IMAGE_FILE_MACHINE_SH3E |0x01a4");
- m_Combox.AddString("IMAGE_FILE_MACHINE_SH4 |0x01a6");
- m_Combox.AddString("IMAGE_FILE_MACHINE_SH5 |0x01a8");
- m_Combox.AddString("IMAGE_FILE_MACHINE_ARM |0x01c0");
- m_Combox.AddString("IMAGE_FILE_MACHINE_THUMB |0x01c2");
- m_Combox.AddString("IMAGE_FILE_MACHINE_AM33 |0x01d3");
- m_Combox.AddString("IMAGE_FILE_MACHINE_POWERPC |0x01F0");
- m_Combox.AddString("IMAGE_FILE_MACHINE_POWERPCFP |0x01f1");
- m_Combox.AddString("IMAGE_FILE_MACHINE_IA64 |0x0200");
- m_Combox.AddString("IMAGE_FILE_MACHINE_MIPS16 |0x0266");
- m_Combox.AddString("IMAGE_FILE_MACHINE_ALPHA64 |0x0284");
- m_Combox.AddString("IMAGE_FILE_MACHINE_MIPSFPU |0x0366");
- m_Combox.AddString("IMAGE_FILE_MACHINE_MIPSFPU16 |0x0466");
- m_Combox.AddString("IMAGE_FILE_MACHINE_TRICORE |0x0520");
- m_Combox.AddString("IMAGE_FILE_MACHINE_CEF |0x0CEF");
- m_Combox.AddString("IMAGE_FILE_MACHINE_EBC |0x0EBC");
- m_Combox.AddString("IMAGE_FILE_MACHINE_AMD64 |0x8664");
- m_Combox.AddString("IMAGE_FILE_MACHINE_M32R |0x9041");
- m_Combox.AddString("IMAGE_FILE_MACHINE_CEE |0xC0EE");
复制代码 例如选择"IMAGE_FILE_MACHINE_I386 |0x014c",
例程会提取数值0X014C赋值给IMAGE_FILE_HEADER的成员变量Machine。
那么这些如IMAGE_FILE_MACHINE_I386的含义是什么,表示什么处理器呢?
下面截图于一PDF文件,这里就不码字了:
PE文件结构之标准PE头介绍及编程读取
2.NumberOfSections:
PE文件中存在的节的个数,单字长度。
在XP系统中,可以没有节,但数值不可小于1,或大于96。
仅能等于内存中存在的节个数,不然系统装载PE文件时会提示错误。
如果我们想在PE文件增,删节,得记得对应修改一下此数值。
3.TimeDateStamp:
双字长度,编译器在创建此文件时填写的时间戳,表示从1970年,1月1日,0时,0分,0秒开始,到文件创建时的总的秒数。
此数值无意义,可任意修改。要注意的是此值与文件属性:创建时间,修改时间,访问时间无关。
如果想知道时间戳与年月日,时分秒间如何相互转换,可以下载与参考例程源代码。
如上面第一图片,点击界面两个按钮,可以进行相互间转换。
4.PointerToSymbolTable,NumberOfSymbols:
PointerToSymbolTable双字长度,COFF符号表文件偏移,如无COFF符号表,此值为0。
对于映像文件,此值为0,微软已不建议使用。
NumberOfSymbols双字长度,符号表中元数数目。
这两成员已无用,主要用于调试,可不用关注。
COFF:Common Object File Format标准通用文件对象,记录了PE文件的全局属性。
5.SizeOfOptionalHeader:
单字,指定可选PE头(对应结构体IMAGE_OPTIONAL_HEADER32)的长度。
默认值为0X00E0,如果是64位PE文件,默认值则为0x00f0.
可以修改此值,但要自行保证文件中IMAGE_OPTIONAL_HEADER32大小与此值相同。
以及满足PE文件对齐特征。
6.Characteristics:
单字长度,表示文件属性标识字段。以二进制位的形式来使用,共16个属性。
这是一个很重要的字段,系统会根据此值来决定对文件的装载方式。
对于一般可执行文件,此值一般是0x10f,
对于DLL文件,一般是0x210e.
那么这16个进进制位,每个位的含义是什么呢?
可以参考下面图片。
PE文件结构之标准PE头介绍及编程读取
例程中有实现对每个位的读取与设置,
可以下载例程来参考使用。
PE文件结构之标准PE头介绍及编程读取
以上就是标准PE头结果成员 的含义与读取的关键代码。
自己编写代码来读取一个可执行文件的每个部分是最好的学习PE文件。
例程下载地址:
下一帖子会介绍可选PE头的读取与成员变量的含义。
|