节表数据

导入表

导入表查看

  在 IMAGE_OPTIONAL_HEADER 结构体中 DataDirectory 字段,给出了数据目录结构体,定义如下

//
// Directory format.
//

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;        // 实际上数据目录的 RVA
    DWORD   Size;                  // 数据目录项的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

  VirtualAddress:PE 文件载入内存之后的 RVA(相对虚拟地址)。

  Size:导入表大小

  导入表的 FOA:地址转换看PE 结构的三种地址

导入表的结构

  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;

IMAGE_IMPORT_DESCRIPTOR(汇编)

 IMAGE_IMPORT_DESCRIPTOR STRUCT
    union
        Characteristics dd      ?
        OriginalFirstThunk dd   ?
    ends
    TimeDateStamp dd    ?
    ForwarderChain dd   ?
    Name1 dd            ?
    FirstThunk dd       ?
IMAGE_IMPORT_DESCRIPTOR ENDS

  OriginalFirstThunk:保存了指向导入表函数名称(序号)的 RVA 表,这个表是个 IMAGE_THUNK_DATA 结构体。

  Name:导入模块名称的 RVA。

  FirstThunk:指向导入地址表的 RVA,在 PE 文件没有被装载前它的内容与 OriginalFirstThunk 指向相同的内容,装载内存之后,它的值发生变化,里面保存导入函数的实际地址。

 

  IMAGE_THUNK_DATA 结构体,具有 32 位和 64 位,定义如下:

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

 IMAGE_THUNK_DATA32(汇编)

IMAGE_THUNK_DATA32 STRUCT
    union u1
        ForwarderString dd  ?
        Function dd         ?
        Ordinal dd          ?
        AddressOfData dd    ?
    ends
IMAGE_THUNK_DATA32 ENDS

  Oridinal:导入函数的序号,当 IMAGE_THUNK_DATA 的最到位为 1 时,该值有效。

  AddressOfData:指向 IMAGE_IMPORT_BY_NAME 结构体的 RVA,当 IMAGE_THUNK_DATA 的最到位不为 1 时,该值有效。

  通过这两个字段的解释可以明白,Oridinal 和 AddressOfData 本质上是一个值,但是在使用时取决于 IMAGE_THUNK_DATA 的最高位。当 IMAGE_THUNK_DATA 的最到位为 1 时,使用的是序号进行导入的函数,导入函数的序号是 Oridinal 的低 31 位;当最高位不为 1 时,说明导入函数是通过名称进行导入的,而 AddressOfData 保存了指向 IMAGE_IMPORT_BY_NAME 的 RVA。

  IMAGE_IMPORT_BY_NAME 结构体的定义如下:

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
IMAGE_IMPORT_BY_NAME(汇编)
 IMAGE_IMPORT_BY_NAME STRUCT
    Hint dw     ?
    Name1 db    ?
IMAGE_IMPORT_BY_NAME ENDS

  Hint:表示该函数在导出函数表中导出函数名称对应的序号,该值不是必须的。

  Name:导入函数的函数名称。导入函数是一个以 ASCII 编码保存的字符串,并以 NULL 结尾。IMAGE_IMPORT_BY_NAME 中使用 NAME[1] 来定义该字段,表示该字段是一个只有 1 字节长度的字符串数组。在实际中函数名称不可能只有 1 个字节的长度,其实这是一种编程的技巧,通过数组越界来进行访问变长字符串的功能。

OriginalFirstThunk 和 FirstThunk 的区别

      在 IMAGE_IMPORT_DESCRIPTOR 结构体中的 OriginalFirstThunk 和 FirstThunk 都指向了 IMAGE_THUNK_DATA 结构体,但是两者是有区别的。当 PE 文件在磁盘上时,两者都指向的 IMAGE_THUNK_DATA 结构体中保存的是相同的内容,而当文件被载入内存后,两者指向的 IMAGE_THUNK_DATA 结构体中保存的内容就不相同了。

  PE 文件在磁盘上时,OriginalFirstThunk 指向的 IMAGE_THUNK_DATA 中保存的是导入函数的序号或者指向导入函数名称的 RVA,因此称为导入名称表。即 INT。FirstThunk 指向的 IMAGE_THUNK_DATA 中保存的也是导入函数的序号或者指向导入函数名称的 RVA。此时,它们在磁盘上是没有区别的。

  当 PE 文件从磁盘装载入内存中后,OriginalFirstThunk 指向的 IMAGE_THUNK_DATA 中保存的仍然是导入函数的序号或者指向导入函数名称的 RVA。而 FirstThunk 指向的 IMAGE_THUNK_DATA 中则被 Windows 操作系统的 PE 装载器填充为导入函数的地址,因此这里被称为导入地址表,即 IAT。所以 FirstThunk 所指向的 IMAGE_THUNK_DATA 在内存中保存的是导入函数实际地址。

手动分析导入表

重定位表

  重定位表查找同导入表一样,在数据目录索引为 5 的位置。

  IMAGE_BASE_RELOCATION 结构体定义如下:

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
IMAGE_BASE_RELOCATION(汇编)
 IMAGE_BASE_RELOCATION STRUCT
    VirtualAddress dd   ?
    SizeOfBlock dd      ?
IMAGE_BASE_RELOCATION ENDS

  重定位表由多个 IMAGE_BASE_RELOCATION 组合而成。

  VirtualAddress:重定位数据的起始 RVA 地址。

  SizeOfBlock:当前区段重定位结构的大小。该大小不是 IMAGE_BASE_RELOCATION 结构体的大小,IMAGE_BASE_RELOCATION 结构体的大小是 8 字节,该字段的大小还包括重定位数据的大小,即 8 字节 + N*WORD。

  TypeOffset:重定位数据的数组。每个 TypeOffset 都是 WORD 类型,占用 16 个字节。高 4 位表示该 TypeOffset 的类型,低 12 位表示“区段”内需要重定位的“偏移地址”,由低 12 位与 VirtualAddress 相加就是需要进行重定位的 RVA 地址。在 Win32 下,所有的重定位类型都是 IMAGE_REL_BASED_HIGHLOW。在 Winnt.h 头文件中,TypeOffset 是被注释掉的。

TypeOffset 取值
 //
// Based relocation types.
//

#define IMAGE_REL_BASED_ABSOLUTE              0
#define IMAGE_REL_BASED_HIGH                  1
#define IMAGE_REL_BASED_LOW                   2
#define IMAGE_REL_BASED_HIGHLOW               3
#define IMAGE_REL_BASED_HIGHADJ               4
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5    5
#define IMAGE_REL_BASED_RESERVED              6
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7    7
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8    8
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9    9
#define IMAGE_REL_BASED_DIR64                 10
  

 

posted @ 2023-02-06 13:28  liert  阅读(37)  评论(0编辑  收藏  举报