1.PE文件结构简介

PE 文件就是windows下可执行文件的总称,常见的有:DLL,EXE,OCX,SYS

Windows 是如何区分可执行文件的呢?也许你会说文件扩展名,但我要告诉你,这是错误的。因为这个是涉及到PE结构的。

image-20230523134431288

DOS头是用来兼容MS-DOS操作系统的,目标一般是用来指明NT头在文件中的位置

NT头包含windows PE文件的主要信息,其中包括一个‘PE’字样的签名,PE文件头【IMAGE_FILE_HEADER】和PE可选头【IMAGE_OPTIONAL_HEADER32】,头部的详细结构以及其具有意义在PE文件头文章中详细描述

节表是PE文件后续节的描述,windows根据节表的描述加载每个节

每个节实际上是一个容器,可以包含代码,数据…每个节可以有独立的内存权限,比如代码节默认有读/执行权限,节的名字和数量是可以自己定义的【不一定就是上图中的三个】

当一个PE文件被加载到内存中以后,就称之“映像【image】”,一般来说,PE文件在硬盘上和内存是不完全一样的,被加载到内存以后占用的虚拟地址空间要比硬盘上占用的空间大一些,这是因为:各个节在硬盘上是连续的,但是在内存中是按照耶对齐的,所以加载到内存以后节之间会出现一些“空洞”

因为存在这种对齐,所以在PE结构内部,表示某个位置的地址采用了两种方式:

  • 1.针对在硬盘上存储文件中的地址,称为原始存储地址或者物理地址表示距离文件头的偏移;

  • 2.另外一种是针对加载到内存以后映像中的地址,称为相对虚拟地址【RVA】,表示相对内存映像头的偏移

然而CPU的某些指令是需要使用绝对地址的,比如取全局变量的地址,传递函数的地址 编译以后的汇编指令中肯定需要用到绝对地址而不是相对映像头的偏移,因此PE文件会建议操作系统将其加载到某个内存地址【这个叫基地址】,编译器便根据这个地址求出代码中一些全局变量和函数的地址,并将这些地址用到对应的指令中。

可执行文件头

DOS头和NT头就是PE文件中两个重要的文件头。

一、DOS头

主要是兼容,对于32位PE文件来说,DOS所起的作用就是显示一行文字,提示用户:我需要在32位windows上才可以运行。我认为这是个善意的玩笑,因为他并不像显示的那样不能运行,其实已经运行了,只是在DOS上没有干用户希望看到的工作而已,好吧,我承认这不是重点。但是,至少我们看一下这个头是如何定义的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

需要关注的就2个地方

  1. e_magic:一个WORD类型,值是一个常数0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都

是’MZ’开头

  1. e_lfanew:为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移。

image-20230523140957251

二.NT头

顺着 e_lfanew 很容易就能找到NT头,这个才是32位PE文件中最有用的头

1
2
3
4
5
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

我们可以通过010里面的模块来分析文件,

image-20230523143737562

2.PE字段简介

PEtools 这个工具

image-20230523152936812

image-20230523153027058


贼多嘞,后面在学吧 《windows PE 权威指南》

3.PE节表

节表位置的计算:DOS头大小+标准PE头大小+标准PE头SizeofoftimHeader的值

FileBuffer 是从硬盘读到内存的缓存

ImageBuffer(映像或镜像)是把内存中的FileBuffer拉伸后的结果

image-20230523153646466

image-20230523153657361

image-20230523153705486

节表 VirtualAddress 属性的意思

真实代码的大小,包括为初始化数据的大小,例如 char a[100] ,a数组没有初始化数据,但是还是要算100字节大小,

image-20230523153723175

节表****SizeOfRawData 属性的意思

image-20230523153736676

节表 PointerToRawData****属性

image-20230523153748695

Characteristics 节的属性

image-20230523153759721

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
标志(属性块) 常用特征值对照表:
[值:00000020h] [IMAGE_SCN_CNT_CODE // Section contains code.(包含可
执行代码)]
[值:00000040h] [IMAGE_SCN_CNT_INITIALIZED_DATA // Section contains initialized
data.(该块包含已初始化的数据)]
[值:00000080h] [IMAGE_SCN_CNT_UNINITIALIZED_DATA // Section contains
uninitialized data.(该块包含未初始化的数据)]
[值:00000200h] [IMAGE_SCN_LNK_INFO // Section contains comments or
some other type of information.]
[值:00000800h] [IMAGE_SCN_LNK_REMOVE // Section contents will not
become part of image.]
[值:00001000h] [IMAGE_SCN_LNK_COMDAT // Section contents comdat.]
[值:00004000h] [IMAGE_SCN_NO_DEFER_SPEC_EXC // Reset speculative exceptions
handling bits in the TLB entries for this section.]
[值:00008000h] [IMAGE_SCN_GPREL // Section content can be
accessed relative to GP.]
[值:00500000h] [IMAGE_SCN_ALIGN_16BYTES // Default alignment if no
others are specified.]
[值:01000000h] [IMAGE_SCN_LNK_NRELOC_OVFL // Section contains extended
relocations.]
[值:02000000h] [IMAGE_SCN_MEM_DISCARDABLE // Section can be discarded.]
[值:04000000h] [IMAGE_SCN_MEM_NOT_CACHED // Section is not cachable.]
[值:08000000h] [IMAGE_SCN_MEM_NOT_PAGED // Section is not pageable.]
[值:10000000h] [IMAGE_SCN_MEM_SHARED // Section is shareable(该块为共
享块).]
[值:20000000h] [IMAGE_SCN_MEM_EXECUTE // Section is executable.(该块可
执行)]
[值:40000000h] [IMAGE_SCN_MEM_READ // Section is readable.(该块可
读)]
[值:80000000h] [IMAGE_SCN_MEM_WRITE // Section is writeable.(该块可
写)]