动态链接库(dynamic link library)介绍
代码放到exe中,肯定会造成磁盘冗余; 电脑ABCD四个软件,lib加入到代码中不是在编译期进入的,而是在运行期 (A进程启动,把dll加入到A进程中……),编译的时候不需要这份代码, 后缀是.dll
如果要更新软件,把dll换掉就可以了,所有软件都会跟着更新
分析DLL的工具
.dll中凡是能给外面用的函数叫 导出函数;
这个工具能看导出函数;
调win api的时候跟不到源码中,因为放到了dll中了
动态库的创建
文件导入并去掉宏,宏在静态库和动态库表现不一致
直接编译,生成dll文件,dll文件用工具打开, 然而并没有导出函数显示
导出函数
编译之后,用工具打开发现 默认的没有导出函数, 需要手动指定后,才导出;
就像类一样,默认时私有的;
用编译器命令导出
注意细节1:
两个cpp文件中把头文件注释掉了,编译之后,在工具中发现没有导出函数,为什么?
.h在预处理时期,预编译时把头文件中东西拷贝到.cpp文件中,没有包含头文件就没有导出函数了
注意细节2:
再把头文件加上,有了导出函数之后,编译之后生成了lib; 这里和静态的lib有区别,这里文件大小2kb;
这里只是一个描述性的lib,里面没有代码,这里描述dll中有哪些导出函数,是给开发者使用的
使用dll
使用dll, 头文件的这里改成dllimport, 告诉编译器这里用的是dll中的函数;
编译有误,找不到函数是在哪个dll文件中;
问题: 一个.cpp 两个.h声明,通过这些能判断这两个函数要加载哪个dll吗?
此时就用到了描述性的lib文件,拷到目录下(类似Makefile)
和静态的lib用法相同
编译的时候不需要dll,运行的时候需要;这里是运行状态; dll拿出来放到Debug文件里
1-导出全局变量
全局变量可以导出
VS的bug: dll中的全局变量,在VS的监视窗口中看不到值
2-导出类
类可以导出
但这样写不能导出,报错内容如下:
这样写就可以了
工具输出的内容,上面两个是构造还是有重载,下面那个是自己写的类
这个时候断点跟源码,能跟到自己写的库里,因为调试信息都放到.pdb文件里了;把这个删了就跟不进去了;
导出和导出函数的宏处理
这个东西,每次要用都要改,文件多了就很麻烦,用宏给它安排下
源码中 : 把宏的开关放到这里,全局的宏放置的位置
工具里导出的都是C++的符号,如果C的呢?
隐式/显示加载方式
隐式加载方式:
lib + .h (函数 全局变量 类 都可以用)
显示加载方式:
Ollydebug中强大的是插件,很多的dll,使用某个功能的时候,就会去加载dll
Ollydebug发布的时候,有没有用人家写的插件dll的lib和.h?没有啊, 所以它的加载方式和这里隐式加载方式不同,Ollydebug是显示的加载方式;
并不知道别人写的插件叫啥名字,是怎么加载别人写的dll呢?
做法: 当前路径下的某个文件夹,遍历文件夹下后缀为.dll的文件,加载到进程; 这时候的加载,只要有个文件名和文件路径就可以加载,显示加载 (函数 全局变量 类(很麻烦))
使用dll,调用导出函数的方法(Ollydebug加载dll的做法)
加载dll(加载到进程内存中) -> 获取导出函数的地址 -> 然后调用(通过函数地址的方式调用)-> 从进程中卸掉dll
01加载dll的api
参数: 的module指的是 dll / exe(主模块) 的地址 ;
返回值: 模块句柄和HINSTANCE两个是等价的;
HINSTANCE是可执行文件exe在内存中的首地址
HMODULE是dll在内存中的首地址
作用: 把dll加载到进程内存中
code:
注意细节:
调用多个 loadLibrary, 不会调用多个dll,而是句柄引用计数的值会增加;
调用两个loadLibrary,也要有两个FreeLibrary才能卸载掉;
02获取函数地址
模块句柄还有函数名填进去,返回的就是函数地址;
code: 用的函数指针接收
注意全局变量:
如果要拿全局变量怎么访问? 这里拿到的是地址
全局变量这样访问,指针p保存的是地址 *p访问值
调用: 普通调用就行
一步一步调试看现象
03从进程中卸掉dll
code:
code
#include <iostream> #include <windows.h> using PFN_ADD = int(*)(int, int); int main() { HMODULE hDll = LoadLibrary(R"(C:UsersYunaDesktopCR2windowswin01UseDllDebugdll.dll)"); if (NULL == hDll) { std::cout << "加载失败" << std::endl; return 0; } PFN_ADD pfnAdd = (PFN_ADD)GetProcAddress(hDll,"Add"); if (NULL == pfnAdd) { std::cout << "获取函数地址失败" << std::endl; return 0; } int nRet = pfnAdd(1,4); int i = 0; //为了调试上一句 FreeLibrary(hDll); }
文章来源: 博客园
- 还没有人评论,欢迎说说您的想法!