壳执行流程
壳程序入口—>解密原程序—>重定位—>EIP指向源程序OEP
PE
DOS header
PE header
SECTION table
VA: 虚拟内存地址(Virtual Address)
PE 文件被操作系统加载进内存后的地址。
RVA: PE文件的相对虚拟地址(Relative Virual Address)
是PE文件中的数据、模块等运行在内存中的实际地址相对PE文件装载到内存的基址之间的距离。举例说明,如果PE文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h。
FOA:
文件偏移地址(File Offset Address),和内存无关,它是指某个位置距离文件头的偏移。
RVA FOA
RVA->VA
VA=ImageBase+RVA
FOA->VA
1.RVA找到所在Section
2.Section RVA-SECTIONBASE
3.RAW+OFFSET
简化:FOA=(RVA-SECTIONRVA)+BASEFOA
导入表
IMAGE_IMPORT_DESCRIPTOR
每个IID代表一个DLL
0
1
2
3
4
5
6
7
8
9
10
|
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk; // 指向 导入名称表INT(ImportNameTable)的RVA
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; // 指向 DLL名称的地址 RVA
DWORD FirstThunk; // 指向 导入地址表IAT(ImportAddressTable)的RVA
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
|
FirstThunk -》IAT
导入表FOA = 导入表RVA - 区段RVA + 区段FOA
导入表VA = 加载基址BaseImage + 导入表RVA
导出表
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions; //导出函数数量
DWORD NumberOfNames;//按名字导出函数的数量
DWORD AddressOfFunctions; // DWORD数组 记录导出函数RVA
DWORD AddressOfNames; // DWORD数组 记录导出函数名字
DWORD AddressOfNameOrdinals;
// WORD 数组 数组中的每一项与AddressOfNames中的每一项对应,
//表示该名字的函数在AddressOfFunctions中的序号。
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
|
重定位
0
1
2
3
4
5
|
typedef struct _MyReloadtion {
DWORD virtualAddress;
DWORD sizeOfBlock;
vector<WORD> typeOffset; //高4位表类型,一般都是3000 低12位表示偏移量
//所以这里ebx实际上就是 ebx = virtualAddress + typeOffset低12位
}MyReloadtion, *pMyReloadtion;
|
重定位表的作用就是:当实际加载到内存中的Imagebase与本该加载时候的Imagebase地址不同的时候 就需要进行修复重定位表
重定位表修复场景
1.脱壳后
脱壳前重定位表记载的是壳程序的重定位表
脱壳后需要修复重定位表