源代码如下:
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
image.png
重定位表是叁个数组,这一个数组的尺寸记载在 _IMAGE_OPTIONAL_HEADER 的
Dos头:
-
Dos头的前三个字节恒为4D5A(只是作为剖断PE文件的率先个标记,并不能够经过它就会判断是不是是PE文件)
-
Dos头的终极多少个字节是指向NT头的偏移量
唯有前七个字节和前面多个字节关系到PE文件是否正规运作 -
公海710登录网址 ,NT头:

image.png
-
前方多个字节恒为0x4550,用于判别是还是不是为PE文件的第一个标识
-
Nt头前面正是各样区段音信
.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size 成员中
文件头
www.710.com ,image.png
-
文本头大小0x拾伍个字节(由图可以预知:它是Nt头的第二个要素)
-
扩大头的尺寸就在里边
-
节的数量也在当中
-
文本头里面保存了PE文件的有的属性(这里只列举了部分):
1.是否是dll(0x0210),exe(0x010F)
2.是或不是可进行
布局图如下,图片中 0 和 000 都代表16进制数,调换来二进制是 0000 和 0000
0000 0000:
扩展头
image.png
image.png
增加头安详严整:
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic; //表示这是一个什么类型的PE文件,32位一般是0x010B,64位的文件一般是0x020B
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode; //所有代码区段(节)的总大小(基于文件对齐后的大小)
DWORD SizeOfInitializedData; //已经初始化的数据的总大小
DWORD SizeOfUninitializedData; //未初始化的数据的大小
DWORD AddressOfEntryPoint; //程序开始执行的相对虚拟地址,即OEP,这是一个RVA,要想得到VA,则必须要加上ImageBase(下面有介绍!!!!!)
DWORD BaseOfCode; //起始代码的相对虚拟地址(RVA),就是.text段的RVA
DWORD BaseOfData; // 其实数据的相对虚拟地址(RVA),就是.data段的RVA
//
// NT additional fields.
//
DWORD ImageBase; //默认加载地址(如果没有这个基址会发生重定位)
DWORD SectionAlignment; //块对齐数,一般是0x1000
DWORD FileAlignment; //文件对齐数,一般是0x200
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage; //把文件加载进内存,所需要的内存大小,是进行了内存对齐之后的大小
DWORD SizeOfHeaders; //所有头部大小(这是按照文件对齐后的大小),也是文件主体相对文件起始的偏移,是所有头+节表的大小
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics; //文件(包括exe和dll文件)特征标志(见下面一张图)
DWORD SizeOfStackReserve; //表示进程中栈可以增长到的最大值,一般1M
DWORD SizeOfStackCommit; //进程中栈的初始值,据说也是栈每次分配增长的值,一般4KB
DWORD SizeOfHeapReserve; //表示进程中堆可以增长到的最大值,一般1M
DWORD SizeOfHeapCommit; //进程堆的初始值
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes; //数据目录的个数,也就是下面那个数组中元素的个数
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录表,比较重要!
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
image.png
扩展头里面比较根本的在下边已经做出注释
每种成分的高低都记载在 SizeOfBlock 中,那么些成分是由 三个
_IMAGE_BASE_RELOCATION 结构体和一个TypeOffset 数组组成的。TypeOffset
数组的各样成分占2个字节,在那之中,高4位是偏移类型(type卡塔尔国,低十一人代表要求重一直的地址(Offset卡塔 尔(阿拉伯语:قطر,即,它与
VirtualAddress 相加正是指向 PE 影像中要求改善的不得了代码的RVA。
再小结一波:
ImageBase(影像基址,装载基址,它是叁个VA值):若无加载到那一个地址则会重一直(就是PE文件加载进内部存储器之后,就一定于明白了Dos头的职责,然后就足以驾驭其余的职位了),正是PE装入内存的集散地址,暗许情状下,EXE文件在内部存款和储蓄器中的集散地址是0X0040
0000,DLL文件为0x0100 0000,由编写翻译器决定!
程序入口点(OEP)
影象大小(SizeOfImage)————>把文件加载进内存,所要求的内部存款和储蓄器大小(注意是开展了块对齐之后)
代码大小(SizeOfCode)——>全部区段的总大小
代码基址(BaseOfCode)开始代码的 KugaVA—->.text的TiguanVA
数码基址(BaseOfData)发轫数据的PAJEROVA—–>.data的KugaVA
头大小(SizeOfHeaders)————>全数底部大小,便是文本宗旨绝对文件早先的舞狮
内部存款和储蓄器对齐(SectionAlignment)———–>为0x1000(4KB)
文件对齐(FileAlignment)—————->200h(0x200)
DLL标志(DllCharacteristics)——–>提示Dll特征的标记
偏移类型的意义如下:
PE头部包涵了Dos头,平昔到节表的终结地点,.text区段早先以前
- 数量目录表

image.png
Constant |
Value |
Description |
IMAGE_REL_BASED_ABSOLUTE |
0 |
The base relocation is skipped. This type can be used to pad a block. |
IMAGE_REL_BASED_HIGH |
1 |
The base relocation adds the high 16 bits of the difference to the 16bit field at offset. The 16-bit field represents the high value of a 32-bit word. |
IMAGE_REL_BASED_LOW |
2 |
The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word. |
IMAGE_REL_BASED_HIGHLOW |
3 |
The base relocation applies all 32 bits of the difference to the 32-bit field at offset. |
IMAGE_REL_BASED_HIGHADJ |
4 |
The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots. |
IMAGE_REL_BASED_MIPS_JMPADDR |
5 |
The relocation interpretation is dependent on the machine type. When the machine type is MIPS, the base relocation applies to a MIPS jump instruction. |
IMAGE_REL_BASED_ARM_MOV32 |
5 |
This relocation is meaningfull only when the machine type is ARM or Thumb. The base relocation applies the 32-bit address of a symbol across a consecutive MOVW/MOVT instruction pair. |
IMAGE_REL_BASED_RISCV_HIGH20 |
5 |
This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the high 20 bits of a 32-bit absolute address. |
|
6 |
Reserved, must be zero. |
IMAGE_REL_BASED_THUMB_MOV32 |
7 |
This relocation is meaningful only when the machine type is Thumb. The base relocation applies the 32-bit address of a symbol to a consecutive MOVW/MOVT instruction pair. |
IMAGE_REL_BASED_RISCV_LOW12I |
7 |
This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V I-type instruction format. |
IMAGE_REL_BASED_RISCV_LOW12S |
8 |
This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V S-type instruction format. |
IMAGE_REL_BASED_MIPS_JMPADDR16 |
9 |
The relocation is only meaningful when the machine type is MIPS. The base relocation applies to a MIPS16 jump instruction. |
IMAGE_REL_BASED_DIR64 |
10 |
The base relocation applies the difference to the 64-bit field at offset. |
多少目录表也是二个布局体数组——>每二个结构体里面著录的是各类表所对应的讴歌ZDXVA以致大小
(扩展:
- 区段头表(它是二个结构体数组)是由八个IMAGE_把文件加载进内部存储器。SECTION_HEADE科雷傲那样的结构体组成,以八个全都以0的结构体结尾;
- 导入表也是三个布局体数组(后边会主要讲),以四个全0成分结尾,导入表中的IMAGE_THUNK_DATA(文件未有加载的时候,OrignalFirstThunk与FirstThunk指向IMAGE_THUNK_DATA)也是二个布局体数组;
- 重定位表:它也是叁个构造体数组,以全0成分结尾
- 财富表:它里面也含有结构体数组(更为详细的能够查阅相关文献)
)
别的粤语翻译:
PE中有结构体数组的布局的下结论:
数录节入重!
- 节表(区段头表)
image.png
.text 段:代码段
.data段:数据段
.bss段:表示未早先化的数据,例如Static变量
.rdata 段:表示只读的数码,比方字符串
……
.relcoc段:存款和储蓄重一向音讯的区段
各变量贮存于哪个区:
常量 ——————>.rdata区
静态变量————->.bss区
全局变量————–>.data 区
节表里面包车型大巴多少个根本数据:
VirtualAddress:这一个区段的周旋设想地址
SizeofRawData:那么些区段在磁盘中的大小,实行了文本对齐
PointerToRawData:区段的文件偏移,正是其大器晚成区段在磁盘文件中的伊始地点
贰个最首要的公式:
offset(转)=揽胜VA(需求改动的OdysseyVA)-奇骏VA(所在区段的奥德赛VA)+offset(就是PointerToRawData)
常量 | 值 | 描述 |
IMAGE_REL_BASED_ABSOLUTE | 0x0 | 使块按照32位对齐,位置为0。 |
IMAGE_REL_BASED_HIGH | 0x1 | 高16位必须应用于偏移量所指高字16位。 |
IMAGE_REL_BASED_LOW | 0x2 | 低16位必须应用于偏移量所指低字16位。 |
IMAGE_REL_BASED_HIGHLOW | 0x3 | 全部32位应用于所有32位。 |
IMAGE_REL_BASED_HIGHADJ | 0x4 | 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内。 |
例子:
浅析广泛的dll:在QQ中的 zlib.dll 文件 (在QQ安装目录下的bin文件夹中卡塔尔国:
第生龙活虎找到重定位表,这里运用工具:
找到数据:
VirtualAddress 为 0x1000,SizeOfBlock 为 0x64。第一个条约为
0x338C,高叁个人为 0x3,offset为 0x38C,即偏移地址为 0x138C (由 0x1000 +
0x38C得来卡塔尔国应用于此地址上任何三拾壹人。打开C32Asm反汇编查看: