binary hacks读数笔记(dlopen、dlsym、dlerror、dlclose)

时间:2023-03-09 06:13:35
binary hacks读数笔记(dlopen、dlsym、dlerror、dlclose)

1、dlopen是一个强大的库函数。该函数将打开一个动态库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。比如 Apache Web 服务器利用这个函数在运行过程中加载模块,这为它提供了额外的能力。一个配置文件控制了加载模块的过程。这种机制使得在系统中添加或者删除一个模块时,都 不需要重新编译了。 
可以在自己的程序中使用 dlopen()。dlopen() 在 dlfcn.h 中定义,并在 dl 库中实现。它需要两个参数:一个文件名和一个标志。

功能:打开一个动态链接库
包含头文件: 
#include <dlfcn.h> 
函数定义: 
void * dlopen( const char * pathname, int mode ); 
函数描述: 
在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。 
mode:分为这两种 
RTLD_LAZY 暂缓决定,等有需要时再解出符号 
RTLD_NOW 立即决定,返回前解除所有未决定的符号。 
RTLD_GLOBAL 允许导出符号 

打开错误返回NULL 
成功,返回被加载模块的句柄。
编译时候要加入 -ldl (指定dl库) 
例如 
gcc test.c -o test -ldl

  当库被装入后,可以把 dlopen() 返回的句柄作为给 dlsym() 的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。

2、dlsym
函数原型
void* dlsym(void* handle,const char* symbol) 
该函数在<dlfcn.h>文件中。 
handle是由dlopen打开动态链接库后返回的句柄,symbol就是要求获取的函数的名称,函数返回值是void*,指向函数的地址,供调用使用

取动态对象地址:
#include <dlfcn.h>
void *dlsym(void *pHandle, char *symbol);
dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。
使用这个函数不但可以获取函数地址,也可以获取变量地址。比如,假设在so中
定义了一个void mytest()函数,那在使用so时先声明一个函数指针:
void (*pMytest)(),然后使用dlsym函数将函数指针pMytest指向mytest函数,
pMytest = (void (*)())dlsym(pHandle, "mytest");

3、dlclose
函数原型:
int dlclose (void *handle); 
函数描述: 
dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

4、dlerror
函数原型: 
const char *dlerror(void); 
函数描述: 
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

接下来介绍一个实例来看看这几个函数的具体使用:

首先:将如下程序编译为动态链接库libcaculate.so,编译参数 gcc -fPIC -shared libcaculate.c  -o libcaculate.so。程序如下:

 int add(int a,int b)
{
return (a+b);
} int sub(int a,int b)
{
return (a-b);
} int mul(int a,int b)
{
return (a*b);
} int div(int a,int b)
{
return (a/b);
}

采用上面生成的libcaculate.so,写个测试程序如下,编译选型:gcc -rdynamic -o dl dl.c -ldl

#include<stdio.h>
#include<stdlib.h>
#include<dlfcn.h>
//动态库路径
#define LIB_CACULATE_PATH "./libcaculate.so" typedef int (*Func)(int,int); int main()
{
void * handle;
char * error;
     //定义函数指针
Func func;
    //打开动态链接库
handle=dlopen(LIB_CACULATE_PATH,RTLD_LAZY);
if(!handle){
fprintf(stderr,"%s\n",dlerror());
exit(EXIT_FAILURE);
}
    //清楚之前错误
dlerror();
    //获取add函数
func=dlsym(handle,"add");
if((error = dlerror())!=NULL){
fprintf(stderr,"%s\n",error);
exit(EXIT_FAILURE);
}
printf("add: %d\n",func(2,7)); func=dlsym(handle,"sub");
printf("sub: %d\n",func(9,2)); func=dlsym(handle,"mul");
printf("mul: %d\n",func(2,7)); func=dlsym(handle,"div");
printf("div: %d\n",func(8,2)); dlclose(handle);
return 0;
}