当前位置: 首页 > 编程日记 > 正文

PE文件和COFF文件格式分析——导出表的应用——一种插件模型

可能在很多人想想中,只有DLL才有导出表,而Exe不应该有导出表。而在《PE文件和COFF文件格式分析——导出表》中,我却避开了这个话题。我就是想在本文中讨论下载Exe中存在导出表的场景。(转载请指明出于breaksoftware的csdn博客)

首先要说的是Exe是可以有导出表的,我用我写的PE分析工具扫描了我电脑上所有文件。发现有导出表的Exe文件还不少。比如chrome.exe。

还有OllyDBG.EXE。

我一开始还不能理解为什么要在Exe中搞导出函数。后来查了相关资料,发现这样做是为了方便开发插件,这让我一下焕然大悟。

现在思考一个过程,我们的Exe程序的逻辑可能需要若干Dll中函数来辅助。如下图

A.exe需要B.dll、C.dll和D.dll辅助。现在我们要支持插件,那么我们需要提供一些接口函数供插件使用。比如我们要提供B1()、C1()和D1()供插件使用,那如何设计呢?

最简单的办法就是不做设计,插件要动态LoadLibrary我们的B.dll、C.dll和D.dll,然后把各个函数导出来用。看似很方便,但是如果我们工程不止是3个Dll呢?暴露的函数也不止这三个呢?我想做这个系统的插件的同学想到要Load那么多DLL就会感觉烦!而且还有一个严重的问题,哪天我们想给B.dll改个名字,叫E.dll,那么使用B.dll的插件都不能正常工作了。可以见得这是个非常不稳定的方案,因为它关联的因素太多了。

那我们收敛一下方案,我们做个空壳DLL(使用《PE文件和COFF文件格式分析——导出表》介绍的类似于Kernel32.dll的AddVectoredExceptionHandler导出方法,这个方法的应用我会在之后写篇文章介绍),该DLL就导出B.dll中B1()、C.dll中C1()和D.dll中D1()的入口地址。然后插件就加载这个DLL,调用该DLL中的方法。如下图

这样就很好解决了之前的不足。貌似离最佳不远了,但是想想,是不是还可以优化呢?我们这么设计要多维护一个DLL(PluginHelper.dll),这个也就引入了一个不稳定因素。那么这个DLL可以省掉么?省掉后导出的那些函数放哪儿?

经过考虑,PluginHelper.dll的功能放在哪个DLL文件中都不合适。那只能放在A.exe中了。是的!我们让A.exe导出函数,反正我们A.exe也是要加载B.dll、C.dll和D.dll,这样还可以省下PluginHelper.dll加载如上DLL的过程。现在我写了一个工程,模拟这种插件模型。

ExeMain是我们的主程序,DllOne和DllTwo是ExeMain需要加载的DLL,它们也提供了插件需要暴露给插件的函数的实现。Plugin是个插件。

我们先看下DLLOne和DllTwo的导出函数

LIBRARY	"DllOne"
EXPORTSRet1
LIBRARY	"DllTwo"
EXPORTSRet2

那么在Exe中如何暴露这两个函数呢?看Exe中的代码

typedef int (WINAPI* RetNFunc)();extern "C" __declspec(dllexport) int MainRet1();
extern "C" __declspec(dllexport) int MainRet2();int MainRet1(){int nRet = 0;HMODULE hDllOne = LoadLibraryA("DllOne.dll");do {if ( NULL == hDllOne ) {break;}RetNFunc pFunc = (RetNFunc)GetProcAddress( hDllOne, "Ret1" );nRet = pFunc();FreeLibrary( hDllOne );hDllOne = NULL;} while (0);return nRet;
}int MainRet2(){int nRet = 0;HMODULE hDllTwo = LoadLibraryA("DllTwo.dll");do {if ( NULL == hDllTwo ) {break;}RetNFunc pFunc = (RetNFunc)GetProcAddress( hDllTwo, "Ret2" );pFunc();FreeLibrary( hDllTwo );hDllTwo = NULL;} while (0);return nRet;
}

我们看下Exe的导出函数表

至于插件的调用,我这儿不准备搞复杂的设计,我这儿将直接Load插件DLL,并调用DLL中的导出方法(该方法的调用约定是提前确定好的)。调用方法是

typedef void (WINAPI* PluginFunc)();
int _tmain(int argc, _TCHAR* argv[])
{HMODULE hPlugin = LoadLibraryA("Plugin.dll");do {if ( NULL == hPlugin ) {break;}PluginFunc pFunc = (PluginFunc)GetProcAddress( hPlugin, "PluginMain" );pFunc();FreeLibrary( hPlugin );hPlugin = NULL;} while (0);system("pause");return 0;
}

那么插件该如何写呢?插件的逻辑代码如下

LIBRARY	"Plugin"
EXPORTSPluginMain

typedef int (WINAPI* RetNFunc)();void PluginMain() {RetNFunc pFun1 = (RetNFunc)GetProcAddress( GetModuleHandle(NULL), "MainRet1" );if ( NULL != pFun1 ) {printf( "MainRet1: %d\n", pFun1() );}RetNFunc pFun2 = (RetNFunc)GetProcAddress( GetModuleHandle(NULL), "MainRet2" );if ( NULL != pFun2 ) {printf( "MainRet2: %d\n", pFun2());}
}

因为插件DLL已经被Exe加载,所以此处GetModuleHandle(NULL)会得到该进程Exe的模块句柄,GetProcAddress该句柄的导出方法,就可以获得了Exe中导出的函数入口地址了。

看!这样的插件模型是不是非常简单而且紧凑而且易用。

附上工程

相关文章:

IBatis.Net学习笔记九--动态选择Dao的设计分析

在IBatis.Net中可以通过配置文件动态选择数据库、动态选择Dao对象。Dao对象也就是操作数据库的类,通过配置文件我们可以选择DataMapper的方式、Ado的方式、NHibernet的方式以前其他第三方的方式来操作数据库。有利于系统的灵活性和可扩展性。通过分析动态选择Dao的设…

Pytorch和Tensorflow,谁会笑到最后?

作者 | 土豆变成泥来源 | 知秋路(ID:gh_4a538bd95663)【导读】作为谷歌tensorflow某项目的Contributor,已经迅速弃坑转向Pytorch。目前Tensorflow还没有被Pytorch比下去,但之后极大概率被比下去。01 在学术界Pytorch已经超越Tenso…

HTTP请求的过程

HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1. 建立TCP连接在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同…

JSTL+EL表达式方法获取Oracle的Clob字段内容

我们在页面获得数据的时候一般的类型还是很好获得的,但是一遇到Clob类型就比较麻烦,最常用的方法是用一个流将其读取出来.使用MVC框架的时候这些都是无所谓的事情,因为反正是写在java类中怎么写都行,可是不使用MVC框架,使用jsp页面JSTL的sql标签去读取数据库的数据这种方式就麻…

通向人工智能产业落地化的道路在哪?

整理 | 夕颜出品 | AI科技大本营(ID:rgznai100)世事浮云,白云苍狗,转眼间关于人工智能的研究已历经两个世纪。在研究者和践行者的不懈努力之下,如今人工智能应用已遍地可见,无论是繁华都市还是偏远小镇&…

PE文件和COFF文件格式分析——导出表的应用——通过导出表隐性加载DLL

通过导出表隐性加载DLL?导出表?加载DLL?还隐性?是的。如果觉得不可思议,可以先看《PE文件和COFF文件格式分析——导出表》中关于“导出地址表”的详细介绍。(转载请指明出于breaksoftware的csdn博客&#x…

系统启动时,spring配置文件解析失败,报”cvc-elt.1: 找不到元素 'beans' 的声明“异常...

现象:spring加载配置文件applicationContext.xml出错,抛出nested exception is og.xml.sax.SAXParseException; lineNumber: 12; columnNumber: 47; cvc-elt.1: 找不到元素 beans 的声明r的异常信息。 造成该异常原因有两种:第一,配置文件头部配置的xsd版…

DllMain中不当操作导致死锁问题的分析--死锁介绍

最近在网上看到一些关于在DllMain中不当操作导致死锁的问题,也没找到比较确切的解答,这极大吸引了我研究这个问题的兴趣。我花了一点时间研究了下,正好也趁机研究了下进程对DllMain的调用规律。因为整个研究篇幅比较长,我觉得还是…

XGBoost缺失值引发的问题及其深度分析 | CSDN博文精选

作者 | 兆军(美团配送事业部算法平台团队技术专家)来源 | 美团技术团队(*点击阅读原文,查看美团技术团队更多文章)背景XGBoost模型作为机器学习中的一大“杀器”,被广泛应用于数据科学竞赛和工业领域&#…

什么是CPI指数和GDP

即消费者物价指数(Consumer Price Index),英文缩写为CPI,是反映与居民生活有关的产品及劳务价格统计出来的物价变动指标,通常作为观察通货膨胀水平的重要指标。如果消费者物价指数升幅过大,表明通胀已经成为经济不稳定因素&#x…

The Ultimate Guide To iPhone Resolutions

2019独角兽企业重金招聘Python工程师标准>>> ios 屏幕尺寸 像素 等说明 转载于:https://my.oschina.net/starmier/blog/467271

DllMain中不当操作导致死锁问题的分析--进程对DllMain函数的调用规律的研究和分析

不知道大家是否思考过一个过程:系统试图运行我们写的程序,它是怎么知道程序起始位置的?很多同学想到,我们在编写程序时有个函数,类似Main这样的名字。是的!这就是系统给我们提供的控制程序最开始的地方&…

力挺Python!同是程序员,为啥同事年前就实现了财务自由?

人红是非多,最近Python就遇到了这样的问题。与技术社区上一片「形势大好」对比鲜明的是,国内技术圈却一直存在对Python,「力挺」和「吃瓜」两派阵营,针锋相对,那么,Python到底有没有用,真相究竟…

C# 判断远程文件是否存在

#region 判断远程文件是否存在/// <summary>/// 判断远程文件是否存在/// </summary>/// <param name"fileUrl"></param>/// <returns></returns>public static bool RemoteFileExists(string fileUrl){HttpWebRequest re null…

DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子

有了前面两节的基础&#xff0c;我们现在切入正题&#xff1a;研究下DllMain为什么会因为不当操作导致死锁的问题。首先我们看一段比较经典的“DllMain中死锁”代码。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; //主线程中 HMODULE h LoadLibraryA(strD…

性能超FPN!北大、阿里等提多层特征金字塔网络

作者 | Qijie Zhao等编译 | 李杰出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;特征金字塔网络具有处理不同物体尺度变化的能力&#xff0c;因此被广泛应用到one-stage目标检测网络&#xff08;如DSSD&#xff0c;RetinaNet&#xff0c;RefineDet&#xff09;和two-…

什么是WIFI

WIFI全称Wireless Fidelity&#xff0c;又称802.11b标准&#xff0c;它的最大优点就是传输速度较高&#xff0c;可以达到11Mbps&#xff0c;另外它的有效距离也很长&#xff0c;同时也与已有的各种802.11DSSS设备兼容。 WIFI是由AP(Access Point)和无线网卡组成的无线网络。…

Android入门——电话拨号器和4种点击事件

关于HelloWorld为,电话拨号程序还AndroidA入门demo,从这个样例我们要理清楚做安卓项目的思路。大体分为三步&#xff1a; 1.理解需求&#xff0c;理清思路 2.设计UI 3.代码实现 电话拨号器 1. 理解需求&#xff1a; *一个文本框——用来接收电话号码 *一个button——用来触发事…

DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2

本文介绍使用Windbg去验证《DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子》中的结论&#xff0c;调试对象是文中刚开始那个例子。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 1 g 让程序运行起来 2 ctrlbreak 中断程序 3 ~ 查看…

从入门到深入:移动平台模型裁剪与优化的技术探索与工程实践

可以看到&#xff0c;通过机器学习技术&#xff0c;软件或服务的功能和体验得到了质的提升。比如&#xff0c;我们甚至可以通过启发式引擎智能地预测并调节云计算分布式系统的节点压力&#xff0c;以此改善服务的弹性和稳定性&#xff0c;这是多么美妙。而对移动平台来说&#…

我在不炎熱也不抑鬱的秋天,依然不抽煙

写过几次电影的观后感,挺过瘾.最近看到my little airport的那张新唱片,再也没有办法保持沉默了 为什么人家的唱片名都起的和小说一样,难得是为了证明听歌的人们都不喜欢动笔吗? 于是,我建了个类别,叫 我也会听歌.很明显,这里面会塞一些和歌相关的东西 这是第一篇

ubuntu安装redis的方法以及PHP安装redis扩展、CI框架sess使用redis的方法

为什么80%的码农都做不了架构师&#xff1f;>>> 再一次被网上那些教程误导后决定自己写一个。真心被那些奇怪的教程误导了好几次&#xff0c;之前研究其它东西的时候也是。蛋疼啊。 安装redis 直接用apt-get命令即可 sudo apt-get install redis-server 安装的时候…

浅谈数据库设计技巧

说到数据库&#xff0c;我认为不能不先谈数据结构。1996年&#xff0c;在我初入大学学习计算机编程时&#xff0c;当时的老师就告诉我们说&#xff1a;计算机程序&#xff1d;数据结构&#xff0b;算法。尽管现在的程序开发已由面向过程为主逐步过渡到面向对象为主&#xff0c;…

避免神经网络过拟合的5种技术(附链接) | CSDN博文精选

作者 | Abhinav Sagar翻译 | 陈超校对 | 王琦来源 | 数据派THU(ID:DatapiTHU)(*点击阅读原文&#xff0c;查看作者更多精彩文章&#xff09;本文介绍了5种在训练神经网络中避免过拟合的技术。 最近一年我一直致力于深度学习领域。这段时间里&#xff0c;我使用过很多神经网络&a…

DllMain中不当操作导致死锁问题的分析--加载卸载DLL与DllMain死锁的关系

前几篇文章一直没有在源码级证明&#xff1a;DllMain在收到DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH时会进入临界区。这个论证非常重要&#xff0c;因为它是使其他线程不能进入临界区从而导致死锁的关键。我构造了在DLL被映射到进程地址空间的场景&#xff0c;请看死锁时加载DL…

LinearLayout增加divider分割线

2019独角兽企业重金招聘Python工程师标准>>> 在android3.0及后面的版本在LinearLayout里增加了个分割线 android:divider"drawable/shape"<!--分割线图片--> android:showDividers"middle|beginning|end" <!--分割线位置--> 分割线…

JAVA游戏编程之二----j2me MIDlet 手机游戏入门开发--贪吃蛇

作者&#xff1a;雷神 QQ:38929568 QQ群&#xff1a;28048051JAVA游戏编程&#xff08;满&#xff09; 28047782&#xff08;将满&#xff09; 与前一款扫雷比较&#xff0c;这个游戏多了一个 类&#xff0c;用来显示动画&#xff0c;也是蛇要吃的物品类&#xff0c; 也有了代码…

DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁

之前的几篇文章已经讲解了在DllMain中创建并等待线程导致的死锁的原因。是否还记得&#xff0c;我们分析了半天汇编才知道在线程中的死锁位置。如果对于缺乏调试经验的同学来说&#xff0c;可能发现这个位置有点麻烦。那么本文就介绍几个例子&#xff0c;它们会在线程明显的位置…

如何从菜鸡变成收割机,大厂面试的算法,你懂了吗?

是什么&#xff1f;让大厂面试显得逼格很高&#xff0c;是算法和数据结构吗&#xff1f;是的&#xff01;&#xff01;&#xff01;Google工程师曾总结过&#xff0c;大厂之所以爱考察算法和数据结构是因为&#xff1a;算法能力能够准确辨别一个程序员的技术功底是否扎实&#…

Ejabberd源码解析前奏--配置

一、基本配置 配置文件将在你第一次启动ejabberd时加载&#xff0c;从该文件中获得的内容将被解析并存储到内部的ejabberd数据库中&#xff0c;以后的配置将从数据库加载&#xff0c;并且任何配置文件里的命令都会被添加到数据库里。 需要注意的是&#xff1a;ejabberd从不编辑…