win32下PE文件分析之NT头

时间:2021-10-17 01:31:28

(一)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头: