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;

导出表:

资源表是一个树形结构,可以设置成2的31次方的层数,Windows 使用了3级:

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

  • 上篇文章,我们学习了各种头,Dos,NT,节表头,我们知道,OptionalHeader指向的DataDirectory[]数组一共有16个:

金沙国际官网,类型->名称->语言

AddressOfNames 所指向内容是以 4
字节为一个单位的数组元素,每个元素代表一个指向字符串的 RVA

金沙国际官网 1

金沙国际官网 2

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

  • 我们接下来要学习的有:

 

AddressOfNames 和 AddressOfNamesOrdinals
的数目肯定是一样的,不是一样那么就出错了。

  1. IMAGE_DIRECTORY_ENTRY_IMPORT 导入表
  2. IMAGE_DIRECTORY_ENTRY_BASERELOC 基址重定位表
  3. IMAGE_DIRECTORY_ENTRY_EXPORT 导出表
  4. IMAGE_DIRECTORY_ENTRY_RESOURCE 资源表

其中涉及到四个结构:

主要要掌握两种寻找函数入口地址的方法:

  • 今天我们学习导出表:

 

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

  1. 定位到PE 文件头
  2. 从PE 文件头中的 IMAGE_OPTIONAL_HEADER32
    结构中取出数据目录表,并从第一个数据目录中得到导出表的RVA
  3. 从导出表的 Base 字段得到起始序号
    4.
    将需要查找的导出序号减去起始序号Base,得到函数在入口地址表中的索引,检测索引值是否大于导出表的
    NumberOfFunctions 字段的值,如果大于后者的话,说明输入的序号是无效的
  4. 用这个索引值在 AddressOfFunctions
    字段指向的导出函数入口地址表中取出相应的项目,这就是函数入口地址的RVA
    值,当函数被装入内存的时候,这个RVA
    值加上模块实际装入的基地址,就得到了函数真正的入口地址
  1. 我们知道dll文件,是动态链接库,里面有许多函数给别人调用,但是别人怎么知道里面有什么函数呢?就需要导出表清单给人家看,就如同你去餐厅点餐,却不知道餐厅有什么菜,这时服务生会拿出菜单来,这个菜单就如同导出表。
  2. 所有PE文件都可以有导出表,只是大部分情况下,exe不提供导出表而已。

Data

Description

Resource Directory Tables (and Resource Directory Entries)

A series of tables, one for each group of nodes in the tree. All top-level (Type) nodes are listed in the first table. Entries in this table point to second-level tables. Each second-level tree has the same Type ID but different Name IDs. Third-level trees have the same Type and Name IDs but different Language IDs.

Each individual table is immediately followed by directory entries, in which each entry has a name or numeric identifier and a pointer to a data description or a table at the next lower level.

Resource Directory Strings

Two-byte-aligned Unicode strings, which serve as string data that is pointed to by directory entries.

Resource Data Description

An array of records, pointed to by tables, that describe the actual size and location of the resource data. These records are the leaves in the resource-description tree.

Resource Data

Raw data of the resource section. The size and location information in the Resource Data Descriptions field delimit the individual regions of resource data.

B. 从函数名称查找入口地址

我想通的地方,记录下来:用函数名来查找的话,Base
的值现在没有任何意义

  1. 首先得到导出表的地址
  2. 从导出表的 NumberOfNames
    字段得到已命名函数的总数,并以这个数字作为循环的次数来构造一个循环,从
    AddressOfNames
    字段指向得到的函数名称地址表的第一项开始,在循环中将每一项定义的函数名与要查找的函数名相比较,如果没有任何一个函数名是符合的,表示文件中没有指定名称的函数。
    3.
    如果某一项定义的函数名与要查找的函数名符合,那么记下这个函数名在字符串地址表中的索引值,然后在AddressOfNamesOrdinals
    指向的数组中以同样的索引值取出数组项的值,我们这里假设这个值是 x
  3. 最后,以 x 的值作为索引值在 AddressOfFunctions 
    字段指向的函数入口地址表中获取 RVA 。此 RVA 就是函数的入口地址。

附上图片:

金沙国际官网 3

  • 我们知道OptionalHeader指向的DataDirectory[]数组一共有16个,每个都是一样的结构:

 

  1. VirtualAddress  虚拟偏移地址
  2. size  大小

 

  • NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT
    ],这个数据目录表VirtualAddress指向的是导出表的地址:

 

 

typedef struct _IMAGE_EXPORT_DIRECTORY 
 {
 DWORD Characteristics;//未使用,总是定义为0 
 DWORD TimeDateStamp;//文件生成时间 
 WORD MajorVersion;//未使用,总是定义为0 
 WORD MinorVersion;//未使用,总是定义为0 
 DWORD Name; //模块的真实名称的RVA 
 DWORD Base; //基数,加上序数就是函数地址数组的索引值 
 DWORD NumberOfFunctions;//导出函数的总数 
 DWORD NumberOfNames; //以名称方式导出的函数的总数 
 DWORD AddressOfFunctions; // RVA from base of image指向输出函数地址的RVA 
 DWORD AddressOfNames; // RVA from base of image指向输出函数名字的RVA 
 DWORD AddressOfNameOrdinals; // RVA from base of image向输出函数序号的RVA 

 } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY

Resource Directory Table

Each resource directory
table has the following format. This data structure should be considered
the heading of a table because the table actually consists of directory
entries (described in section 6.9.2, “Resource Directory Entries”) and
this structure:

Offset Size Field Description
0 4 Characteristics Resource flags. This field is reserved for future use. It is currently set to zero.
4 4 Time/Date Stamp The time that the resource data was created by the resource compiler.
8 2 Major Version The major version number, set by the user.
10 2 Minor Version The minor version number, set by the user.
12 2 Number of Name Entries The number of directory entries immediately following the table that use strings to identify Type, Name, or Language entries (depending on the level of the table).
14 2 Number of ID Entries The number of directory entries immediately following the Name entries that use numeric IDs for Type, Name, or Language entries.

 

  1. Characteristics:现在没有用到,一般为0。
  2. TimeDateStamp:导出表生成的时间戳,由连接器生成。
  3. MajorVersion,MinorVersion:看名字是版本,实际貌似没有用,都是0。
  4. Name:模块的名字,就是dll的名称。
  5. Base:序号的基数,按序号导出函数的序号值从Base开始递增。
  6. NumberOfFunctions:所有导出函数的数量。
  7. NumberOfNames:按名字导出函数的数量。
  8. AddressOfFunctions:一个RVA,指向一个DWORD数组,数组中的每一项是一个导出函数的RVA,顺序与导出序号相同。
  9. AddressOfNames:一个RVA,依然指向一个DWORD数组,数组中的每一项仍然是一个RVA,指向一个表示函数名字。
  10. AddressOfNameOrdinals:一个RVA,还是指向一个WORD数组,数组中的每一项与AddressOfNames中的每一项对应,表示该名字的函数在AddressOfFunctions中的序号。

Resource Directory Entries

The directory entries
make up the rows of a table. Each resource directory entry has the
following format. Whether the entry is a Name or ID entry is indicated
by the resource directory table, which indicates how many Name and ID
entries follow it (remember that all the Name entries precede all the ID
entries for the table). All entries for the table are sorted in
ascending order: the Name entries by case-sensitive string and the ID
entries by numeric value.  Offsets are relative to the address in the
IMAGE_DIRECTORY_ENTRY_RESOURCE DataDirectory.

Offset

Size

Field

Description

0

4

Name Offset

The offset of a string that gives the Type, Name, or Language ID entry, depending on level of table.

0

4

Integer ID

A 32-bit integer that identifies the Type, Name, or Language ID entry.

4

4

Data Entry Offset

High bit 0. Address of a Resource Data entry (a leaf).

4

4

Subdirectory Offset

High bit 1. The lower 31 bits are the address of another resource directory table (the next level down).

 

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

Resource Directory String

The resource directory
string area consists of Unicode strings, which are word-aligned. These
strings are stored together after the last Resource Directory entry and
before the first Resource Data entry. This minimizes the impact of these
variable-length strings on the alignment of the fixed-size directory
entries. Each resource directory string has the following format:

Offset

Size

Field

Description

0

2

Length

The size of the string, not including length field itself.

2

variable

Unicode String

The variable-length Unicode string data, word-aligned.

金沙国际官网 4

 

金沙国际官网 5

Resource Data Entry

Each Resource Data
entry describes an actual unit of raw data in the Resource Data area. A
Resource Data entry has the following format:

Offset

Size

Field

Description

  0

4

Data RVA

The address of a unit
of resource data in the Resource Data area.

  4

4

Size

The size, in bytes, of
the resource data that is pointed to by the Data RVA field.

  8

4

Codepage

The code page that is
used to decode code point values within the resource data. Typically,
the code page would be the Unicode code page.

12

4

Reserved, must be
0.

  • AddressOfFunctions 指向所有函数的地址。
  • AddressOfNames 指向名字的地址。
  • AddressOfNameOrdinals 指向一个序号。

  • 查找导出表代码(c/c++):

    int main(int argc, char *argv[])
    {
    PIMAGE_DOS_HEADER Pdos = (PIMAGE_DOS_HEADER)GetModuleHandle(L”user32.dll”);

 PIMAGE_NT_HEADERS Pnt = (PIMAGE_NT_HEADERS)((int)Pdos->e_lfanew + (int)Pdos);

 IMAGE_OPTIONAL_HEADER32 Popt = Pnt->OptionalHeader;

 IMAGE_EXPORT_DIRECTORY * Export;
 Export = (IMAGE_EXPORT_DIRECTORY*)(Popt.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)Pdos);

 DWORD * AllAddress;
 DWORD * AllName;
 USHORT * AllOrg;

 AllAddress = (DWORD*)((int)Export->AddressOfFunctions + (int)Pdos);//函数地址数组
 AllName = (DWORD*)((int)Export->AddressOfNames + (int)Pdos);//函数名称数组
 AllOrg = (USHORT *)((int)Export->AddressOfNameOrdinals + (int)Pdos);//序号数组


 int OneAddress;
 char * OneName;
 USHORT OneOrg;
 char * Buf = new char[500];
 int ListId = NULL;

 for (int i = 0; i < (int)Export->NumberOfNames; i++)
 {

 OneName = (char*)((BYTE*)Pdos + AllName[i]);
 OneOrg = (USHORT)AllOrg[i];
 OneAddress = (int)((int)Pdos + AllAddress[OneOrg]);

 printf("Name: %s, Org :%d,Address :%x\n", OneName, OneOrg, OneAddress);
 }

 return 0;
}

金沙国际官网 6

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图