PE文件详解(一)--数据结构字段

DOS MZ头IMAGE_DOS_HEADER STRUCT :

IMAGE_DOS_HEADER STRUCT

{
+0hWORDe_magic //Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记
+2h WORD e_cblp //Bytes on last page of file
+4hWORD e_cp //Pages in file
+6hWORD e_crlc //Relocations
+8hWORD e_cparhdr //Size of header in paragraphs
+0ahWORD e_minalloc //Minimun extra paragraphs needs
+0chWORD e_maxalloc //Maximun extra paragraphs needs
+0ehWORD e_ss //intial(relative)SS value DOS代码的初始化堆栈SS
+10hWORD e_sp //intial SP value DOS代码的初始化堆栈指针SP
+12hWORD e_csum //Checksum
+14hWORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
+16hWORD e_cs //intial(relative)CS value DOS代码的初始堆栈入口
+18hWORD e_lfarlc //File Address of relocation table
+1ahWORD e_ovno // Overlay number
+1chWORD e_res[4] //Reserved words
+24hWORD e_oemid // OEM identifier(for e_oeminfo)
+26hWORD e_oeminfo // OEM information;e_oemid specific
+29hWORD e_res2[10] // Reserved words
+3chDWORD e_lfanew //Offset to start of PE header 指向PE文件头
} IMAGE_DOS_HEADER ENDS
IMAGE_NT_HEADERS结构:
IMAGE_NT_HEADERS STRUCT
{
+0hDWORDSignature //
+4h IMAGE_FILE_HEADER FileHeader //
+18hIMAGE_OPTIONAL_HEADER32OptionalHeader //
} IMAGE_NT_HEADERS ENDS

Signature 字段:
在一个有效的 PE 文件里,Signature 字段被设置为00004550h, ASCII 码字符是“PE00”。标志这 PE 文件头的开始。
“PE00” 字符串是 PE 文件头的开始,DOS 头部的 e_lfanew 字段正是指向这里。
如下图所示:


IMAGE_FILE_HEADER 结构

typedef struct _IMAGE_FILE_HEADER
{
+04h WORD Machine; // 运行平台 +06h WORD NumberOfSections; // 文件的区块数目 +08h DWORDTimeDateStamp; // 文件创建日期和时间 +0Ch DWORD PointerToSymbolTable; // 指向符号表(主要用于调试) +10h DWORD NumberOfSymbols; // 符号表中符号个数(同上) +14h WORD SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 结构大小 +16h WORD Characteristics; // 文件属性 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

该结构如下图所示:



下边,小甲鱼童鞋为大家详细解释各个成员的含义和用法:

(1)Machine:可执行文件的目标CPU类型。

Value Meaning
IMAGE_FILE_MACHINE_I386
0x014c

x86

IMAGE_FILE_MACHINE_IA64
0x0200

Intel Itanium

IMAGE_FILE_MACHINE_AMD64
0x8664

x64


(2)NumberOfSection: 区块的数目。(注:区块表是紧跟在 IMAGE_NT_HEADERS 后边的)
(3)TimeDataStamp: 表明文件是何时被创建的。
这个值是自1970年1月1日以来用格林威治时间(GMT)计算的秒数,这个值是比文件系统(FILESYSTEM)的日期时间更加精确的指示器。如何将这个值翻译请看:http://bbs.fishc.com/space.php?uid=9&do=blog&id=555
提示:VC的话可以用_ctime 函数或者 gmtime 函数。

(4)PointerToSymbolTable: COFF 符号表的文件偏移位置,现在基本没用了。
(5)NumberOfSymbols: 如果有COFF 符号表,它代表其中的符号数目,COFF符号是一个大小固定的结构,如果想找到COFF 符号表的结束位置,则需要这个变量。

(6)SizeOfOptionalHeader: 紧跟着IMAGE_FILE_HEADER 后边的数据结构(IMAGE_OPTIONAL_HEADER)的大小。(对于32位PE文件,这个值通常是00E0h;对于64位PE32+文件,这个值是00F0h )。
(7)Characteristics: 文件属性,有选择的通过几个值可以运算得到。( 这些标志的有效值是定义于 winnt.h 内的 IMAGE_FILE_** 的值,具体含义见下表。普通的EXE文件这个字段的值一般是 0100h,DLL文件这个字段的值一般是 210Eh。)小甲鱼温馨提示:多种属性可以通过 “或运算” 使得同时拥有!

The characteristics of the image. This member can be one or more of the following values.

Value Meaning
IMAGE_FILE_RELOCS_STRIPPED
0x0001

Relocation information was stripped from the

file. The file must be loaded at its preferred

base address. If the base address is not

available, the loader reports an error.

IMAGE_FILE_EXECUTABLE_IMAGE
0x0002

The file is executable (there are no unresolved

external references).

IMAGE_FILE_LINE_NUMS_STRIPPED
0x0004

COFF line numbers were stripped from the

file.

IMAGE_FILE_LOCAL_SYMS_STRIPPED
0x0008

COFF symbol table entries were stripped from

file.

IMAGE_FILE_AGGRESIVE_WS_TRIM
0x0010

Aggressively trim the working set. This value is

obsolete as of Windows 2000.

IMAGE_FILE_LARGE_ADDRESS_AWARE
0x0020

The application can handle addresses larger

than 2 GB.

IMAGE_FILE_BYTES_REVERSED_LO
0x0080

The bytes of the word are reversed. This flag

is obsolete.

IMAGE_FILE_32BIT_MACHINE
0x0100

The computer supports 32-bit words.

IMAGE_FILE_DEBUG_STRIPPED
0x0200

Debugging information was removed and stored

separately in another file.

IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
0x0400

If the image is on removable media, copy it to

and run it from the swap file.

IMAGE_FILE_NET_RUN_FROM_SWAP
0x0800

If the image is on the network, copy it to and

run it from the swap file.

IMAGE_FILE_SYSTEM
0x1000

The image is a system file.

IMAGE_FILE_DLL
0x2000

The image is a DLL file. While it is an executable

file, it cannot be run directly.

IMAGE_FILE_UP_SYSTEM_ONLY
0x4000

The file should be run only on a uniprocessor

computer.

IMAGE_FILE_BYTES_REVERSED_HI
0x8000

The bytes of the word are reversed. This flag

is obsolete.

 
IMAGE_OPTIONAL_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;


事实上,这个结构中的大部分字段都不重要,大家可以从注释中理解它们的含义,小甲鱼将比较重要的字段在下边跟大家详细讲解。另外,这玩意千万不要去背啊,我们要把绝大多数的时间拿来改变,而不是记住。不用做笔记,把这篇文章转载到您的博客就行(最好注明:小甲鱼是帅哥)吼吼 ^_^


● AddressOfEntryPoint字段

指出文件被执行时的入口地址,这是一个RVA地址(RVA的含义在下一节中详细介绍)。如果在一个可执行文件上附加了一段代码并想让这段代码首先被执行,那么只需要将这个入口地址指向附加的代码就可以了。


● ImageBase字段

指出文件的优先装入地址。也就是说当文件被执行时,如果可能的话,Windows优先将文件装入到由ImageBase字段指定的地址中,只有指定的地址已经被**模块使用时,文件才被装入到**地址中。链接器产生可执行文件的时候对应这个地址来生成机器码,所以当文件被装入这个地址时不需要进行重定位操作,装入的速度最快,如果文件被装载到**地址的话,将不得不进行重定位操作,这样就要慢一点。


对于EXE文件来说,由于每个文件总是使用独立的虚拟地址空间,优先装入地址不可能被**模块占据,所以EXE总是能够按照这个地址装入,这也意味着EXE文件不再需要重定位信息。对于DLL文件来说,由于多个DLL文件全部使用宿主EXE文件的地址空间,不能保证优先装入地址没有被**的DLL使用,所以DLL文件中必须包含重定位信息以防万一。因此,在前面介绍的 IMAGE_FILE_HEADER 结构的 Characteristics 字段中,DLL 文件对应的 IMAGE_FILE_RELOCS_STRIPPED 位总是为0,而EXE文件的这个标志位总是为1。

在链接的时候,可以通过对link.exe指定/base:address选项来自定义优先装入地址,如果不指定这个选项的话,一般EXE文件的默认优先装入地址被定为00400000h,而DLL文件的默认优先装入地址被定为10000000h。


● SectionAlignment 字段和 FileAlignment字段

SectionAlignment字段指定了节被装入内存后的对齐单位。也就是说,每个节被装入的地址必定是本字段指定数值的整数倍。而FileAlignment字段指定了节存储在磁盘文件中时的对齐单位。


● Subsystem字段

指定使用界面的子系统,它的取值如表17.3所示。这个字段决定了系统如何为程序建立初始的界面,链接时的/subsystem:**选项指定的就是这个字段的值,在前面章节的编程中我们早已知道:如果将子系统指定为Windows CUI,那么系统会自动为程序建立一个控制台窗口,而指定为Windows GUI的话,窗口必须由程序自己建立。


界面子系统的取值和含义

取 值

Windows.inc中的预定义值

含 义

0

IMAGE_SUBSYSTEM_UNKNOWN

未知的子系统

1

IMAGE_SUBSYSTEM_NATIVE

不需要子系统(如驱动程序)

2

IMAGE_SUBSYSTEM_WINDOWS_GUI

Windows图形界面

3

IMAGE_SUBSYSTEM_WINDOWS_CUI

Windows控制台界面

5

IMAGE_SUBSYSTEM_OS2_CUI

OS2控制台界面

7

IMAGE_SUBSYSTEM_POSIX_CUI

POSIX控制台界面

8

IMAGE_SUBSYSTEM_NATIVE_WINDOWS

不需要子系统

9

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

Windows CE图形界面


● DataDirectory字段

这个字段可以说是最重要的字段之一,它由16个相同的IMAGE_DATA_DIRECTORY结构组成,虽然PE文件中的数据是按照装入内存后的页属性归类而被放在不同的节中的,但是这些处于各个节中的数据按照用途可以被分为导出表、导入表、资源、重定位表等数据块,这16个IMAGE_DATA_DIRECTORY结构就是用来定义多种不同用途的数据块的(如表17.4所示)。IMAGE_DATA_DIRECTORY结构的定义很简单,它仅仅指出了某种数据块的位置和长度。

IMAGE_DATA_DIRECTORY STRUCT

VirtualAddress DWORD ? ;数据的起始RVA

isize DWORD ? ;数据块的长度

IMAGE_DATA_DIRECTORY ENDS

数据目录列表的含义

索 引

索引值在Windows.inc中的预定义值

对应的数据块

0

IMAGE_DIRECTORY_ENTRY_EXPORT

导出表

1

IMAGE_DIRECTORY_ENTRY_IMPORT

导入表

2

IMAGE_DIRECTORY_ENTRY_RESOURCE

资源

3

IMAGE_DIRECTORY_ENTRY_EXCEPTION

异常(具体资料不详)

4

IMAGE_DIRECTORY_ENTRY_SECURITY

安全(具体资料不详)

5

IMAGE_DIRECTORY_ENTRY_BASERELOC

重定位表

6

IMAGE_DIRECTORY_ENTRY_DEBUG

调试信息

7

IMAGE_DIRECTORY_ENTRY_ARCHITECTURE

版权信息

8

IMAGE_DIRECTORY_ENTRY_GLOBALPTR

具体资料不详

9

IMAGE_DIRECTORY_ENTRY_TLS

Thread Local Storage

10

IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG

具体资料不详

11

IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT

具体资料不详

12

IMAGE_DIRECTORY_ENTRY_IAT

导入函数地址表

13

IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

具体资料不详

14

IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR

具体资料不详

15

未使用



在PE文件中寻找特定的数据时就是从这些IMAGE_DATA_DIRECTORY结构开始的,比如要存取资源,那么必须从第3个IMAGE_DATA_DIRECTORY结构(索引为2)中得到资源数据块的大小和位置;同理,如果要查看PE文件导入了哪些DLL文件的哪些API函数,那就必须首先从第2个IMAGE_DATA_DIRECTORY结构得到导入表的位置和大小。

 

转:小甲鱼PE详解

你可能感兴趣的:(逆向)