VA <----> FileOffset
术语:
- RVA:RVA 是相对虚拟地址(Relative Virtual Address)的缩写,它是文件映射到内存中的“相对地址”。
- FOA:FOA是文件偏移地址(File Offest Address)的缩写,它是文件在磁盘上存放时相对文件开头的偏移地址。
LordPE的位置偏移功能的确很方便,但始终还是要熟悉原理,才能写出操作PE的代码。
有一条公式可以帮助我们很方便的计算出文件偏移的位置。
`文件偏移(磁盘文件的位置 FOA)``=``相对虚拟地址(任意RVA)``-``该区段相对虚拟地址(RVA)``+``该区段的文件偏移(offset)`
要转换的相对虚拟地址会落在一个区段中是因为每个偏移,不管是在文件中,还是在内存中,它们距离区段开始位置的距离总是相等的。
该区段相对虚拟地址(RVA) <--对应--> IMAGE_SECTION_HEADER.VirtualAddress
该区段的文件偏移(offset) <--对应--> IMAGE_SECTION_HEADER.PointerToRawData
在写代码前我们首先弄清楚基本概念。
根据上图看出,区段装入内存之后的偏移与文件偏移是存在差异的。所以当我们进行文件偏移与虚拟内存地址之间换算时,首先要得出所转换的地址在第几区段内。每个区段的含义如下。
输入表(IAT)
IMAGE_IMPORT_DESCRIPTOR
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
DWORD ForwarderChain; // -1 if no forwarders
DWORD Name;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
OriginalFirstThunk 指向的数组通常叫做 hint-name table,即 INT ,他在 PE 加载到内存中时被保留了下来且永远不会被修改。但是在 Windows 加载过 PE 到内存之后,PE装载器会重写 FirstThunk 所指向的数组元素中的内容,使得数组中每个 IMAGE_THUNK_DATA 不再表示指向带有函数描述的 IMAGE_THUNK_DATA 元素,而是直接指向了函数地址。此时,FirstThunk 所指向的数组就称之为输入地址表(Import Address Table ,即经常说的 IAT)。
IMAGE_THUNK_DATA STRUC
union u1
ForwarderString DWORD ? ; 指向一个转向者字符串的RVA
Function DWORD ? ; 被输入的函数的内存地址
Ordinal DWORD ? ; 被输入的API 的序数值
AddressOfData DWORD ? ; 指向 IMAGE_IMPORT_BY_NAME
ends
IMAGE_THUNK_DATA ENDS
当 IMAGE_THUNK_DATA 值的最高位为 1时,表示函数以序号方式输入,这时候低 31位被看作一个函数序号。
当 IMAGE_THUNK_DATA 值的最高位为 0时,表示函数以字符串类型的函数名方式输入,这时双字的值是一个 RVA,指向一个 IMAGE_IMPORT_BY_NAME 结构。(演示请看小甲鱼解密系列视频讲座)
IMAGE_IMPORT_BY_NAME STRUCT
Hint WORD ?
Name BYTE ?
IMAGE_IMPORT_BY_NAME ENDS
结构中的 Hint 字段也表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为 0。
Name 字段定义了导入函数的名称字符串,这是一个以 0 为结尾的字符串。
输入表(IAT)绑定
在程序装在运行之前就讲IAT表进行填充为真实的函数地址
并将IDD(IMAGE_DATADIRTORY)的第12个成员IMAGE_BOUND_IMPORT_DESCRIPTOR结构,该结构有被绑定的DLL信息的修改时间戳等验证信息,如果真实的DLL信息与此结构信息不一致时则重新生成IAT输入表。如DLL文件无改动则直接使用IAT指向的函数,以此来达到加快程序初始化阶段。
评论区