Windows 网络编程:DLL编程

2019 年 1 月 25 日 计算机与网络安全

一次性进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单

微信群回复公众号:微信群QQ群460500587



微信公众号:计算机与网络安全

ID:Computer-network

DLL(Dynamic Link Library,动态链接库)是一个可以被其他应用程序调用的程序模块,其中封装了可以被调用的资源和函数。动态链接库的扩展名一般是.DLL,不过有时也可能是其他的。DLL文件也属于可执行文件,只不过它是依附于EXE文件来被执行的。一个DLL文件可以被多个EXE文件加载。


一、什么是DLL


Windows操作系统下有非常多的DLL文件,有的是操作系统的DLL文件,有的是应用程序的DLL文件。DLL文件有什么好处呢?DLL是动态链接库,相对应的有静态链接库。动态链接库是在EXE文件运行时被加载执行的,而静态链接库是在OBJ文件进行连接时同时被保存到程序中。动态链接库可以减少可执行文件的体积,在需要的时候进入内存等很多好处。


二、编写一个简单的DLL程序


我们编写一个简单的DLL程序,并在DLL程序中添加一个导出函数。所谓导出函数,就是DLL提供给外部EXE或其他类型的可执行文件调用的函数,当然DLL本身也可以自己进行调用。我们启动VC6来编写一个DLL程序。


启动VC6程序,单击菜单“文件”->“新建”命令,在“Projects”选项卡中的左边选择“Win32 Dynamic-Link Library”,在“Project name:”文本框中填写“FirstDll”,如图1所示。

图1  新建DLL工程

单击“OK”按钮,出现“Win32 Dynamic-Link Library– Step 1 of 1”界面,选择“A simple DLL Project”项,单击“Finish”按钮。在然后出现的对话框中直接单击“OK”按钮即可。在创建好该工程后,VC6自动生成如下代码:

DLL程序的入口函数是DllMain(),该函数有以下3个参数。


(1)hModule:DLL模块的句柄。


(2)ul_reason_for_call:DllMain函数被调用的原因。


该参数的取值有4种,分别是DLL_PROCESS_ATTACH(当DLL被某进程加载时DllMain被调用)、DLL_PROCESS_DETACH (当DLL被某进程卸载时DllMain被调用)、DLL_THREAD_ATTACH (进程中有线程被创建时DllMain被调用)和DLL_THREAD_DETACH(进程中有线程结束时DllMain被调用)。


(3)lpReserved:保留项,也就是Windows的保留参数。所谓保留参数不是不使用的参数,是Windows不想让我们知道作用的参数。

WINAPI也是一个宏,该宏表示一种函数调用约定。

这样写就可以达到根据不同的调用原因执行不同的代码。我们添加一个简单的导出函数。


该函数的定义如下:

运行函数后弹出一个对话框,显示一个字符串,并显示其所在的进程的进程名。我们分别在DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH下加一个对该函数的调用,代码如下:

编译该代码,会生成两个对我们有用的文件,一个是“FirstDll.dll”,另外一个是“FirstDll.lib”,前面的是DLL文件,后面的是库文件,该库文件中包含着导出函数的相关信息。

三、对DLL程序的调用方法一


DLL程序就写到这里,接下来写个调用该DLL的程序测试一下吧。我们需要对该DLL进行两方面的测试,一个是看当加载和卸载该DLL时,是否会弹出对话框;另外一个是调用这个DLL的导出函数看是否能成功。


在工作区的“Workspace ‘FirstDll’:1project”上单击右键,在弹出的菜单中选择“Add New Project to Workspace …”,如图2所示。

图2  添加测试工程

弹出“New”对话框,在“Projects”选项卡的左面选择“Win32 Console Application”,在“Project name:”文本框中填写:“DllTest1”。单击“OK”按钮,在出现的对话框中选择“A Simple Application”,该处和前面内容类似。在左面的工作区打开我们新建的工程,在DllTest1.cpp中添加代码:

对该代码进行编译连接,这时并没有生成我们想要的可执行文件,在编译连接过程中出错了。


这个错误确切地说是连接错误,原因是找不到DLL的Lib文件,我们把“FristDll.lib”文件复制到DllTest1这个工程的目录下,再次编译连接,这次通过了。那么我们就来运行这个DllTest1的程序。不过很可惜,运行出错,错误提示如图3所示。

图3运行DllTest1时的错误信息

这个错误的原因是DllTest1找不到FirstDll.dll这个文件,把开始编译好的这个文件也复制到DllTest1的工程目录下,再次运行,这次一切正常,并且看到弹出3次对话框,说明DLL程序已经能够正常运行了。


四、对DLL程序的调用方法二


第一种方法是属于静态调用,现在的第二种方法属于动态调用。静态调用就是在编译测试程序DllTest1时,FirstDll.dll的信息就已经写入了DllTest1的程序中了。对于动态加载的话,就不是编译时完成了,而是在运行时完成,那么FirstDll.dll的信息也不会写入测试程序中了。现在来写一个DllTest2程序,该程序的建立方法与DllTest1的建立方法相同。DllTest2的代码如下:

我们对代码进行编译连接,正常编译通过。那么就运行该程序,提示“FirstDll.dll文件不存在”,这说明DllTest2程序没有找到FirstDll.dll文件。把FirstDll.dll文件拷贝到DllTest2的工程目录下,再次运行该程序,这次运行成功了,并且应该弹出的3个对话框也都正常弹出了。我们的测试也是成功的。


DLL的动态加载是非常有用的,在DllTest1中,如果无法找到DLL文件,系统会直接报错而退出,而在DllTest2中,如果无法找到DLL文件,程序会给出一个错误提示,并且可以继续运行,而不影响其他代码的运行。除此而外,如果知道一些API函数,而这些API函数是未文档化的函数,或者是没有提供头文件的API函数,要怎么办呢?比如在前面的内容中用到的函数OpenThread(),该函数在VC6默认的PSDK中是没有提供定义的,在新的PSDK中才有,那如何使用呢?那就需要用到LoadLibrary()和GetProcAddress()这两个API函数了。看一下LoadLibrary()和GetProcAddress()这两个函数的定义:

该函数只有一个参数,就是要加载的DLL文件的文件名。

该函数有两个参数,hModule是模块的句柄,lpProcName指定要获取函数地址的函数名称。


在关于DLL话题的最后,介绍一下如何查看DLL程序的导出函数。在这里介绍两个工具,一个工具是VC6自带的工具“Depends”,另一个工具是用来查看PE结构的工具“PEID”。


首先用“Depends”来查看DLL的导出函数,如何找到这个工具呢?在VC6的安装菜单下就可以找到该工具。方法如下:单击菜单“开始”->“程序”->“Microsoft Visual Studio6.0”->“Microsoft Visual Studio 6.0 Tools”->“Depends”命令,打开该程序,再单击菜单“File”->“Open…”命令,在“打开”对话框中找到我们写的FirstDll.dll文件并打开,如图4所示。

图4  Depends界面

右下角这个区域范围就是我们的导出函数部分,这里可以看到导出函数“MsgBox”。


除了这个工具以外,再介绍一个工具——PEID。该工具是用来进行查壳的工具,我们把FirstDll.dll文件拖曳到PEID界面上,PEID会自动解析出该DLL文件的PE结构,该界面如图5所示。

图5  PEID界面

可以看到,PEID最下方的编辑框处显示出DLL是由VC6开发的,而且版本是Debug版本。单击“子系统”右边的“”按钮,会显示PE结构的详细信息,在详细信息的下半部分有一个“目录信息”,在“目录信息”中第一个就是我们想要查看的导出函数的内容,单击“导出表”右面的“大于号按钮”按钮,出现如图6所示的界面。

图6  导出表信息

因为DLL中只有一个导出函数MsgBox(),那么该导出表中就只有一个导出项。


对于DLL的编程就介绍到这里了,希望大家可以自己动手完成这个简单的DLL文件。

微信公众号:计算机与网络安全

ID:Computer-network

【推荐书籍】
登录查看更多
1

相关内容

【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
Python导论,476页pdf,现代Python计算
专知会员服务
259+阅读 · 2020年5月17日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
用 Python 开发 Excel 宏脚本的神器
私募工场
26+阅读 · 2019年9月8日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
C# 10分钟完成百度人脸识别
DotNet
3+阅读 · 2019年2月17日
逆向 | C++ 加壳程序的编写思路
计算机与网络安全
9+阅读 · 2019年1月1日
Python3.7中一种懒加载的方式
Python程序员
3+阅读 · 2018年4月27日
刚开始学编程?这几款小工具能让你事半功倍
Arxiv
10+阅读 · 2020年4月5日
AliCoCo: Alibaba E-commerce Cognitive Concept Net
Arxiv
13+阅读 · 2020年3月30日
Arxiv
15+阅读 · 2020年2月6日
Factor Graph Attention
Arxiv
6+阅读 · 2019年4月11日
Feature Selection Library (MATLAB Toolbox)
Arxiv
7+阅读 · 2018年8月6日
VIP会员
相关资讯
用 Python 开发 Excel 宏脚本的神器
私募工场
26+阅读 · 2019年9月8日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
C# 10分钟完成百度人脸识别
DotNet
3+阅读 · 2019年2月17日
逆向 | C++ 加壳程序的编写思路
计算机与网络安全
9+阅读 · 2019年1月1日
Python3.7中一种懒加载的方式
Python程序员
3+阅读 · 2018年4月27日
刚开始学编程?这几款小工具能让你事半功倍
Top
微信扫码咨询专知VIP会员