0x01  导出表结构

    导出表是由数据目录表中的第一个成员DataDirectory[0]指出的:

 typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

   

    导出表就是记载着动态链接库的一些导出信息。通过导出表,DLL 文件可以向系统提供导出函数的名称、序号和入口地址等信息,比便Windows 加载器通过这些信息来完成动态连接的整个过程。扩展名为.exe 的PE 文件中一般不存在导出表,而大部分的.dll 文件中都包含导出表。但这并不是绝对的。例如纯粹用作资源的.dll 文件就不需要导出函数啦,另外有些特殊功能的.exe 文件也会存在导出函数。

    当PE文件被加载为模块时候,Windows加载器会将导入表中登记的DLL文件一并装入,再根据DLL文件中的函数导出信息对被执行文件的IAT表进行修正。

    Windows 在加载一个程序后就会在内存中为该程序开辟一个单独的4G虚拟地址空间(x86下)。有一些函数很多程序都会用到,为每一个程序所调用的相同的函数都占用一次内存空间显得很浪费,因此Windows提出了了动态链接库的概念,将一些常用的函数封装成动态链接库,等到需要的时候通过直接加载动态链接库,将需要的函数映射到自己的地址空间中,从而提高了内存的利用率。

  

     导出表的结构成员: 1 typedef struct _IMAGE_EXPORT_DIRECTORY {

     DWORD   Characteristics;        //未使用,总是定义为0
DWORD TimeDateStamp; //文件生成时间
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;            //模块的真实名称RVA
DWORD Base;            //导出函数序号的起始值,将AddressOfFunctions 字段指向的入口地址表的索引号加上这个起始值就是对应函数的导出序号。假如Base 字段的值为x,那么入口地址表指定的第1个导出函数的序号就是x;第2个导出函数的序号就是x+1。总之,一个导出函数的导出序号等于Base 字段的值加上其在入口地址表中的位置索引值。
DWORD NumberOfFunctions;   //导出函数的个数 DWORD NumberOfNames;      //名称方式导出的函数的总数。有的导出函数是没有名字的,只有序号
DWORD AddressOfFunctions; //一个RVA 值,指向包含全部导出函数入口地址的双字数组(EAT)。数组中的每一项是一个RVA 值,数组的项数等于NumberOfFunctions 字段的值。
DWORD AddressOfNames; //一个RVA 值,指向函数名字符串地址表。这个地址表是一个双字数组,数组中的每一项指向一个函数名称字符串的RVA。数组的项数等NumberOfNames 字段的值,所有有名称的导出函数的名称字符串都定义在这个表中
DWORD AddressOfNameOrdinals; //一个RVA 值,指向另一个word 类型的数组(注意不是双字数组)。数组项目与文件名地址表中的项目一一对应,项目值代表函数入口地址表的索引,这样函 数名称与函数入口地址关联起来,起到一个桥梁的作用。
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

  

0x02  关键问题

(1)通过函数序号得到函数地址: 

    1>由DOS头定位到PE头。

    2>由PE头定位到PE头中的中的 可选头IMAGE_OPTIONAL_HEADER32 结构中取出数据目录表,并从第一个数据目录中得到导出表的RVA。

    3>从导出表的 Base 字段得到起始序号。

    4>将需要查找的导出序号减去起始序号,得到函数在入口地址表中的索引。

    5>检测索引值是否大于导出表的 NumberOfFunctions 字段的值,如果大于后者的话,说明输入的序号是无效的。

    6>用这个索引值在 AddressOfFunctions 字段指向的导出函数入口地址表中取出相应的项目,这就是函数入口地址的RVA 值,当函数被装入内存的时候,这个RVA 值加上模块实际装入的基地址,就得到函数真正的入口地址。

(2)通过函数名称得到函数地址:

    1>由DOS头定位到PE头。(同上)

    2>由PE头定位到PE头中的中的 可选头IMAGE_OPTIONAL_HEADER32 结构中取出数据目录表,并从第一个数据目录中得到导出表的RVA。(同上)   

    3>从导出表的NumberOfNames 字段得到已命名函数的总数,并以这个数字作为循环的次数来构造一个循环。

    4>从AddressOfNames 字段指向得到的函数名称地址表的第一项开始,在循环中将每一项定义的函数名与要查找的函数名相比较,如果没有任何一个函数名是符合的,表示文件中没有指定名称的函数。

    5>如果某一项定义的函数名与要查找的函数名符合,那么记下这个函数名在字符串地址表中的索引值,然后在AddressOfNamesOrdinals 指向的数组中以同样的索引值取出数组项的值,我们这里假设这个值是x。

    6>以 x 值作为索引值,在 AddressOfFunctions 字段指向的函数入口地址表中获取的 RVA 加上模块基地址就是函数的入口地址。

PE文件 02 导出表的更多相关文章

  1. 【学习】Windows PE文件学习(一:导出表)

    今天做了一个读取PE文件导出表的小程序,用来学习. 参考了<Windows PE权威指南>一书. 首先, PE文件的全称是Portable Executable,可移植的可执行的文件,常见 ...

  2. 【C#进阶系列】02 PE文件,程序集,托管模块,元数据——还是那个Hello world

    好了,还是这张图,还是一样的Hello world. 因为本章其实很多都是讲一些命令行编译啊什么鬼的配置类的东西,要用的时候直接百度或者回头查书就可以了, 所以了解一下也就行了,也没有记录下来,接下来 ...

  3. 浅析MSIL中间语言——PE文件结构篇

    一.开篇 开篇我想讲一下于本文无关的话题,其实我很想美化一下自己博客园一直没时间弄,无意间找了博客园李宝亨的博客园里面有一篇分享自己主题的文章,我就将这个模板暂时用作我的blog主题,我要讲述一个关于 ...

  4. .NET的PE文件结构篇(转)

    一.开篇 开篇我要讲述一个关于PE文件结构的文章,这篇文章动手能力比较强,希望大家能够动手进行操作,这边文章篇幅有可能会长一些,为了方便大家阅读我可以将其分为几个部分进行讲解,主要分为以下几个部分: ...

  5. PE文件学习系列三-PE头详解

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com 最近比较忙 ...

  6. 修改PE文件的入口函数OEP

    修改入口函数地址.这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节.当然,如果.text节空隙足够大的话,不用添加新节也可以. BOOL Chan ...

  7. PE文件之资源讲解

    资源是PE文件中非常重要的部分,几乎所有的PE文件中都包含资源,与导入表与导出表相比,资源的组织方式要复杂得多,要了解资源的话,重点在于了解资源整体上的组织结构. 我们知道,PE文件资源中的内容包括: ...

  8. 手写PE文件(一)

    DOS Header(IMAGE_DOS_HEADER)->64 Byte DOS头部 DOS Stub 112字节 "PE"00(Signature) 4个字节 IMAGE ...

  9. 打造XP下可运行的微型PE文件

    前几天和朋友交流技术,提到手工打造微型PE文件,他说现在网上流传的大部分版本在XP SP3下都不能运行,于是心血来潮,拍着胸脯说:“你放心,忙完了帮你做一个.”后来花了半天时间,终于打造出一个XP下可 ...

随机推荐

  1. English Voice of <<Beautiful now>>

    Beautiful Now  -Zedd & Jon Bellion I see what you're wearing, there's nothing beneath it 我看见了你身着 ...

  2. Confluence 6 有关空间的一些提示

    如果你已经为你的整个 Confluence 站点设置了特定主题(例如文档或者其他第三方的主题),你创建的空间将会集成你需要主题.如果你没有使用默认主题的话,你可能不能在边栏中看见蓝图. Conflue ...

  3. lanmp中环境变量的更改方法

    1.vim /etc/profile 改成: export PATH=$PATH:/www/wdlinux/phps/71/bin/ 然后运行: source /etc/profile

  4. 直播 APP 的直播实现流程

    直播平台搭建所涉及的事项非常的广泛, 不仅需要直播源码. 直播系统开发. 后台服务 器.专门的运维人员等, 还需要技术团队切实的把控.下面, 小编就给大家确切的说下直播 平台搭建需要用到哪些步骤. 1 ...

  5. LitePal 数据库使用方法(最新2.0LitePal数据库适用)

    转发郭神的blog,讲的非常详细,是基于1.6版本,但现在使用的是2.0,有点差别https://blog.csdn.net/guolin_blog/article/details/384612391 ...

  6. deepin系统安装成功了之后重启电脑没有deepin启动选项的简单解决办法

    开机 连续按 f10(我的电脑是惠普的,由于主板的不同可能启动键也有所不同)进入 bios 界面如图 选择系统设置,启动选项  之后如图 选择 uefi  模式下的开机顺序栏的  操作系统管理员选项并 ...

  7. 删除 github 相应仓库下的文件(不删除仓库)

    1.git  clone url(仓库的ssh) 将仓库克隆 到本地 2.进入到本地仓库文件夹 将想要删除的文件删除 3.右键 git bash here 4.git add . 5.git comm ...

  8. bzoj3529: [Sdoi2014]数表 莫比乌斯反演

    题意:求\(\sum_{i=1}^n\sum_{j=1}^nf(gcd(i,j))(gcd(i,j)<=a),f(x)是x的因子和函数\) 先考虑没有限制的情况,考虑枚举gcd为x,那么有\(\ ...

  9. 关于react16.4——错误边界

    过去,组件内的 JavaScript 错误常常会破坏 React 内部状态,并导致它在下一次渲染时产生神秘的错误.这些错误总会在应用代码中较早的错误引发的,但 React 并没有提供一种方式能够在组件 ...

  10. C++的面试题

    1.什么是类? 类是具有相同属性和相同的方法的对象的集合,它是一种既包含数据又包含函数的抽象数据类型. 对象是类进行实体化后的产物,是一个实体. 在C++中也是先声明一个类类型,用类去定义若干个同类型 ...