PE文件结构详解(三)PE导出表
上篇文章 PE文件结构详解(二)可执行文件头 的结尾出现了一个大数组,这个数组中的每一项都是一个特定的结构,通过函数获取数组中的项可以用RtlImageDirectoryEntryToData函数,DataDirectory中的每一项都可以用这个函数获取,函数原型如下:
PVOID NTAPI RtlImageDirectoryEntryToData(PVOID Base, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size);
Base:模块基地址。
MappedAsImage:是否映射为映象。
Directory:数据目录项的索引。
- #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
- #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
- #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
- #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
- #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
- #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
- #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
- // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
- #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
- #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
- #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
- #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
- #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
- #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
- #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
- #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
Size:对应数据目录项的大小,比如Directory为0,则表示导出表的大小。
返回值表示数据目录项的起始地址。
这次来看看第一项:导出表。
导出表是用来描述模块中的导出函数的结构,如果一个模块导出了函数,那么这个函数会被
记录在导出表中,这样通过GetProcAddress函数就能动态获取到函数的地址。函数导出的方式有两种,一种是按名字导出,一种是按序号导出。这两
种导出方式在导出表中的描述方式也不相同。模块的导出函数可以通过Dependency walker工具来查看:
上图中红框位置显示的就是模块的导出函数,有时候显示的导出函数名字中有一些符号,像 ??0CP2PDownloadUIInterface@@QAE@ABV0@@Z,这种是导出了C++的函数名,编译器将名字进行了修饰。
下面看一下导出表的定义吧:
- typedef struct _IMAGE_EXPORT_DIRECTORY {
- DWORD Characteristics;
- DWORD TimeDateStamp;
- WORD MajorVersion;
- WORD MinorVersion;
- DWORD Name;
- DWORD Base;
- DWORD NumberOfFunctions;
- DWORD NumberOfNames;
- DWORD AddressOfFunctions; // RVA from base of image
- DWORD AddressOfNames; // RVA from base of image
- DWORD AddressOfNameOrdinals; // RVA from base of image
- } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
结构还算比较简单,具体每一项的含义如下:
Characteristics:现在没有用到,一般为0。
TimeDateStamp:导出表生成的时间戳,由连接器生成。
MajorVersion,MinorVersion:看名字是版本,实际貌似没有用,都是0。
Name:模块的名字。
Base:序号的基数,按序号导出函数的序号值从Base开始递增。
NumberOfFunctions:所有导出函数的数量。
NumberOfNames:按名字导出函数的数量。
AddressOfFunctions:一个RVA,指向一个DWORD数组,数组中的每一项是一个导出函数的RVA,顺序与导出序号相同。
AddressOfNames:一个RVA,依然指向一个DWORD数组,数组中的每一项仍然是一个RVA,指向一个表示函数名字。
AddressOfNameOrdinals:一个RVA,还是指向一个WORD数组,数组中的每一项与AddressOfNames中的每一项对应,表示该名字的函数在AddressOfFunctions中的序号。
第一次接触这个结构的童鞋被后面的5项搞晕了吧,理解这个结构比结构本身看上去要复杂一些,文字描述不管怎么说都显得晦涩,所谓一图胜千言,无图无真相,直接上图:
在上图中,AddressOfNames
指向一个数组,数组里保存着一组RVA,每个RVA指向一个字符串,这个字符串即导出的函数名,与这个函数名对应的是
AddressOfNameOrdinals中的对应项。获取导出函数地址时,先在AddressOfNames中找到对应的名字,比如Func2,他在AddressOfNames中是第二项,然后从AddressOfNameOrdinals中取出第二项的值,这里是2,表示函数入口保存在AddressOfFunctions这个数组中下标为2的项里,即第三项,取出其中的值,加上模块基地址便是导出函数的地址。如果函数是以序号导出的,那么查找的时候直接用序号减去Base,得到的值就是函数在AddressOfFunctions中的下标。
用代码实现如下:
- DWORD* CEAT::SearchEAT( const char* szName)
- {
- if (IS_VALID_PTR(m_pTable))
- {
- bool bByOrdinal = HIWORD(szName) == 0;
- DWORD* pProcs = (DWORD*)((char*)RVA2VA(m_pTable->AddressOfFunctions));
- if (bByOrdinal)
- {
- DWORD dwOrdinal = (DWORD)szName;
- if (dwOrdinal < m_pTable->NumberOfFunctions && dwOrdinal >= m_pTable->Base)
- {
- return &pProcs[dwOrdinal-m_pTable->Base];
- }
- }
- else
- {
- WORD* pOrdinals = (WORD*)((char*)RVA2VA(m_pTable->AddressOfNameOrdinals));
- DWORD* pNames = (DWORD*)((char*)RVA2VA(m_pTable->AddressOfNames));
- for (unsigned int i=0; i<m_pTable->NumberOfNames; ++i)
- {
- char* pNameVA = (char*)RVA2VA(pNames[i]);
- if (strcmp(szName, pNameVA) != 0)
- {
- continue;
- }
- return &pProcs[pOrdinals[i]];
- }
- }
- }
- return NULL;
- }
PE文件结构详解(三)PE导出表的更多相关文章
- PE文件结构详解(四)PE导入表
PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...
- PE文件结构详解(六)重定位
前面两篇 PE文件结构详解(四)PE导入表 和 PE文件结构详解(五)延迟导入表 介绍了PE文件中比较常用的两种导入方式,不知道大家有没有注意到,在调用导入函数时系统生成的代码是像下面这样的: 在这里 ...
- PE文件结构详解(二)可执行文件头
在PE文件结构详解(一)基本概念里,解释了一些PE文件的一些基本概念,从这篇开始,将详细讲解PE文件中的重要结构. 了解一个文件的格式,最应该首先了解的就是这个文件的文件头的含义,因为几乎所有的文件格 ...
- PE文件结构详解(五)延迟导入表
PE文件结构详解(四)PE导入表讲 了一般的PE导入表,这次我们来看一下另外一种导入表:延迟导入(Delay Import).看名字就知道,这种导入机制导入其他DLL的时机比较“迟”,为什么要迟呢?因 ...
- PE文件结构详解(三)
0x01 前言 上一篇讲到了数据目录表的结构和怎找到到数据目录表(DataDirectory[16]),这篇我们我来讲讲数据目录表后面的另一个结构——区块表. 0x01 区块 区块就是PE载入器将PE ...
- PE文件结构详解(一)基本概念
PE(Portable Execute) 文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任 何扩展名.那 ...
- PE文件结构详解
(注:最左边是文件头的偏移量.) IMAGE_DOS_HEADER STRUCT { +0h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执 ...
- 小甲鱼PE详解之输入表(导出表)详解(PE详解09)
小甲鱼PE详解之输出表(导出表)详解(PE详解09) 当PE 文件被执行的时候,Windows 加载器将文件装入内存并将导入表(Export Table) 登记的动态链接库(一般是DLL 格式)文件一 ...
- PE文件详解(三)
本文转自小甲鱼的PE文件详解系列传送门 PE文件到内存的映射 在执行一个PE文件的时候,windows 并不在一开始就将整个文件读入内存的,二十采用与内存映射文件类似的机制. 也就是说,windows ...
随机推荐
- 20141201--测试 jQuery
测试 JavaScript 框架库 - jQuery jQuery 是一个 JavaScript 库. 引用 jQuery <!DOCTYPE html> <html> < ...
- 【原创】微信公众号与HTML 5混合模式揭秘3——JSSDK获取地理位置
微信公众号与HTML 5混合模式揭秘1——如何部署JSSDK 微信公众号与HTML 5混合模式揭秘2——分享手机相册中照片 JSSDK为开发者提供了两个位置API服务:获取地理位置和使用微信内置地图查 ...
- String中重要方法与字段
下列这段代码已全部包含了我要写的String类中重要的字段: //StringMisc.java// This program demonstrates the length, charAt and ...
- input中的id和name
name在以下用途是不可替代的: 1. 表单(form)的控件名,提交的数据都用控件的name而不是id来控制.因为有许多name会同时对应多个控件,比如checkbox和radio,而id必须是全文 ...
- MySQL触发器 Update触发Insert失败
今天工作需要,想要实现将仅对状态更新的表进行历史记录显示,于是考虑在原表中建立触发器,将更新的内容同时写入另一张表 于是进行测试 --建立测试表CREATE TABLE `triggletest_tr ...
- ExtJS实战 01——HelloWorld
前言 Extjs5的发布已经有些日子了,目前的最新稳定版本是Extjs5.1.0,我们可以在官方网站进行下载.不过笔者今天访问得到的是502Bad Gateway,原因可能是sencha的nigix没 ...
- apache泛域名的配置
假设我们把服务器架设在:/home/www文件夹下面 我们有应用A和B,对应的文件目录为A:/home/www/testAB:/home/www/testB 设置proxy_module让网站支持泛域 ...
- 用nodejs删除mongodb中ObjectId类型数据
mongodb中"_id"下面有个ObjectId类型的数据,想通过这个数据把整个对像删除,费了半天劲终于搞定费话少说上代码 module.exports = function ( ...
- Git客户端Windows下的使用
1,必须安装的软件 msysgit http://code.google.com/p/msysgit/downloads/list?q=full+installer+official+git (ms ...
- C# this指针用法
this指针是什么: 这里有一些面向对象编程的概念需要说明:类(Class)的概念和对象(Object)的概念类是对事物概括,也是C#编码时所有代码归属的基本单位:而对象是对类的实例化,也就是C#里n ...