1.NT头
接下来说一下NT头,IMAGE_NT_HEADERS。
代码 IMAGE_NT_HEADERS结构体
typedef struct _IMAGE_NT_HEADERS{
DWORD Signature;
//PE Signature : 50450000 ("PE"00)
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
该结构体由3个成员构成:
签名(Signature)→
值为50450000h("PE"00)
文件头(File Header)
可选头(Optional Header)
依然以Notepad.exe为例,使用010 Editor打开。
可以查看其IMAGE_NT_HEADERS。
IMAGE_NT_HEADERS结构体的大小为F8,非常大,接下来分别说一下文件头和可选头两个结构体。
2.NT头:文件头
文件头是表现文件大致属性的IMAGE_FILE_HEADER 结构体
代码 IMAGE_FILE_HEADER结构体
typedef struct _IMAGE_FILE_HEADER{
WORD
Machine;
WORD
NumberOfSections;
DWORD
TimeDateStamp;
DWORD
PointToSymbolTable;
DWORF
NumberOfSymbols;
WORD
SizeOfOptionalHeader;
WORD
Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADERS结构体中有如下4种重要成员,(若设置不正确,将导致文件无法正常运行)。
#1.Machine
每个CPU都拥有唯一的Machine码,兼容32位Intel x86芯片的Machine码为14C。
定义在winnt.h文件中的Machine码。
代码 Machine码
#define IMAGE_FILE_MACHINE_UNKNOWN
0
#define IMAGE_FILE_MACHINE_I386
0x014c
//Inter 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
#2.NumberOfSections
PE文件把代码、数据、资源等一句属性分类到各个节区中储存。
NumberOfSections用来指出文件中存在的节区数量。该值一定要大于0,其当定义的节区数量与实际节区不同时,将发生运行错误。
#3.SizeOfOptionalHeader
IMAGE_NT_HEADER结构体的最后一个成员为IMAGE_OPTIONAL_HEADER32结构体。SizeOfOptionalHeader成员用来之处IMAGE_OPTIONAL_HEADER32结构体的长度。IMAGE_OPTIONAL_HEADER32结构体有C语言编写而成,故其大小已经确定。Windows的PE装载器需要查看IMAGE_FILE_HEADER的SizeOfOptionalHeader值,从而识别出IMAGE_OPTIONAL_HERADER32的结构体的大小。
注:PE32+格式的文件,使用的是IMAGE_OPTIONAL_HEADER64结构体(不是
IMAGE_OPTIONAL_HEADER32结构体!!!两个结构体的大小是不一样的
)所以需要在 SizeOfOptionalHeader成员中明确指出结构体的大小。
#4.Characteristics
该字段用于表示文件的属性,文件是否是可运行的形态,是否为DLL文件等信息,以bit OR形式组合起来。
定义在winnt.h文件中的Characteristics值。
(注意
0002h与2000h
)
代码 Characteristics
#define IMAGE_FILE_RELOCS_STRIPPED
0x0001
//Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE
0x0002
//File is executable
//(i.e. no unresolved externel
references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED
0x0004
//Line numbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED
0x0008
//Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM
0x0010
//Agressively trim working set.
#define IMAGE_FILE_LARGE_ADDRESS_AWARE
0x0020
//App can handle >2gb addresses
#define IMAGE_FILE_BYTES_RESVERSED_LO
0x0080
//byte of machine word are reversed
#define IMAGE_FILE_32BIT_MACHINE
0x0100
//32 bit word machine
#define IMAGE_FILE_DEBUG_STRIPPED
0x0200
//Debugging info stripped from
file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
0x0400
//If Image is on removable media,
//copy and run from the swap file
#define IMAGE_FILE_NET_RUN_FROM_SWAP
0x0800
//If Image is on Net,
copy and run from the swap file.
#define IMAGE_FILE_SYSTEM
0x1000
//System File
#define IMAGE_FILE_DLL
0x2000
//File is a DLL
#define IMAGE_FILE_UP_SYSTEM_ONLY
0x4000
//File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI
0x8000
//byte of machine word are reversed
注:PE文件中Characteristics的值有可能不是0002h(not executable),例如:*.obj的object文件及resource DLL文件等,2000h表明PE文件是否为DLL文件。
IMAGE_FILE_HEADER的TimeDateStamp成员,该成员的值不影响文件运行,用来记录编译器创建文件的时间(并不是所有的开发工具都提供了设置该值的工具,Delphi则并没有提供)。
3.NT头:可选头
IMAGE_OPTIONAL_HEADER32是PE头结构体中最大的。
代码 IMAGE_OPTIONAL_HEADER32结构体。
typedef struct _IMAGE_DATA_DIRECTORY{
DWORD
VirtualAddress;
DWORD
Size;
}
IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES
16
typedef struct _IMAGE_OPTIONAL_HEADER{
WORD
Magic;
BYTE
MajorLinkerVersion;
BYTE
MinorLinkerVersion;
DWORD SizeOfCode;
DWORD
SizeOfInitializedData;
DWORD
SizeOfUnitializedData;
DWORD
AddressOfEntryPoint;
DWORD
BaseOfCode;
DWORD
BaseOfData;
DWORD
ImageBase;
DWORD
SectionAlignment;
DWORD
FileAlignment;
WORD
MajorOperatingSystemVersion;
WORD
MinorOperatingSystemVersion;
WORD
MajorImageVersion;
WORD
MinorImageVersion;
WORD
MajorSubsystemVersion;
WORD
MinorSubsystemVersion;
DWORD
Win32VersionValue;
DWORD
SizeOfImage;
DWORD
SizeOfHeaders;
DWORD
CheckSum;
WORD
Subsystem;
WORD
DllCharacteristics;
DWORD
SizeOfStackReserve;
DWORD
SizeOfStackCommit;
DWORD
SizeOfHeapReserve;
DWORD
SizeOfHeapCommit;
DWORD
LoaderFlags;
DWORD
NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY
DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
}
IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
IMAGE_OPTIONAL_HEADER32结构体中有如下几种重要成员,(若设置不正确,将导致文件无法正常运行)。
#1.Magic
为IMAGE_OPTIONAL_HEADER32结构体是,Magic码为10B;为IMAGE_OPTIONAL_HEADER64结构体时,Magic码为20B。
#2.AddressOfEntryPoint
AddressOfEntryPoint持有EP的RVA值。该值指出程序最先执行的代码起始地址。
#3.ImageBase
进程虚拟内存的范围为0~FFFFFFFF(32位操作系统,64位的操作系统为0~FFFFFFFFFFFFFFFF(16个))。PE文件被加载到如此大的内存中时ImageBase指出文件优先装入地址。
EXE/DLL文件被装在到用户内存的0~7FFFFFFF(32位系统)中,SYS文件被载入内核内存的80000000~FFFFFFFF中。一般而言,使用开发工具创建好EXE文件后,其ImageBase的值为00400000,DLL文件的ImageBase为100000000(可以指定为其他值)。
注:执行PE文件时,PE装载器先差un构建进程,再将文件载入内存,然后把EIP寄存器的值设置为
ImageBase+AddressOfEntryPoint.
#4.SectionAlignment,FileAlignment
PE文件的Body部分划分为若干节区,这些节存储着不同类别的数据。FileAlignment指定了节区在磁盘文件中的最小单位,SectionAlignment指定了节区在内存中的最小单位(SectionAlignment与FlieAlignment的值不一定相同)。磁盘文件或内存节区的大小必定为FileAlignment或SectionAlignment的整数倍。
#5.SizeOfImage
加载PE文件到内存时,SizeOfImage指定了PE Image在虚拟内存中所占空间的大小。一般而言,文件与加载到内存之后两者的大小是不相同的。
#6.SizeOfHeader
SizeOfHeader用来指出整个PE头的大小,当然这个值也必须为FileAlignment的整数倍。第一节区所在位置与SizeOfHeader据文件开始偏移的量相同。
#7.Subsystem
这个值是用来区分系统驱动文件安(*.sys)和普通的可执行文件的(*.exe,*.dll)。
值
含义
备注
1
Driver文件
系统驱动
2
GUI文件
窗口应用程序
3
CUI文件
控制台应用程序
#8.NumberOfRvaAndSizes
NumberOfRvaAndSizes用来制定DataDirectory(IMAGE_OPTIONAL_HEADER32结构体最后一个成员)数组的个数。虽然结构体定义中明确指出了数组个数为16(
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES
16
)但是PE装载查看的NumberOfRvaAndSizes的值来识别数组的大小(即数组大小也可能不为16)。
#9.DataDirectory
DataDirectory是有IMAGE_DATA_DIRECTORY结构体组成的数组,数组的每项都有被定义的值。
代码 DataDirectory结构体数组
DataDirectory[0] = EXPORT Directory
DataDirectory[1] = IMPOTR Directory
DataDirectory[2] = RESOURCE Directory
DataDirectory[3] = EXCEPTION Directory
DataDirectory[4] = SECURITY Directory
DataDirectory[5] = BASERELOC Directory
DataDirectory[6] = DEBUG Directory
DataDirectory[7] = COPYRIGHT Directory
DataDirectory[8] = GLOBALPTR Directory
DataDirectory[9] = TLS Directory
DataDirectory[A] = LOAD_CONFIG Directory
DataDirectory[B] = BOUND_IMPORT Directory
DataDirectory[C] = IAT Directory
DataDirectory[D] = DELAY_IMPORT Directory
DataDirectory[E] = COM_DESCRIPTOR Directory
DataDirectory[F] = Reserver Directory
IMAGE_OPTIONAL_HEADER
使用010 Editor查看Notepad.exe的IMAGE_OPTIONAL_HEADER整个结构体。