工控编程吧
标题:
PE文件结构之节表的组成及编程读取
[打印本页]
作者:
qq263946146
时间:
2019-12-23 15:11
标题:
PE文件结构之节表的组成及编程读取
前面几个帖子介绍了PE文件头几个部分的组成及代码上的读取。
这里介绍PE头最后一个部分的读取,节表的读取及成员含义。
下图可以帮助回顾下PE文件的大概组成。
(, 下载次数: 0)
上传
点击文件名下载附件
这帖子介PE文件头最后组成部分:节表。
节表信息读取代码在前面帖子基础上添加实现,例程界面如下:
(, 下载次数: 2)
上传
点击文件名下载附件
打开一PE文件后,点击界面的节表按钮,可以显示PE文件的节表信息。
节表信息由报表形式显示,双击报表单元格可以弹出窗口进行内容的修改。
节表紧跟在PE文件头后,也就是结构体IMAGE_NT_HEADER后就为节表数据,在编程上还是很容易定位。
节表是由多个节表项组成的,每个节表项对应一个结构体IMAGE_SECTION_HEADER.
具体由几个节表项组成?
它由标准PE头中的成员NumberOfSections指定。
那么节表的定位与节表项个数如何通过代码得到呢?
可以参考例程代码:
void CSectionHeaderDlg::UpdateData(PIMAGE_DOS_HEADER pDosHeader,bool bSetGet)
{
if(pDosHeader == NULL)
return;
PIMAGE_NT_HEADERS pNtHeader=(PIMAGE_NT_HEADERS )((char *)pDosHeader+pDosHeader->e_lfanew);
int nSectionNum = pNtHeader->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
复制代码
例如程序中通过PE文件的dos_mz头获取pe头,pe头中的标准pe头成员NumberOfSections就为节表项个数。通过宏IMAGE_FIRST_SECTION可以快速获取第一个节表项地址。
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
此宏可以选择后按F12定位到定义:
#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \
((ULONG_PTR)(ntheader) + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + ((ntheader))->FileHeader.SizeOfOptionalHeader ))
复制代码
宏表示3部分相加和。
1、IMAGE_NT_HEADERS的起始地址
2、IMAGE_OPTIONAL_HEADER32 (PE扩展头)在IMAGE_NT_HEADERS中的偏移
3、IMAGE_OPTIONAL_HEADER32的大小
这里
FIELD_OFFSET宏输出可选PE头OptionalHeader在IMAGE_NT_HEADERS结构体中的偏移。
后两个加起来的大小恰好就是IMAGE_NT_HEADERS的大小,再跟第一个相加就得到Session Table的地址。
这里没有直接使用sizeof(
IMAGE_NT_HEADERS
)来偏移指向节表地址,
是因为IMAGE_OPTIONAL_HEADER32(OptinalHeader)的大小不固定,
默认情况,
32位PE文件,这个值等于00e0h,
64位PE文件,这个值大小为00f0h。
还可以由我们通过标准PE头的SizeOfOptionalHeader 字段指定。
可以定位第一个节表项
IMAGE_SECTION_HEADER,以及知道节表项IMAGE_SECTION_HEADER的个数,
就可以循环访问每个节表项的成员了。
例程中通过一个函数将PE文件中全部节表项成员都显示在了界面上:
<blockquote>void CSectionHeaderDlg::UpdateData(PIMAGE_DOS_HEADER pDosHeader,bool bSetGet)
复制代码
代码是实现了每个节表项IMAGE_SECTION_HEADER成员的访问与显示或修改。但节表项每个成员的含义是什么呢?
IMAGE_SECTION_HEADER的定义如下:
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
复制代码
1.Name:
8字长长度。
表示节表项名称,默认以'.'结尾,如“.text”。名称无意义,可随意,但要保证每个节表项名称不重复。
另外要注意读取时请自行添加字符串结束标识‘/0'.
2.Misc:
双字长度。
共用体结构,其VirtualSize表示节数据在没有进行对齐处理前的实际大小。
3.VirtualAddress:
双字长度。
节的RVA地址。
4.SizeOfRawData:
双字长度。
文件对齐后,节大小。
5.PointerToRawData:
双字长度。
节起始地址在文件中的偏移。
6.PointerToRelocations:
双字长度。
未用到,主要在.obj文件,作为指向重定位表的指针用。
7.NumberOfRelocations:
单字长度。
未用到。主要在.obj文件,作为重定位表的个数用。
8.PointerToLinenumbers:
双字长度。
未用到。在调试用,表示行号表位置。
9.NumberOfLinenumbers:
单字长度。
未用于。表示行号数量。
10.Characteristics:
双字长度。
表示节的标志,很重要。32个二进制位分别表示不同属性,可或操作组合使用。
个别位系统保留,个别位为0,下面是常用的位介绍。
IMAGE_SCN_CNT_CODE
0x00000020
包含代码,常与 0x10000000一起设置。
IMAGE_SCN_CNT_INITIALIZED_DATA
0x00000040
该
节
包含以初始化的数据。
IMAGE_SCN_CNT_UNINITIALIZED_DATA
0x00000080
该
节
包含未初始化的数据。
IMAGE_SCN_MEM_DISCARDABLE
0x02000000 进程载入后,
该
节
可被丢弃。
IMAGE_SCN_MEM_SHARED
0x10000000
该
节
为共享区块。
IMAGE_SCN_MEM_EXECUTE
0x20000000
该
节
可以执行。
IMAGE_SCN_MEM_READ
0x40000000
该
节
可读,可执行文件中的区块总是设置该
标志。
IMAGE_SCN_MEM_WRITE
0x80000000
该
节
可写。
节表项对应描述一个节表的信息,通过这些信息可以定位一个节表,进而读取节表中数据。
节表有很种类,导入表,导出表,栈与重定位表等等。
会在后面帖子介绍与通过代码读取。
例程下载地址VS2010,mfc 编写:
欢迎光临 工控编程吧 (https://www.gkbc8.com/)
Powered by Discuz! X3.4