【逆向基础】七、链接库dll,lib的创建及使用(超级详解)

本文详细介绍了链接库的概念,包括静态链接库和动态链接库的格式、内容、优缺点。并提供了在Windows环境下使用MicrosoftVisualStudio创建和使用链接库的步骤,包括库的创建、功能编写、生成以及静态和动态链接库的使用方法。同时,文章强调了静态库和动态库的差异,如静态库包含所有代码,而动态库仅含地址信息,并讨论了显式加载动态库的方法。
摘要由CSDN通过智能技术生成

一,链接库概念详解

前言

首先,编程时,我们将存储可以重复使用的代码块文件称为库文件。比如c++常常导入的<stdio.h>,<match.h>等,这些都简称为。根据应用程序使用库时的链接方式被划分为静态链接库动态链接库两种。都符合PE文件格式下面为大家详细介绍。

1,静态链接库

(一)库格式

静态链接库(Static-Link Library)通常是以".lib"作为文件拓展名的二进制文件, 也可以是以".a"等;

(二)库内容

静态链接库在生成可执行文件前,将目标文件(.obj),运行时的函数库(.lib),已编译的资源文件(.res)等全部链接到了一起,打包成二进制文件。该文件包含运行时所需的所有代码。因此静态链接库是可以独立运行的(编译时加载);
包含文件:
xxx.h:生成静态链接库时的头文件,包含方法的声明;
xxx.lib :静态链接库,包含了一个或多个方法的具体实现代码的二进制文件;

(三)优,缺点

优点: 包含了全部运行时所需代码,可以独立运行移植性性强;
缺点: 若程序多次调用静态库中的同一代码块,则生成的可执行文件会重复加载此代码段,造成代码冗余,程序占用内存增大;

2,动态链接库

(一)库格式

动态链接库(Dynamic-Link Library)通常是以".dll"作为文件拓展名的二进文件,也可以是以".so",“.sys”,".drv"等;

(二)库内容

动态链接库在生成可执行文件前,将目标文件(.obj),运行时的函数库(.lib),已编译的资源文件(.res)等地址信息全部记录到文件中,打包成二进制文件。该文件包含运行时所需的代码块位置信息。因此动态链接库是不可以独立运行的(运行时加载);
包含
xxx.h:生成动态链接库时的头文件,包含方法的声明;
xxx.lib:动态链接库的导入库;包含了各个函数的地址信息;没有实现代码;
xxx.dll:动态链接库,包含了一个或多个方法的具体实现代码的二进制文件;

(三)优,缺点

优点:
1,若程序多次调用动态库中的同一代码块地址,则生成的可执行文件会加载相同地址的代码块,即使用的是同一块代码(共享代码);真正实现了运行时加载;同时避免了空间上的浪费
缺点:
1,仅包含了全部运行时所需代码块地址,需要搭配相应的库文件。不可以独立运行,即移植性性强;
2,运行时加载代码块,需要通过动态库记录的地址去寻找相应地代码块,会使得程序性能下降(约%5);

二,链接库的创建

1,链接库创建环境

系统 : windows 10专业版
编译器: Microsoft Visual Studio 2015
语言:C++

2,链接库项目创建

步骤1:创建一个空项目。操作路径为:文件-》新建-》项目;
在这里插入图片描述

然后选择模板中选择Visual c++ -》空项目 -》输入名称 - 》点击【确定】按钮
在这里插入图片描述

步骤2:点击视图-》解决方案管理器-》右键项目名称:MyLib->点击属性-》进行项目设置
在这里插入图片描述
步骤3:到此,任意选择上述配置,编译器编译出来的项目结果就是链接库;下面以静态库创建操作为例,如下图所示:

静态库创建:在项目MyLib属性页中,点击常规-》配置类型-》静态库(.lib)
动态库创建:在项目MyLib属性页中,点击常规-》配置类型-》动态库(.dll)

在这里插入图片描述

3,链接库功能编写

首先,在项目目录下,右键源文件-》添加》新建项-》
在这里插入图片描述

下面以添加.h为例,操作如下图所示,(“.h”,".cpp"文件都需要添加)

添加.h文件:选择Visual C++ --》头文件(.h) -》 输入文件名–》点击【添加】即可
添加.cpp文件:选择Visual C++ --》c++文件 (.cpp)-》 输入文件名–》点击【添加】即可;
在这里插入图片描述

静态链接库文件编写:静态链接库没有main()函数,其余与正常程序编写一致在这里插入图片描述

动态链接库文件编写:动态链接库没有main()函数,区分导入导出函数;其余与正常程序编写一致;
导入函数:指的是链接库自身使用的函数,不能直接被外部程序直接调用;
导出函数:指的是链接库提供给外部程序使用的函数,也可以调用自身的函数
(备注:
1,若没有在函数声明前添加关键字__declspec(dllexport),则默认为导入函数,不生成lib库;
2,建议使用extern "C" __declspec(dllexport)来定义声明的函数,避免显示调用时,函数名因编译器处理c++重载导致乱码照成调用不到的情况;)
在这里插入图片描述

4,链接库生成

静态链接库生成
右键项目-》生成-》即可在输出窗口找到生成静态链接库保存路径;则生成如下".lib"文件;
".lib"文件: 存放链接库中函数的声明与具体代码实现等全部信息;(注意区分动态链接库的".lib"文件)
在这里插入图片描述在这里插入图片描述

动态链接库生成:
若在链接库项目创建时,选择动态链接库创建,则生成如下".dll"和“.lib”两个文件;
".lib"文件: 存放添加关键字__declspec(dllexport)的函数地址信息,成为动态链接库的导入库;若没有编写导出函数,则不生成".lib"文件(此时只能通过用WIN32 API函数LoadLibrary、GetProcAddress装载调用函数);
".dll"文件: 存放添加关键字__declspec(dllexport)的函数具体实现代码信息
在这里插入图片描述
在这里插入图片描述

三,链接库的使用

在执行程序调用链接库时,需要提供链接库的相关文件如下:

静态链接库文件如下(注意:debug模式下生成的lib库,只能在debug模式下的程序调用,只能隐式加载):
MyFunction.h
MyLib.lib

动态链接库文件如下(注意:debug模式下生成的lib库,只能在debug模式下的程序调用,可以隐式加载,也可以显式加载):
MyFunction.h
MyLib.lib (若动态库无此文件,则只能使用显式加载)
MyLib.dll

1,使用方式一:代码配置后使用(隐式加载

步骤1:创建一个可执行程序项目,用于调用链接库;
(具体流程按照链接库项目创建的步骤一执行即可(编译器默认生成exe文件),此处省略;)

步骤2:将链接库的相关文件放到刚创建的可执行程序项目文件夹中;
在这里插入图片描述
步骤3:创建一个.cpp文件,然后代码导入链接库的MyFunction.hMyLib.lib后即可直接使用链接库中的功能函数;
在这里插入图片描述
步骤4:直接点击键盘快捷键【F5】或者单击运行,调用链接库成功,结果如下:
在这里插入图片描述

2,使用方式二:编译器配置后使用(隐式加载

步骤1:创建一个可执行程序项目,用于调用链接库;
(具体流程按照链接库项目创建的步骤一执行即可(编译器默认生成exe文件),此处省略;)

将MyLib.dll放在可执行程序.exe的同级目录,加载时可以直接连接到;交付用户时,只需要提供可执行程序和Mylib.dll文件即可;
在这里插入图片描述

步骤2:右键项目TEST–>属性–》VC++目录–>包含目录-》编辑-》新行–》选择头文件目录(要让可执行程序可以找到链接库的头文件,所以添加的包含目录是头文件MyFunction.h 所在目录;可以放在自己创建的文件夹里;)
在这里插入图片描述
在这里插入图片描述

步骤3:右键项目TEST–>属性–》VC++目录–>库目录-》编辑-》新行–》选择库文件目录–》点击【确认】即可;(要让可执行程序可以找到链接库的库文件,所以添加的库目录是库文件MMyLib.lib 所在目录)
在这里插入图片描述
步骤4:右键项目TEST–>属性–》链接器-》输入-》附加依赖项-》编辑–》输入库名称MyLib.lib–》点击【确认】即可;(要让可执行程序可以找到链接库的库文件,所以添加的库目录是库文件MMyLib.lib 所在目录)
在这里插入图片描述
步骤5:创建一个.cpp文件,然后代码导入链接库的MyFunction.h 后,可直接使用链接库中的功能函数;
在这里插入图片描述
步骤6:直接点击键盘快捷键【F5】或者单击运行,调用链接库成功,结果如下:
在这里插入图片描述

3,使用方式三:函数指针直接使用(显式加载

显式加载指的是程序运行,使用到动态库时,在通过LoadLibrary方法调用dll文件;
然后通过GetProcAddress方法获取dll文件中的函数地址;最后通过函数指针实现库方法的调用;(无需动态库的导入库lib文件);

步骤1:创建一个可执行程序项目,用于调用链接库;
(具体流程按照链接库项目创建的步骤一执行即可(编译器默认生成exe文件),此处省略;)

步骤2:将对应的库文件放到调用库的项目中去;

将动态库的头文件直接放在test.cpp的同级文件夹目录下,直接用#include通过相对路径导入即可。省去配置头文件的环境;
在这里插入图片描述
将动态库的dll文件直接放在可执行程序exe的同级文件夹目录下,运行时,程序会自行链接,省去配置动态库的环境了;
在这里插入图片描述

步骤3:通过API实现dll的加载即函数调用,代码如下

#include <stdio.h>
#include <stdlib.h>
#include <wtypes.h>
#include <WinBase.h>

#include "MyFunction.h"				//步骤一:导入静态库对应的.h文件(相对于test.cpp路径)
//#pragma comment(lib,"MyLib.lib")	//步骤二:导入静态库(相对于test.cpp路径)

int main()
{
	//指定的可执行模块映射到调用进程的地址空间
	HINSTANCE hDLLDrv = LoadLibrary("MyLib.dll");
	if (hDLLDrv == NULL){
		printf("动态链接库 MyLib.dll 加载失败\n");
		system("pause");
		return 0;
	}

	//定义一个FunAdd函数的指针类型pFunAddr
	typedef int(*pFunAddress)(int x, int y);	

	//根据函数名称获取函数地址
	pFunAddress pFunAdd = (pFunAddress)GetProcAddress(hDLLDrv, "FunAdd");
	if (pFunAdd == NULL){
		printf("动态链接库没有找到函数FunAdd的地址\n");
		system("pause");
		return 0;
	}

	//直接使用dll库中的函数,等价于int iValue =  FunAdd(1, 3);	
	int iValue = pFunAdd(1, 3);
	printf("FunAdd return: %d\n", iValue);

	//释放函数对dll文件的引用
	FreeLibrary(hDLLDrv);

	system("pause");
	return 0;
}

运行结果如下:
在这里插入图片描述

一,链接库总结

写着写着,发现链接库的内容也不少啊。作为学习关键的一部,总结时不能少的啦,所以下面我来说说链接库的一些容易弄错的点吧;
首先,.lib文件在静态链库中是一个有完整代码实现的二进制文件;而在动态链接库中是只包含了函数地址信息的导入库,就是一个壳,实际代码实现在.dll文件中;
然后,显式加载相当于做了lib导入库的工作,使用显式加载时,lib文件便可有可无了;
还有延迟加载等,这些实现原理与显示加载大致一样;其余没讲到的地方还请大家见谅,学海无涯嘛,不过我会继续向前,修习自己的道,请大家一起见证哈。

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修道-0323

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值