一次性进群,长期免费索取教程,没有付费教程。
教程列表见微信公众号底部菜单
进微信群回复公众号:微信群;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