动态链接库DLL编程.ppt

上传人:本田雅阁 文档编号:3112465 上传时间:2019-07-10 格式:PPT 页数:61 大小:783.02KB
返回 下载 相关 举报
动态链接库DLL编程.ppt_第1页
第1页 / 共61页
动态链接库DLL编程.ppt_第2页
第2页 / 共61页
动态链接库DLL编程.ppt_第3页
第3页 / 共61页
动态链接库DLL编程.ppt_第4页
第4页 / 共61页
动态链接库DLL编程.ppt_第5页
第5页 / 共61页
点击查看更多>>
资源描述

《动态链接库DLL编程.ppt》由会员分享,可在线阅读,更多相关《动态链接库DLL编程.ppt(61页珍藏版)》请在三一文库上搜索。

1、,VC+动态链接库(DLL)编程,1.概论,先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。 在仓库的发展史上经历了“无库静态链接库动态链接库”的时代。 对动态链接库,需建立如下概念:,(1)与具体的编程语言及编译器无关,只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。 譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C+还是Delphi。,(2)动态链接

2、库随处可见,在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。 kernel32.dll中的函数主要处理内存管理和进程调度; user32.dll中的函数主要控制用户界面(MessageBox函数); gdi32.dll中的函数则负责图形方面的操作。,(3)VC动态链接库的分类,Visual C+支持三种DLL,它们分别是非MFC动态库、MFC规则DLL、MFC Extension DLL。 非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC

3、编写的应用程序所调用; MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环; MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。,2.静态链接库,在VC+6.0中new一个名称为libTest的static library工程,并新建lib.h和lib.cpp两个文件,lib.h和lib.cpp的源代码如下: /文件:lib.h #ifndef LIB_H #define LIB_H extern “C“ int add(int x,int y); /声明为C编译、连接方式的外部函数 #endif /文件:lib.cpp #include

4、 “lib.h“ int add(int x,int y) return x + y; ,#include #include “lib.h“ #pragma comment( lib, “debuglibTest.lib“ ) /指定与静态库一起连接 int main(int argc, char* argv) printf( “2 + 3 = %d“, add( 2, 3 ) ); ,选择tools、options、directories、library files菜单或选项,填入库文件路径,4.非MFC DLL,在建立的工程中添加lib.h及lib.cpp文件,源代码如下:,/* 文件名:

5、lib.h */ #ifndef LIB_H #define LIB_H extern “C“ int _declspec(dllexport)add(int x, int y); #endif /* 文件名:lib.cpp */ #include “lib.h“ int add(int x, int y) return x + y; ,dllCall,#include #include typedef int(*lpAddFun)(int, int); /宏定义函数指针类型 int main(int argc, char *argv) HINSTANCE hDll; /DLL句柄 lpAdd

6、Fun addFun; /函数指针 hDll = LoadLibrary(“DebugdllTest.dll“); if (hDll != NULL) addFun = (lpAddFun)GetProcAddress(hDll, “add“); if (addFun != NULL) int result = addFun(2, 3); printf(“%d“, result); FreeLibrary(hDll); return 0; ,DLL的调用和静态链接库的调用有较大差异,首先,语句typedef int ( * lpAddFun)(int,int)定义了一个与add函数接受参数类型

7、和返回值均相同的函数指针类型。随后,在main函数中定义了lpAddFun的实例addFun; 其次,在函数main中定义了一个DLL HINSTANCE句柄实例hDll,通过Win32 Api函数LoadLibrary动态加载了DLL模块并将DLL模块句柄赋给了hDll; 再次,在函数main中通过Win32 Api函数GetProcAddress得到了所加载DLL模块中函数add的地址并赋给了addFun。经由函数指针addFun进行了对DLL中add函数的调用; 最后,应用工程使用完DLL后,在函数main中通过Win32 Api函数FreeLibrary释放了已经加载的DLL模块。,声

8、明导出函数,DLL中导出函数的声明有两种方式: 一种为给出的在函数声明中加上_declspec(dllexport); 一种方式是采用模块定义(.def) 文件声明;,在DLL中想要export的函数和数据定义前添加_declspec(dllexport)关键字(对于函数和变量定义,加在最前面;对于class定义,加在class关键字后); _declspec(dllexport) void ShowDlg(void) class _declspec(dllexport) class_name /导出类 这样该函数和数据就会被添加到ET中。使用这种方法函数将按名字export。,_declsp

9、ec(dllexport),(.def) 文件声明,为DLL创建一个.DEF文件(模块定义文件),并在build该DLL时使用这个.DEF文件。使用这种方法使你可以将函数按序号export。 在LINK选项卡中假如: /def:“lib.def“ 将lib.def加入到工程中。,lib.def,; lib.def : 导出DLL函数 LIBRARY dllTest EXPORTS add 1 .def文件的规则为: (1)LIBRARY语句说明.def文件相应的DLL; (2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加n,表示要导出函数的序号为n(在进行函数

10、调用时,这个序号将发挥其作用); (3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。,库的调试与查看,动态链接库中的导出接口可以使用Visual C+的Depends工具进行查看,用Depends打开系统目录中的MouseHook.dll .,DLL的调用方式,隐式调用: 将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录,并在*.cpp文件(的顶部添加: #pragma comment(lib,“RegularDll.lib“) OR,动态调用,特点:是完全由编程者用 API 函数加载和卸载 DLL,程序员可以决定 DLL 文件何时

11、加载或不加载,显式链接在运行时决定加载哪个 DLL 文件。,dllTest.dll,在建立的工程中添加lib.h及lib.cpp文件,源代码如下: /* 文件名:lib.h */ #ifndef LIB_H #define LIB_H extern “C“ int _declspec(dllexport)add(int x, int y); #endif /* 文件名:lib.cpp */ #include “lib.h“ int add(int x, int y) return x + y; ,调用 dllTest.dll,#include #include typedef int(*lpA

12、ddFun)(int, int); /宏定义函数指针类型 int main(int argc, char *argv) HINSTANCE hDll; /DLL句柄 lpAddFun addFun; /函数指针 hDll = LoadLibrary(“DebugdllTest.dll“); if (hDll != NULL) addFun = (lpAddFun)GetProcAddress(hDll, “add“); if (addFun != NULL) int result = addFun(2, 3); printf(“%d“, result); FreeLibrary(hDll);

13、,DLL的Export和Import,DLL的export是指将DLL中的函数和数据输出到其它程式中,以供其使用。DLL的import是指使用DLL的程式引入DLL中的函数和数据。 DLL的export DLL中包含有一个表,称为export table(以下简称ET),其中包含了DLL中可以被外部程式使用的所有函数和数据的名字。 只有记录在ET中的函数和数据才可以被外部程式所使用(如果没有.DEF文件的话),其它所有没有记录在ET中的函数和数据都被视为是DLL私有的。,DllMain函数,Windows在加载DLL的时候,需要一个入口函数,就如同控制台或DOS程序需要main函数、WIN32

14、程序需要WinMain函数一样。 在前面的例子中,DLL并没有提供DllMain函数,应用工程也能成功引用DLL,这是因为Windows在找不到DllMain的时候,系统会从其它运行库中引入一个不做任何操作的缺省DllMain函数版本,并不意味着DLL可以放弃DllMain函数。,BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) DllMain函数在DLL被加载和卸载时被调用,在单个线程启动和终止时,DLLMain函数也被调用; ul_reason_for_call指明了被调用

15、的原因。原因共有4种,即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和THREAD_DETACH,以switch语句列出。,DLL导出变量,/* 文件名:lib.h */ #ifndef LIB_H #define LIB_H extern int dllGlobalVar; #endif /* 文件名:lib.cpp */ #include “lib.h“ #include int dllGlobalVar; BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID

16、lpReserved) dllGlobalVar = 100; /在dll被加载时,赋全局变量为100 return TRUE; ,;文件名:lib.def ;在DLL中导出变量 LIBRARY “dllTest“ EXPORTS dllGlobalVar DATA,在主函数中引用DLL中定义的全局变量:,#include #pragma comment(lib,“dllTest.lib“) extern int _declspec(dllimport) dllGlobalVar; /用_declspec(dllimport)导入 int main(int argc, char *argv)

17、printf(“%d “, dllGlobalVar); dllGlobalVar = 1; printf(“%d “, dllGlobalVar); return 0; ,特别要注意,用extern int dllGlobalVar声明所导入的并不是DLL中全局变量本身,而是其地址,应用程序必须通过强制指针转换来使用DLL中的全局变量。这一点,从*(int*)dllGlobalVar可以看出。因此在采用这种方式引用DLL全局变量时,千万不要进行这样的赋值操作: dllGlobalVar = 1;,MFC规则DLL,MFC规则DLL的概念体现在两方面: 它是MFC的 “是MFC的”意味着可以在

18、这种DLL的内部使用MFC; 它是规则的 “是规则的”意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是其与应用程序的接口不能是MFC。而MFC扩展DLL与应用程序的接口可以是MFC,可以从MFC扩展DLL中导出一个MFC类的派生类。 Regular DLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。,Regular DLL分为两类:,(1)静态链接到MFC 的规则DLL 静态链接到MFC的规则DLL与MFC库(包括MFC扩展 DLL)静态链接,将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时,MFC使用D

19、LL的资源。因此,在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。 使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码。 (2)动态链接到MFC 的规则DLL 动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到 MFC DLL 和任何MFC扩展 DLL。在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。因此,对于共享MFC DLL的规则DLL,必须进行模块切换以使得MFC能够找到正确的资源模板。,MFC规则DLL的创建

20、,automation(自动化)技术,是否支持Windows Sockets,在MFC应用程序中CWinApp取代了SDK程序中WinMain的地位,SDK程序WinMain所完成的工作由CWinApp的三个函数完成: virtual BOOL InitApplication( ); virtual BOOL InitInstance( ); virtual BOOL Run( ); /传说中MFC程序的“活水源头”,MFC规则DLL接口函数,#include “StdAfx.h“ #include “DllDialog.h“ _declspec(dllexport) void ShowDlg

21、(void) 或 extern “C“ _declspec(dllexport) void ShowDlg(void) CDllDialog dllDialog; dllDialog.DoModal(); 分析: 这个接口并不使用MFC,但是在其中却可以调用MFC扩展类CdllDialog的函数,这体现了“规则”的概类。 与非MFC DLL完全相同,可以使用_declspec(dllexport)声明或在.def中引出的方式导出MFC规则DLL中的接口。,MFC规则DLL的调用,#pragma comment(lib,“RegularDll.lib“),_declspec(dllexport)

22、 void ShowDlg(void) void ShowDlg(void); 或 extern “C“ _declspec(dllexport) void ShowDlg(void) extern “C“ void ShowDlg(void);,void CRegularDllCallDlg:OnCalldllButton() ShowDlg(); ,MFC扩展 DLL,MFC扩展DLL与MFC规则DLL的相同点在于在两种DLL的内部都可以使用MFC类库,其不同点在于MFC扩展DLL与应用程序的接口可以是MFC的。 MFC扩展DLL的含义在于它是MFC的扩展,其主要功能是实现从现有MFC库类

23、中派生出可重用的类。 MFC扩展DLL使用MFC 动态链接库版本,因此只有用共享MFC 版本生成的MFC 可执行文件(应用程序或规则DLL)才能使用MFC扩展DLL。 一般使用MFC扩展DLL来包含一些MFC的增强功能,譬如扩展MFC的CStatic、CButton等类使之具备更强大的能力。,三种DLL对DllMain入口函数的不同处理方式:,宏,宏为DLL和应用程序的编写提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA 在DLL和应用程序中将具有不同的定义,这取决于_AFXEXT宏是否被定义。这使得在DLL和应用程序中,使用统一的一个宏就可以表示出输

24、出和输入的不同意思。 在DLL中,表示输出(因为_AFXEXT被定义,通常是在编译器的标识参数中指定/D_AFXEXT); 在应用程序中,则表示输入(_AFXEXT没有定义)。,class AFX_EXT_CLASS CExtDialog : public CDialog * #include “ExtDialog.h“ #pragma comment( lib, “ExtDll.lib“ ) 而“调用DLL”按钮的单击事件的消息处理函数为: void CLoadExtDllDlg:OnDllcallButton() CExtDialog extDialog; extDialog.DoModa

25、l(); ,Win32系统钩子技术,APIHOOK技术应用广泛,常用于屏幕取词、网络防火墙、病毒木马、加壳软件、串口红外通信、游戏外挂、Internet通信等领域。 HOOK的中文意思就是钩子,APIHOOK就是钩住API,对API进行预处理,先执行我们的函数。,APIHOOK技术,钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。 钩子的种类很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。此时钩子函数可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。 这有点类似与MFC中的PreTrans

26、lateMessage函数,所不同的是该函数只能用于拦截本进程中的消息,而对系统消息则无能为力。,Win32系统钩子的实现,每种类型的钩子均由系统来维护一个钩子链,最近安装的钩子位于链的开始,拥有最高的优先级,而最先安装的钩子则处在链的末尾。 要实现Win32的系统钩子,首先要调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数,其原型是:,HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId); 其中: 第一个参数是钩子的类型,常用的有WH_MOUSE、WH_

27、KEYBOARD、WH_GETMESSAGE等; 第二个参数是钩子函数的地址,当钩子钩到任何消息后便调用这个函数; 第三个参数是钩子函数所在模块的句柄; 第四个参数是钩子相关函数的ID用以指定想让钩子去钩哪个线程,为0时则拦截整个系统的消息此时为全局钩子。如果指定确定的线程,即为线程专用钩子。,全局钩子函数必须包含在DLL(动态链接库)中,而线程专用钩子则可包含在可执行文件中。 得到控制权的钩子函数在处理完消息后,可以调用另外一个SDK中的API函数CallNextHookEx来继续传递该消息。也可以通过直接返回TRUE来丢弃该消息,阻止该消息的传递。,使用全局钩子函数时需要以DLL为载体,V

28、C6中有三种形式的MFC DLL可供选择,即标准静态链接MFC DLL、标准动态链接MFC DLL以及扩展MFC DLL)。 第一种DLL在编译时把使用的MFC代码链接到DLL中,执行程序时不需要其他MFC动态链接类库的支持,但体积较大; 第二种DLL在运行时动态链接到MFC类库,因而体积较小,但却依赖于MFC动态链接类库的支持;这两种DLL均可被MFC程序和Win32程序使用。 第三种DLL的也是动态连接,但做为MFC类库的扩展,只能被MFC程序使用。,Win32 DLL,BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVO

29、ID lpvReserved);其中: 第一个参数表示DLL的实例句柄; 第三个参数系统保留; 第二个参数指明了当前调用该动态连接库的状态,它有四个可能的值: DLL_PROCESS_ATTACH(进程载入)、 DLL_THREAD_ATTACH(线程载入)、 DLL_THREAD_DETACH(线程卸载)、 DLL_PROCESS_DETACH(进程卸载)。,DLL的共享问题,由于在Win32环境下,所有进程的空间都是相互独立的,这减少了应用程序间的相互影响,但大大增加了编程的难度。 当进程在动态加载DLL时,系统自动把DLL地址映射到该进程的私有空间; 而且也复制该DLL的全局数据的一份拷

30、贝到该进程空间,每个进程所拥有的相同的DLL的全局数据其值却并不一定是相同的。 当DLL内存被映射到进程空间中,每个进程都有自己的全局内存拷贝,加载DLL的每一个新的进程都重新初始化这一内存区域,也就是说进程不能再共享DLL。,全局共享数据的实现,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。 一种方法便是把这些需要共享的数据单独分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享,建立一个内存共享的DLL。,#pragma data_seg,用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为: #pragma data_seg (“s

31、hareddata“) HWND sharedwnd=NULL;/共享数据 #pragma data_seg() 所有在data_seg pragmas语句之间声明的变量都将在shareddata段中。仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的(其效果是相同的),,一种方法是在.DEF文件中加入如下语句: SETCTIONS shareddata READ WRITE SHARED 另一种方法是在项目设置链接选项中加入如下语句: /SECTION:shareddata,rws 加上一条指令 #pragma comment(linker,“/se

32、ction:. shareddata,rws“),程序只能启动一次,#include “windows.h“ #pragma data_seg(“flag_data“) int count=0; #pragma data_seg() #pragma comment(linker,“/SECTION:flag_data,RWS“) int main(int argc, char* argv) if(count0) MessageBox(NULL,“已经启动了一个应用程序“,“Warning“,MB_OK); return 0; count+; system(“pause“); return 0;

33、,程序示例,鼠标钩子 鼠标-键盘-密码,挂接ExitWindowsEx,随着安全意识的不断提高,许多软件都增强的自我保护性,结束其进程时将会调用ExitWindowsEx函数关机或者重启。这种技术在收费管理系统、病毒木马、加壳软件、反破解领域里很常见,因而采用APIHOOK技术挂接ExitWindowsEx函数使其失效,对与我们查杀病毒以及软件破解是很有用的。 当然还能运用它免费上网呢!现在许多收费软件都采取会员制,下机时点结帐下机按钮后,客户端就发送数据报给主机,告知用户已下机从而停止记费,同时重新启动或关闭计算机。挂接ExitWindowsEx后就可以让机子不重启,免费上网?,改写IAT(引入表)法,这种方法的优点是较稳定,不要担心线程同步的问题。 思路如下: 根据PE文件格式穷举模块中的image_impot_desciptor引入函数数组, 检查进程空间里是否有要HOOK的API的所在的DLL,如果有则通过WiteProcessMemory、VirtualProtect等函数改写IAT中的目标API函数地址,将其改为我们自定义函数的地址。 由于地址不能跨进程引用,所以我们可以使用Windows消息钩子将APIHOOK所在的DLL注入到其他进程里, 为了取得较好的效果,推荐使用WH_GETMESSAGE类性的钩子。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1