静态链接库,动态链接库【滴水逆向三期48笔记】

在开发过程中,我们通常会有很多函数,需要多次使用或在不同的程序中使用该函数,也有可能我们会将我们写好的函数给别人使用,但是我们又不想给他源代码,毕竟代码是我们花了很多功夫写出来的,那么我们如何不发给其他人源代码而让别人使用咱们写好的函数呢?在这里我们就要用到静态链接库和动态链接库的知识了。

一.什么是库

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能在开发时每个源代码都从零开始,那样太花费时间了,因此库的存在很大程度上提高了我们的开发效率。

二.静态链接库的使用方法

1.创建***.lib文件

我们可以在visual studio中创建静态库,如图所示:
静态库
在创建了静态库之后可以将原有的***.cpp和***.h全部删除,使用我们新建的.h文件和.cpp文件:
完成之后可以添加代码,这里使用的所有代码都是滴水逆向三期视频里海东老师的代码:
.h(头文件)中添加代码,先进行函数声明:

#pragma once
 
int Plus(int x, int y);
int Sub(int x, int y);
int Mul(int x, int y);
int Div(int x, int y);

.cpp文件中添加代码:

#include "MyLib.h"
 
int Plus(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}

在.cpp文件中incldue的是前面头文件的文件名。
点击平时的编译运行按钮,虽然提示无法运行(lib本来就无法单独运行),但已经成功生成.lib 文件了,去到 Debug 或 Release 目录下即可看到,lib 文件名和项目名一致,这里项目叫StaticLib1,生成的文件名则为StaticLib1.lib,和函数名 cpp名都无关。

2.静态链接库的实现

在完成了lib文件的创建后,我们可以将上面创建好的***.lib文件和***.h文件拷贝到需要使用的项目目录下,然后在源文件中添加代码:

#pragma comment(lib, "StaticLib1.lib")//这里需要改为自己创建的lib文件名
#include<stdio.h>
#include"MyLib.h"        //需将.h文件放入目录下才可include,
//int Plus(int x, int y);  //若没有上行的include,可自行声明.h中的函数,声明与.h中的一致即可,则可不将.h拷贝进目录下
#pragma comment(lib, "StaticLib1.lib") //在项目的"资源文件"中添加相应lib文件则不用这一条
 
int main()
{
	printf("%d\n", Plus(2, 1));
	return 0;
}

接下来我们来讨论静态链接库的优缺点:

优点:静态链接库可以实现代码的共享,让别人可以使用或自己可以在不同程序中多次使用。

缺点:
1.我们可以通过visual C++6.0的反汇编窗口观察到:我们在调用函数时,函数的地址在.exe文件中,也就是说,我们之前写好的函数的二进制直接被编译进了程序中,可能我们编译好的函数中有很多函数在这个程序中用不上,但是编译器把它编译进了程序中,造成磁盘空间浪费。使用静态链接生成的可执行文件体积较大,造成浪费我们常用的printf、memcpy、strcpy等就来自这种静态库。
2.既然函数直接被编译进了程序中,那么当我们发现了函数的不足之处时,如果我们需要更新源代码,那么程序就需要重新编译,会给我们带来很多麻烦。

三.动态链接库的使用方法

静态链接库存在很多问题,那么动态链接库就能很好地解决静态链接库的问题。
. exe在可执行程序中没有相应库的代码,当软件运行起来再把库代码拷到内存。

1.dll文件创建

我们在visual studio中创建动态链接库:
动态链接库
在创建完成后我习惯将多余的文件全部删除,新增自己需要的文件:
MyDll.h文件:

#pragma once
_declspec(dllexport) int Plus(int x, int y);
_declspec(dllexport) int Sub(int x, int y);
_declspec(dllexport) int Mul(int x, int y);
_declspec(dllexport) int Div(int x, int y);

MyDll.cpp文件:

#include "MyDll.h"
int Plus(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}

跟创建.lib文件后一样点击平时的编译运行按钮,提示无法运行(本来就无法单独运行),但已成功生成.dll 文件,去到 Debug 或 Release 目录下即可看到,注意同样还有个.lib文件,我们后面会用到。

.dll文件调用

1.隐式调用:

首先,我们将前面创建好的.lib文件和.dll文件放入项目目录下面(静态链接库函数是放在.lib文件中的,但是动态链接库的.lib文件中,可以理解为只放了函数在哪里,而真正的函数是放在.dll文件中的。
完成之后,添加代码:

#pragma comment(lib,"dll名.lib");

然后加入函数声明:

extern "C" _declspec(dllexport) int Plus(int x, int y);

这里解释一下该代码:
extren “C”表示这是个全局函数,可以供各个其他函数调用。
“C”表示按照C语言的方式进行编译和链接,那么我们为什么要用C语言的方式进行编译呢?原因是C++函数重载,编译器为了避免出现函数名一样的函数,会将我们写好的函数名进行更改,而使用C语言方式进行编译后就不会更改我们的函数名了。
_declspec(dllexport)是告诉编译器,此函数为导出函数。

2.显式调用:

1.定义函数指针:

typedef int (_stdcall *Plus)(int,int);

2.声明函数指针变量:

lpPlus myPlus;

3.动态加载dll到内存中

HINSTANCE HModule=LoadLibrary("DllName.dll");

4.获取函数地址:

myPlus=(lpPlus)GetProAddress(hModule,"_Plus@8");

5.调用函数:

int a=myPlus(1,2);

特别说明:
1.Handle代表系统的内核对象,如文件句柄,线程句柄,进程句柄
2.HMODULE是代表程序载入的模块
3.HINSTANCE在Win32下与HMODULE是相同的东西,Win16一六
4.HWND是窗口句柄
实际上,这些都是无符号的整形,Windows之所以这样设计,主要有两个目的:
1.方便区分
2.避免使用者误进行运算
动态调用主要通过 LoadLibrary 获取 加载dll 并获取其地址,后通过 GetProcAddress 通过 dll 句柄和函数名或者函数序号(后面会说)获取真正的函数地址,得到地址,套上和该函数格式一模一样的函数指针。即可成功调用。

三.导出函数名问题

我们可以通过visual C++提供的工具DEPENDS.EXE来观看.dll文件,可以编译器为我们导出的函数名,在我们进行开发过程中,通常函数名都是见名知其意,那么别人就能够通过函数名来猜测我们函数的功能,那么我们如何隐藏函数名呢?
可以通过添加 def 文件,在源文件->添加->新建项->搜索def,即可添加def文件。
或者在文件中直接弄个空文件改成.def,然后在添加到项目的源文件中 也可以。
添加到项目的源文件后,需要在如下项目属性的这里,填入添加的def的文件名才能正常使用。
.def文件中写入一下文本:

EXPORTS	
	
Plus   	@12
Sub	    @15 NONAME
Mul    	@13
Div    	@16

这里的Plus,Sub,Mul,DIV都是我写好的函数,如果要隐藏哪个函数名,可以根据这个来隐藏,其中@后的就是导出序号,其中NONAME表示只有序号,没有函数名,在观看.dll文件时,只能看到导出序号,看不到函数名。
由于之前我们有学习过C++,更没有学习过关于库的知识,所以在课程中可能有很多理解不到位的地方,还希望大家指出,我会非常虚心地学习,希望我们大家共同进步!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Shad0w-2023

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

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

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

打赏作者

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

抵扣说明:

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

余额充值