购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.2 动态链接库简介

3.2.1 动态链接库概述

话说这个Windows API太好用了,方便了俺老张。

呵呵,Windows API就是为了方便,让大家在不用了解底层的情况下就可以完成某些功能。

那军师你说有没有更方便的东西,让俺这种懒人不费吹灰之力就能写出强大的黑客工具?

想得倒美,不过Windows为了方便我们调用API,还发明了一种叫做动态链接库的东西,我跟你介绍下它。

动态链接库(DLL,Dynamic Link Library的缩写形式)是作为共享函数库的可执行文件。动态链接库提供了一种方法,使进程可以调用不属于其自身可执行代码的函数。函数的可执行代码位于一个DLL中,该DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL副本的内容。DLL是一个包含可由多个程序同时使用的代码和数据的库。例如,在Windows操作系统中,Comdlg32.DLL执行与对话框有关的常见函数。因此,每个程序都可以使用该DLL中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。

微软为什么要发明DLL啊,它都有哪些好处?

简要来说有两点:

通过使用DL L,程序可以实现模块化,使之由相对独立的组件构成。例如,一个程序可以按模块来销售。可以在运行时将各个模块加载到主程序中(如果安装了相应模块)。因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才被加载。

此外,可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。例如,用户可能具有一个存款计算程序,而利率每年都会更改。当这些更改被隔离到DLL中以后,无需重新生成或安装整个程序,就可以应用更新。

太好了,这确实方便了不少,适合俺老张这种懒人。

创建动态链接库工程的方法和创建其他工程差别不大,下面就为你演示下。

3.2.2 编写动态链接库

1)新建项目,选择Win32项目,在名称中输入“CustomDll”,单击“确定”按钮。在随后出现的Win32应用程序向导中单击“下一步”按钮,进行如图3.2所示的选择,单击“完成”按钮,完成该工程的创建。

图3.2

2)从菜单栏中单击“项目”→“添加新项”命令,在弹出的“添加新项”对话框中选择“头文件(.h)”,在“名称”文本框中输入“CustomDll”,单击“添加”按钮,并在其中加入如下代码。

3)从菜单栏中单击“项目”→“添加新项”命令,在弹出的“添加新项”对话框中选择“C++文件(.cpp)”,在“名称”文本框中输入“CustomDll”,单击“添加”,并在其中加入如下代码。

4)从菜单栏中单击“生成”→“生成解决方案”命令(快捷键“F7”),编译链接程序。

这段代码好奇怪啊,俺只知道main()函数,从没见过什么DllMain()。

这个DllMain()就是动态链接库的入口点,Windows在库装载、卸载,线程创建和结束时都要调用入口函数,以便动态链接库可以采取相应的动作。

DllMain函数中,hModule参数是该DLL模块的句柄,代表这个文件的映像加载到进程的地址空间时使用的基地址。ul_reason_for_call参数的值表示本次调用的原因,可能是下列4种情况中的某一种。

●DLL_PROCESS_ATTACH:表示动态链接库刚被某个进程加载。程序可以在这里做一些初始化工作,并返回TRUE表示初始化成功,返回FALSE表示初始化出错,这样库的装载就会失败。这给了动态链接库一个选择是否被载入的机会。

●DLL_PROCESS_DETACH:表示动态链接库将被卸载。程序可以在这里进行一些资源的释放工作,如关闭文件、释放内存等。

●DLL_THREAD_ATTACH:表示应用程序创建了一个新的线程。

●DLL_THREAD_DETACH:表示某个线程正常终止。

DLL都还没搞清楚,进程和线程又钻出来了。军师,你耍俺啊?

谁叫你平时不多看点书,至于这里提到的进程与线程的概念,我待会再告诉你吧,现在先说DLL函数。

DLL能够定义两种函数:内部函数和导出函数。内部函数只能被定义这个函数的模块调用,而导出函数不仅可以在本模块调用,还可以被其他模块调用。

DLL的主要功能是向外导出函数,供进程中的其他模块使用。要想将函数导出供其他模块调用,需要在头文件中进行声明。例如,在本例中的函数即为导出函数,在头文件“CustomDll.h”中进行了声明。

3.2.3 使用动态链接库

调用DLL有两种方法:隐式动态链接和显式动态链接。

这倒是好记,一隐一显。军师让我看看它们具体是怎么调用的。

1.隐式动态链接

模块可以像调用本地函数一样调用从其他模块导入的函数,但这种方法必须使用DLL的导入库(.lib文件),它为系统提供了加载这个DLL和定位DLL中的导入函数所需的信息。

新建一个名称为“TestDll”的Win32控制台项目,并添加C++文件“TestDll.cpp”。然后在前面编写的DLL项目中把“CustomDll.h”、“CustomDll.lib”、“CustomDll.dll”三个文件复制到TestDll目录下,最后在“TestDll.cpp”文件中加入如下代码。

#pragma命令指明要链接到“CustomDll.lib”库。也可以不使用该语句,但要将“CustomDll.lib”文件添加到项目中。使用隐式动态链接动态库要指明库文件所在的路径,并且静态编译会导致生成的可执行文件体积变大,这也是用该方法加载DLL库的缺点。按“Ctrl+F5”组合链编译运行程序,显示结果如图3.3所示。

图3.3

2.显式动态链接

模块使用LoadLibrary()或者LoadLibraryEx()函数显式加载DLL。DLL被加载之后,加载模块调用GetProcAddress()函数取得DLL导出函数的地址,然后通过函数地址调用DLL中的函数。显示动态链接是在程序运行过程中显式地去加载DLL库,从中导出需要的函数。一般需要在原DLL工程中建立一个模块定义文件(DEF)来指定要导出的函数。

在原CustomDll工程中,单击菜单栏的“项目”→“添加新项”命令,在弹出的“添加新项”对话框中选择“模块定义文件(.def)”,输入名称“Custo-mDll”,单击“添加”按钮,并在其中加入如下内容:

这两行代码说明此DLL库要向外导出DLLFuncAdd函数,最后按“F7”键重新编译CustomDll工程。回到工程TestDll中,将代码做如下修改。

运行程序,结果和上面的一样,同样输出“32”。

军师,俺觉着第一种方法不错,简单方便,倒是第二种方法太过复杂,俺不学了中不?

这万万不可,我重点给你介绍的就是第二种方法,它在黑客编程中经常会用到。

啊,那你再详细给俺说说。

调用DLL导出函数分为3步进行。

1)声明要导出的DLL函数,注意类型和参数的一致性。

2)加载目标DLL,利用LoadLibrary()函数加载指定目录下的DLL库到进程的虚拟地址空间,函数执行成功,返回此DLL模块的句柄,否则返回NULL。

LoadLibrary()函数声明如下:

功能: 加载指定名称的动态链接库。

参数:

lpFileName:动态链接库的名称。

返回值: 函数执行成功返回动态链接库的句柄。

3)最后由GetProcAddress()函数来获得目标DLL中导出函数的地址。

GetProcAddress()函数声明如下:

功能: 获得目标动态链接库中导出函数的地址。

参数:

hModule:函数所在模块的句柄。

lpProcName:函数的名称。

返回值: 函数执行成功返回函数的地址,否则返回NULL。

当不使用DLL模块时,应调用FreeLibrary()函数释放它占用的资源。 uiq+yhmt/jtSnQIpNvQ6gwUSNfpfPdPoNpNd0LfnPaDSklW+INuuUly38jB/OGRs

点击中间区域
呼出菜单
上一章
目录
下一章
×