PE文件(1)导入表

PE文件(1)导入表

概念

导入函数的代码位于一个或者多个DLL中,在调用者程序中只保留一些相关的函数信息,包括函数名及其对应的DLL名等。
对于磁盘上的PE 文件来说,它无法得知这些输入函数将来在内存中的地址,只有当PE 文件被装入内存后,Windows的 加载器才将相关DLL 装入,并将调用导入函数的指令和函数实际所处的地址联系起来。
这就是“动态链接”的概念。动态链接是通过PE 文件中定义的“导入表”来完成的,导入表中保存的正是函数名和其对应的DLL 名等。

定位导入表

每一个程序中都有多个模块,包括第一模块exe和众多的dll模块,
其中在第一模块exe中有多张导入表,而在其他每张dll中则都有一张导出表。(一般情况下)

导入表就在exe进程空间的PEB结构的PE文件中(并不是PE文件在PEB结构中),而是该模块的PEB结构中的成员ImageBaseAddress成员是整个PE文件的基地址。所以首先打开对方进程空间PEB,利用PEB中的一个PE文件基地址,PE文件中有导入表的偏移,PE文件的基地址加上这个偏移得到导入表的基地址

1.获得exe模块下PEB结构中PE文件的基地址

PEB     Peb = { 0 };
ULONG_PTR ModuleBase = 0;   
ModuleBase = (ULONG_PTR)Peb.ImageBaseAddress;

//注意:以下的所有结构都是微软公开的
//整个获取过程是在讲目标进程的PE文件读取到自己的内存中实现的ReadProcessMemory,所以读取NT之前必须先读取Dos头,(NT头的基地址由Dos头确定ModuleBase + ImageDosHeader.e_lfanew,而Dos基地址也就是PE文件基地址是上述的Peb.ImageBaseAddress)

2.获得导入表的偏移:
IMAGE_NT_HEADERS32(NT头)结构体的
(OptionalHeader成员)IMAGE_OPTIONAL_HEADER32结构体中的
(DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]成员IMAGE_DATA_DIRECTORY结构体的VirtualAddress成员

DWORD  v1 = 0;
v1 = ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

最后得到导入表的基地址:(ModuleBase + v1)

导入表结构

这里写图片描述

可以看出导入表结构实际上就是三个结构体数组
1.

typedef struct  _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD  Characteristics;
        DWORD  OriginalFirstThunk;//输入名称表INT的RAV  
    };
    DWORD  TimoeDateStamp;            //文件生成时间
    DWORD  ForwaiderChain;
    DWORD  Name;                      //DLL名称的RVA(一个用null作为结束符的ASCII字符串的一个RVA,该字符串是该导入DLL文件的名称,如:KERNEL32.DLL)
    DWORD  FirstThunk;                //输入地址表IAT的RAV  
} IMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor = { 0 };//导入描述符结构

2.

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

typedef struct _IMAGE_THUNK_DATA64 {
    union {
        ULONGLONG ForwarderString;  // PBYTE 
        ULONGLONG Function;         // PDWORD
        ULONGLONG Ordinal;
        ULONGLONG AddressOfData;    // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;

当 IMAGE_THUNK_DATA 值的最高位为 1时,表示函数以序号方式导入,这时候低 31位被看作一个函数序号。(可以用预定义值IMAGE_ORDINAL_FLAG32或80000000h来对最高位进行测试)。
当 IMAGE_THUNK_DATA 值的最高位为 0时,表示函数以字符串类型的函数名方式导入,这时双字的值是一个 RVA,指向一IMAGE_IMPORT_BY_NAME 结构。
3.

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

Hint 字段也表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为 0,
Name1字段定义了导入函数的名称字符串,这是一个以 0 为结尾的字符串。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值