(一)win32中PE的NT:
NT头是PE文件中标准PE头和可选PE头的总体称谓,还包含一个PE标识.下面是它在Visual C++ 6.0中WINNT.h中的定义:
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //PE标识
IMAGE_FILE_HEADER FileHeader; //标准PE头(也称文件头)
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //可选PE头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
第一个是64bit的NT头定义,第二个是32bit的.这里只探讨32bit的.标准PE头也叫文件头,这不重要,知道是那么个东西就行了,个人不太喜欢动不动就用高端名词,高端名词主要是为了严谨而取出来的,但是很多时候很晦涩,通俗易懂更易让人接受.
(二).NT头中的Signature:
这就是一个PE标识,说明这是PE的开始位置.它在PE文件中的偏移由DOS头中的最后一个成员e_lfanew决定,上一节解析了它的值为:0xE0,如图:
(三).NT头中的标准PE头:
(1).NT头中的标准PE头数据宽度是0x14个字节,在Visual C++ 6.0中的结构定义如下:
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;
(2).代码的文件结构如下图:每个解析头函数定义分别放在不同的头文件中,方便逐个头结构的观察,为了可以多熟悉即便各个头的数据结构,每个函数中都重新从头开始解析了一遍,这样效率会降低.后面如果有空,会提供优化了的代码.(优化思路:在解析一开始,就将各个头的地址放进一个unsigned long*的全局数组里面,这样在后面是用的时候就直接调用数组里的地址,而不用每次都重新定义DOS头结构再依计算出各个结构的偏移.)
(3).解析文件头的代码如下(代码中都只是输出部分重要的数据,博客中代码列数的限制,注释一行放不下,不美观):
file.h
void Output_File(void* buffer)
{
void* buf = buffer;
//计算偏移时有用
IMAGE_DOS_HEADER* pdos = (IMAGE_DOS_HEADER*)buf;
//pnt存放NT头的地址.
IMAGE_NT_HEADERS32* pnt = (IMAGE_NT_HEADERS32*)((unsigned char*)buf + pdos->e_lfanew);
//pfile存放NT头中标准PE头结构所在地址.
IMAGE_FILE_HEADER* pfile = (IMAGE_FILE_HEADER*)&pnt->FileHeader;
printf("\nNT Header:\n");
//PE标识,值与PE的ascii码一一对应
printf("PE: %#X\n", pnt->Signature);
printf("File Header:\n");
//输出程序能在哪种CPU平台上运行.
printf("Machine: %#X\n", pfile->Machine);
//输出PE文件中节的数量
printf("NumberOfSec: %#X\n", pfile->NumberOfSections);
//时间戳,文件的创建时间,一般有编译器填充,修改后不会影响程序运行
printf("TimeStamp: %#X\n", pfile->TimeDateStamp);
//可选PE头的大小(32bit默认是0xE0,64bit默认是0xF0)
printf("SizeOfOpHdr: %#X\n", pfile->SizeOfOptionalHeader);
//该文件的属性(标识给文件的类型,如是exe还是dll或其他)
printf("Characteristics: %#X\n", pfile->Characteristics);
}
注释掉其他头的解析:运行结果如下:
(四).NT头中的可选PE头: