基址重定位澳门金莎娱乐网站,PE结构分析

2019-11-02 08:59 来源:未知

源代码如下:

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;    // 未使用,总为0 

    DWORD   TimeDateStamp;      // 文件创建时间戳
    WORD    MajorVersion;       // 未使用,总为0 

    WORD    MinorVersion;       // 未使用,总为0
    DWORD   Name;               // 指向一个代表此 DLL名字的 ASCII字符串的 RVA
    DWORD   Base;               // 函数的起始序号
    DWORD   NumberOfFunctions;  // 导出函数的总数

    DWORD   NumberOfNames;      // 以名称方式导出的函数的总数

    DWORD   AddressOfFunctions;     // 指向输出函数地址的RVA
    DWORD   AddressOfNames;         // 指向输出函数名字的RVA
    DWORD   AddressOfNameOrdinals;  // 指向输出函数序号的RVA

} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

在 PE文件头的 IMAGE_OPTIONAL_HEADEXC90 结构中的 DataDirectory(数据目录表) 的第一个分子正是指向输入表的。各类被链接进来的 DLL文件都各自对应二个IMAGE_IMPORT_DESC科雷傲IPTOMurano (简单称谓IID) 数组结构。

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

AddressOfFunctions 所指向内容是以 4 字节为七个单位的数组元素,每一个成分代表函数入口

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

重定位表是二个数组,那一个数组的尺寸记载在 _IMAGE_OPTIONAL_HEADER 的

AddressOfNames 所指向内容是以 4 字节为三个单位的数组成分,每一种成分代表一个针对性字符串的 奇骏VA

在此个 IID数组中,并未提议有多少个项(就是从未明确性指明有稍许个链接文件),但它最终是以二个全为NULL(0) 的 IID 作为完成的标识。

.DataDirect‌​ory[IMAGE_DIRECTORY_E‌​NTRY_BASERELOC].Size 成员中

AddressOfNamesOrdinals 所指向内容是以 2 字节为一个单位的数组成分,每一种成分代表对应名字在 AddressOfFunctions 中的序号数。

下边只摘录非常首要的字段:

结构图如下,图片中 0 和 000 都代表16进制数,调换成二进制是  0000 和 0000 0000 0000:

AddressOfNames 和 AddressOfNamesOrdinals 的多寡鲜明是一样的,不是同样那么就出错了。

OriginalFirstThunk

它指向first thunk,IMAGE_THUNK_DATA,该 thunk 拥有 Hint 和 Function name 的地址。

澳门金莎娱乐网站 1

关键要驾驭二种检索函数入口地址的办法:

Name

它意味着DLL 名称的对峙虚地址(译注:相对三个用null作为完成符的ASCII字符串的三个大切诺基VA,该字符串是该导入DLL文件的名目。如:KE凯雷德NEL32.DLL)。

各种成分的大小都记载在 SizeOfBlock 中,这几个因素是由 八个 _IMAGE_BASE_RELOCATION 结构体和叁个TypeOffset 数组组成的。TypeOffset 数组的每一个成分占2个字节,此中,高4位是偏移类型(type),低九个人表示须求重一直的地点(Offset),即,它与 VirtualAddress 相加正是指向 PE 影像中必要校订的十二分代码的奥迪Q3VA。

A. 从序号查找函数入口地址

  1. 定位到PE 文件头
  2. 从PE 文件头中的 IMAGE_OPTIONAL_HEADE揽胜极光32 结构中收取数据目录表,并从第一个数据目录中拿走导出表的帕杰罗VA
  3. 从导出表的 Base 字段获得起先序号
    4. 将供给搜索的导出序号减去起始序号Base,获得函数在入口地址表中的索引,检查测试索引值是否高于导出表的 NumberOfFunctions 字段的值,即使超越后面一个的话,表达输入的序号是没用的
  4. 用这一个索引值在 AddressOfFunctions 字段指向的导出函数入口地址表中收取相应的类型,那正是函数入口地址的RAV4VA 值,当函数棉被服装入内部存款和储蓄器的时候,那些奥迪Q5VA 值加上模块实际装入的营地址,就获得了函数真正的进口地址

FirstThunk

它含有由IMAGE_THUNK_DATA定义的 first thunk数组的虚地址,通过loader用函数虚地址开端化thunk。

在Orignal First Thunk缺席下,它指向first thunk:Hints和The Function names的thunks。

 

上面来讲授下OriginalFirstThunk和FirstThunk。就个人精通来说:

1. 在文书中时,他们都各自针对八个奇骏VA地址。那么些地址转产生文件中,分别对应五个以 IMAGE_THUNK_DATA 为元素的的数组,那三个数组是以多个填写为 0 的IMAGE_THUNK_DATA作为完成标记符。尽管她们那八个表地方区别,但实在内容是一模一样的。那时,每一个IMAGE_THUNK_DATA 成分指向的是二个笔录了函数名和相对应的DLL文件名的 IMAGE_IMPORT_BY_NAME结构体。

  1. 怎会有两个同样的数组呢?是有案由的:

OriginalFirstThunk 指向的数组经常称得上  hint-name table,即 HNT ,他在 PE 加载到内部存款和储蓄器中时被封存了下来且永世不会被涂改。可是在 Windows 加载过 PE 到内部存款和储蓄器之后,Windows 会重写 FirstThunk 所指向的数组成分中的内容,使得数组中每一种 IMAGE_THUNK_DATA 不再代表针对带有函数描述的 IMAGE_THUNK_DATA 成分,而是直接指向了函数地址。当时,FirstThunk 所指向的数组就叫做输入地址表(Import Address Table ,即经常说的 IAT)。

重写前:

澳门金莎娱乐网站 2

重写后:

 澳门金莎娱乐网站 3

(以上两张图纸来源:)

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE  指向一个转向者字符串的RVA
        DWORD Function;             // PDWORD 被输入的函数的内存地址
         DWORD Ordinal;              // 被输入的 API 的序数值
         DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME   指向 IMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

根据 _IMAGE_THUNK_DATA32 所指虚构地址转到文件地方能够博得实质上的 _IMAGE_IMPORT_BY_NAME 数据

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD   Hint;     // 序号 

    CHAR   Name[1];  // 实际上是一个可变长的以0为结尾的字符串

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

 

比方有程序:

澳门金莎娱乐网站 4

文字版:

#include <windows.h>
int WINAPI WinMain(_In_ HINSTANCE hInstance, 
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine,
    _In_ int nShowCmd)
{
    MessageBoxA(0, "hello", "my message", MB_OK);
    SetWindowTextA(0, "Si Wang");

    return 0;
}

此程序选取了七个 Windows API : Message博克斯A 和 SetWindowTextA

编写翻译获得程序(为简化表明,区段地方由软件计算出):

澳门金莎娱乐网站 5

澳门金莎娱乐网站 6

笔者们试着寻觅 MessageBoxA。首先深入分析 PE 头文件,找到导出表在文件中之处:

澳门金莎娱乐网站 7

输入表地点在 .rdata 区段内, 0x2264 – 0x2001 = 0x0264 获得偏移量。加上文件地方 0x0E00 获得实质上文件偏移量(0x0E00 + 0x264 = 0x1064):0x1064。

接下去查看 0x1064 处:

澳门金莎娱乐网站 8

能够赢得多个 DLL 的叙说,最后三个_IMAGE_IMPORT_DESC传祺IPTOR以0填充表示甘休:

那么只要二个个翻看各类DLL对应的数据就能够找到,然则以前自身把具有的数目都看了下,在首先个DLL中

依据第三个DLL描述的 OriginalFirstThunk 的 0x2350 转变能够驾驭,_IMAGE_THUNK_DATA32 在文件的 0x1150处,FirstThunk 指向的数码后生可畏致:

澳门金莎娱乐网站 9

于是乎就获取了文本中的 MessageBoxA 的音讯。

末尾,在内部存款和储蓄器中 FirstThunk 所指地方上的_IMAGE_THUNK_DATA32 数组被 Windows 加载后被重写后就成了故事中的 IAT ,Import Address Table,输入地址表。使用 OllyDbg 查看运维时情形:

澳门金莎娱乐网站 10

TAG标签:
版权声明:本文由澳门金莎娱乐网站发布于澳门金莎娱乐网站,转载请注明出处:基址重定位澳门金莎娱乐网站,PE结构分析