這個IMAGE_NT_HEADERS其實就是PE相關結構的映像頭,NT據我揣測應該是New Technology的縮寫,區分于DOS WIN9X的新技術,您老要是非覺得是NTR什么的也沒關系。
IMAGE_NT_HEADERS的結構是這個樣子的
IMAGE_NT_HEADERS STRUCT


{
+0h DWORD Signature
+4h IMAGE_FILE_HEADER FileHeader
+18h IMAGE_OPTIONAL_HEADER32 OptionalHeader
} IMAGE_NT_HEADERS ENDS
其中包含兩個子結構體,和一個標志。
其中Signature字段被設置成00004550h ,ASCII碼為PE00 ,標志著PE頭文件的開始。上一篇中 DOS頭結構體中的e_lfanew正是指向這里。
IMAGE_FILE_HEAD
ER這個結構是這樣的
typedef struct _IMAGE_FILE_HEADER


{
+04h WORD Machine; // 運行平臺
+06h WORD NumberOfSections; // 文件的區塊數目
+08h DWORD TimeDateStamp; // 文件創建日期和時間
+0Ch DWORD PointerToSymbolTable; // 指向符號表(主要用于調試)
+10h DWORD NumberOfSymbols; // 符號表中符號個數(同上)
+14h WORD SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 結構大小
+16h WORD Characteristics; // 文件屬性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;Machine 代表了CPU的類型 ,定義在windows.h中
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
NumberOfSection 代表區塊的數目,區塊表緊跟在IMAGE_NT_HEADERS后面,區塊表大概是一個鏈表結構,鏈表長度由NumberOfSection的數值決定。
TimeDataStamp 表明文件的創建時間
SizeOfOptionalHeader 是IMAGE_NT_HEADERS的另一個子結構IMAGE_OPTIONAL_HEADER的大小,32位的PE文件這個值一般是00E0,64位的PE文件一般是00F0
Characteristics 代表文件的
屬性EXE文件一般是0100h DLL文件一般是210Eh,多種屬性可以用或運算同時擁有。
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // 重定位信息被移除
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // 文件可執行
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // 行號被移除
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // 符號被移除
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // 程序能處理大于2G的地址
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32位機器
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // .dbg文件的調試信息被移除
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // 如果在移動介質中,拷到交換文件中運行
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // 如果在網絡中,拷到交換文件中運行
#define IMAGE_FILE_SYSTEM 0x1000 // 系統文件
#define IMAGE_FILE_DLL 0x2000 // 文件是一個dll
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // 文件只能運行在單處理器上
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.下面來編寫一個程序來顯示一下這個結構體
#include "windows.h" //PE的那一套結構體大多都是定義在這個頭文件里的
#include "stdio.h"

int main(int argc, char* argv[])


{
FILE *p;
LONG e_lfanew; //指向IMAGE_NT_HEADERS32結構在文件中的偏移
IMAGE_FILE_HEADER myfileheader;
p = fopen("test.exe","r+b");
if(p == NULL)return -1;

fseek(p,0x3c,SEEK_SET);
fread(&e_lfanew,4,1,p);
fseek(p,e_lfanew+4,SEEK_SET); //指向IMAGE_FILE_HEADER結構的偏移 PE的標志位是DWORD占4字節
fread(&myfileheader,sizeof(myfileheader),1,p);

printf("IMAGE_FILE_HEADER結構:\n");
printf("Machine : %04X\n",myfileheader.Machine);
printf("NumberOfSections : %04X\n",myfileheader.NumberOfSections);
printf("TimeDateStamp : %08X\n",myfileheader.TimeDateStamp);
printf("PointerToSymbolTable : %08X\n",myfileheader.PointerToSymbolTable);
printf("NumberOfSymbols : %08X\n",myfileheader.NumberOfSymbols);
printf("SizeOfOptionalHeader : %04X\n",myfileheader.SizeOfOptionalHeader);
printf("Characteristics : %04X\n",myfileheader.Characteristics);
getch();
return 0;
}總的來說
IMAGE_FILE_HEADER是記錄文件的各種信息的
下面說一下IMAGE_OPTIONAL_HEADER結構,他是一個可選結構,是對IMAGE_FILE_HEADER的一個補充,當然很多情況下它是必須的。
typedef struct _IMAGE_OPTIONAL_HEADER


{
//
// Standard fields.
//
+18h WORD Magic; // 標志字, ROM 映像(0107h),普通可執行文件(010Bh)
+1Ah BYTE MajorLinkerVersion; // 鏈接程序的主版本號
+1Bh BYTE MinorLinkerVersion; // 鏈接程序的次版本號
+1Ch DWORD SizeOfCode; // 所有含代碼的節的總大小
+20h DWORD SizeOfInitializedData; // 所有含已初始化數據的節的總大小
+24h DWORD SizeOfUninitializedData; // 所有含未初始化數據的節的大小
+28h DWORD AddressOfEntryPoint; // 程序執行入口RVA
+2Ch DWORD BaseOfCode; // 代碼的區塊的起始RVA
+30h DWORD BaseOfData; // 數據的區塊的起始RVA
//
// NT additional fields. 以下是屬于NT結構增加的領域。
//
+34h DWORD ImageBase; // 程序的首選裝載地址
+38h DWORD SectionAlignment; // 內存中的區塊的對齊大小
+3Ch DWORD FileAlignment; // 文件中的區塊的對齊大小
+40h WORD MajorOperatingSystemVersion; // 要求操作系統最低版本號的主版本號
+42h WORD MinorOperatingSystemVersion; // 要求操作系統最低版本號的副版本號
+44h WORD MajorImageVersion; // 可運行于操作系統的主版本號
+46h WORD MinorImageVersion; // 可運行于操作系統的次版本號
+48h WORD MajorSubsystemVersion; // 要求最低子系統版本的主版本號
+4Ah WORD MinorSubsystemVersion; // 要求最低子系統版本的次版本號
+4Ch DWORD Win32VersionValue; // 莫須有字段,不被病毒利用的話一般為0
+50h DWORD SizeOfImage; // 映像裝入內存后的總尺寸
+54h DWORD SizeOfHeaders; // 所有頭 + 區塊表的尺寸大小
+58h DWORD CheckSum; // 映像的校檢和
+5Ch WORD Subsystem; // 可執行文件期望的子系統
+5Eh WORD DllCharacteristics; // DllMain()函數何時被調用,默認為 0
+60h DWORD SizeOfStackReserve; // 初始化時的棧大小
+64h DWORD SizeOfStackCommit; // 初始化時實際提交的棧大小
+68h DWORD SizeOfHeapReserve; // 初始化時保留的堆大小
+6Ch DWORD SizeOfHeapCommit; // 初始化時實際提交的堆大小
+70h DWORD LoaderFlags; // 與調試有關,默認為 0
+74h DWORD NumberOfRvaAndSizes; // 下邊數據目錄的項數,這個字段自Windows NT 發布以來 // 一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
// 數據目錄表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;這個結構東西各種多啊···非常蛋疼,不過很多都是optional的,可以不用管他們,重要的就那么幾個。
AddressOfEntryPoint 指出文件執行時的入口地址,是一個RVA地址,就是大家常說的OEP,常常各種尋找的OEP,如果你有什么代碼要先于程序主體執行,只需要將這個入口指向這段代碼就行啦~
ImageBase 指向文件的優先裝入地址,一般情況EXE文件不需要重定位,DLL文件可能需要重定位。
Se
ctionAlignment 和 FileAlignment 確定了內存中的節對齊單位和在磁盤中的節對齊單位。
DataDirectory 成員是一個比較牛逼的成員,它由16個IMAGE_DATA_DIRCTORY結構組成,用來定義多種不通用處的數據塊。
這個結構體的內容很簡單

typedef struct _IMAGE_DATA_DIRECTORY
{
DWORD VirtualAddress; 相對虛擬地址
DWORD Size; 大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;只有相對虛擬地址和大小兩個成員。
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];IMAGE_NUMBEROF_DIRECTORY_ENTRIES 的值代表了數據塊的用途
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#defin e IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor最后把這些結構·讀出來看一看。
#include "windows.h"
#include "stdio.h"

int main(int argc, char* argv[])


{
FILE *p;
unsigned long Signature;
IMAGE_FILE_HEADER myfileheader;
IMAGE_DOS_HEADER mydosheader;
IMAGE_OPTIONAL_HEADER myoptionalheader;

p = fopen("test.exe","r+b");
if(p == NULL)return -1;

fread(&mydosheader,sizeof(mydosheader),1,p);
fseek(p,mydosheader.e_lfanew,SEEK_SET);
fread(&Signature,sizeof(Signature),1,p);

fseek(p,mydosheader.e_lfanew+sizeof(Signature),SEEK_SET);//指向IMAGE_FILE_HEADER結構的偏移
fread(&myfileheader,sizeof(myfileheader),1,p);

fseek(p,mydosheader.e_lfanew+sizeof(Signature)+sizeof(myfileheader),SEEK_SET);
fread(&myoptionalheader,sizeof(myoptionalheader),1,p);

printf("%X\n",mydosheader.e_lfanew);

printf("Signature : %04X\n",Signature);
printf("IMAGE_FILE_HEADER結構:\n");
printf("Machine : %04X\n",myfileheader.Machine);

printf("IMAGE_OPTIONALHEADER_HEADER結構:\n");
printf("Magic : %04X\n",myoptionalheader.Magic);由于這個IMAGE_OPENTIONAL_HEADER結構成員太多,我就不都打出來了,Magic的值一般為010bH,由此可以判頓讀取出的結構是否正確。