一文搞懂linux的库打桩

Linux下的链接器支持一个强大的库打桩(library interpositioning),允许你拦截对系统标准库中某个目标函数的调用,取而代之执行自己的包装函数。它可以给我们带来两个好处,一是通过添加某些语句,可以追踪自己的程序对某些库函数的调用情况;二是可以在你自己的程序中,对某些库函数偷天换日,替换成一个完全不同的实现。

打桩可以发生在编译,链接和运行的任意一个阶段,相应的代码编写和编译也有一些区别,下文将分别做一阐述:

需求:假设需要在主程序myprog.c中跟踪对库函数malloc和free的使用情况。

1.编译时打桩

1.1 建立包装函数

建立mymalloc.c文件,定义需要的包装函数mymalloc和myfree.

#ifdef COMPILETIME
#include <stdio.h>
#include <malloc.h>

//定义malloc 包装函数
void *mymalloc(size_t size)
{
  void *ptr = malloc(size);
  printf("malloc(%d) = %p\n", (int)size, ptr);
  return ptr;
}

//定义free 包装函数
void *myfree(void *ptr)
{
  free(ptr);
  printf("free(%p) = %p\n",  ptr);
}

#endif

1.2 建立头文件malloc.h

该文件向预处理器指明用mymalloc.c中的包装函数替换库里的目标函数

#define malloc(size)  mymalloc(size)
#define free(ptr)        myfree(ptr)

void *mymalloc(size_t size);
void *myfree(void *ptr);

1.3 建立自己的程序文件

建立文件myprog.c,并在其中正常调用malloc函数.

#include <stdio.h>
#include <malloc.h>

int main(void)
{
 int *p = malloc(32);
 free(p);
 return 0;
}

1.4 编译链接

gcc -DCOMPILETIME -c mymalloc.c
gcc -I. -o myprog myprog.c mymalloc.c

-I.:指示C预处理器在搜索通常的系统目录前,先在当前目录中查找malloc.h

1.5 运行结果

./myprog
malloc(32) = 0x9ee010
free(0x9ee010)

2.链接时打桩

linux利用静态链接器完成库打桩。先看它的一个命令行参数:

  • --wrap f:指示链接器把对符号f的引用解析成__wrap_f,把对__real_f的引用解析成符号f
    此处f代表任意的库函数名或变量名

  • -Wl,option:将option传递给链接器, option中的每个逗号都要用空格来替换。

2.1 建立包装函数

创建mymalloc.c文件,定义需要的包装函数.

#ifdef LIKETIME
#include <stdio.h>

void *__real_malloc(size_t size);
void __real_free(void *ptr);

//定义malloc 包装函数
void *__wrap_malloc(size_t size)
{
  void *ptr = *__real_malloc(size);    //调用标准库里的malloc
  printf("malloc(%d) = %p\n", (int)size, ptr);
  return ptr;
}

//定义free 包装函数
void *__wrap_free(void *ptr)
{
  __real_free(ptr);     //调用标准库里的free
  printf("free(%p) = %p\n",  ptr);
}

#endif

2.2 建立自己的程序文件

建立文件myprog.c,并在其中正常调用malloc函数.

#include <stdio.h>

int main(void)
{
 int *p = malloc(32);
 free(p);
 return 0;
}

2.3 编译链接

gcc -DLINKTIME -c mymalloc.c
gcc  -c myprog.c
gcc -Wl,--wrap,malloc  -Wl,--wrap,free -o myprog myprog.o mymalloc.o
  • -Wl,option:将option传递给链接器。 option中的每个逗号都要用空格来替换, 所以-Wl,--wrap,malloc意味着把--wrap malloc传递给链接器。

2.4 运行结果

./myprog
malloc(32) = 0x18cf010
free(0x18cf010)

3 运行时打桩

编译时打桩需要访问程序的源代码,而链接时需要访问可重定位目标文件。那有没有一种办法让仅仅访问可执行目标就能达到同样的目的呢?我们可以利用基于动态链接器的LD_PRELOAD环境变量来实现。

当你将LD_PRELOAD环境变量设置为一个共享路径名的列表(以空格或分号分开),那么在运行一个程序时,动态链接器(LD-LINUX.SO)会先搜索列表里的库,然后才搜素系统其它库。

利用这个原理,你可以对任何共享库中的任何函数打桩,包括libc.so。

3.1 建立包装函数文件

下面建立mymalloc.c文件,其中定义了malloc和free的包装函数。每个包装函数中,利用dlsym调用libc中的标准函数。

#ifdef RUNTIME
#define  _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

//定义malloc 包装函数
void *malloc(size_t size)
{
  void *(*mallocp)(size_t size);

  //获得libc中malloc函数的地址
  if( !(mallocp = dlsym(RTLD_NEXT, "malloc")) ){  
    fputs(dlerror());
    exit(1);
  }

  char *ptr = *mallocp(size);  //利用函数指针间接调用libc中的malloc函数
  printf("malloc(%d) = %p\n", (int)size, ptr);
  return ptr;
}


//定义free 包装函数
void *free(void *ptr)
{
  void (*free)(void *) = NULL;
  if(!ptr)
    return;

  //获得libc中free函数的地址
  if( !(freep = dlsym(RTLD_NEXT, "free")) ){  
    fputs(dlerror());
    exit(1);
  }

  *freep(ptr);  //利用函数指针间接调用libc中的free函数
  printf("free(%p)\n",  ptr);
 }

#endif

3.2 建立自己的程序文件

建立文件myprog.c,并在其中正常调用malloc函数.

#include <stdio.h>

int main(void)
{
 int *p = malloc(32);
 free(p);
 return 0;
}

3.3 编译包含包装函数的共享库

  gcc -DRUNTIME -shared -fpic -o mymalloc.so mymalloc.c -ldl
  • -fpic:(position independent code)指示生成位置无关的目标文件;编译共享库时该参数为必选!
  • -DRUNTIME:在命令行中定义宏定义RUNTIME,为了与文件头部ifdef RUNTIME呼应。
  • -shared:指示编译器生成一个共享目标文件。
  • -ldl:指示链接器链接到libdl.so 共享库。

3.4 编译与运行主程序

  gcc -o myprog myprog.c    //编译

在bash中运行,及其结果:

  LD_PRELOAD="./mymalloc.so" ./myprog   

结果如下

  malloc(32) = 0x1bf7010
  free(0x1bf7010)

在csh或tcsh中运行方法:

(setenv LD_PRELOAD "./mymalloc.so";  ./myprog;  unsetenv LD_PRELOAD)

结果如下

  malloc(32) = 0x2157010
  free(0x2157010)

4. 拓展

GNU binutils包有许多实用的工具特别有帮助,而且可以运行在每一个Linux平台上。

  • AR: 创建静态库,插入/删除/列出和提取成员函数。
  • STRINGS:列出目标文件中所有可打印字符串;
  • STRIP:从目标文件中删除符号表信息;
  • NM: 列出目标文件中符号表中定义的符号;
  • SIZE:列出目标文件中各段的大小;
  • READELF:显示目标文件的完整结构,包括ELF头中编码的所有信息。包含了NM和SIZE的作用;
  • OBJDUMP:显示目标文件中所有的信息,最大的左右是反汇编.text段中的二进制指令成汇编指令。
  • LDD:列出可执行文件运行时需要的所有共享库。

获取更多知识,请点击关注:
嵌入式Linux&ARM
CSDN博客
简书博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容

  • 动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如库)作为加载过...
    小5筒阅读 5,511评论 0 3
  • 最全的iOS面试题及答案 iOS面试小贴士 ———————————————回答好下面的足够了-----------...
    zweic阅读 2,703评论 0 73
  • 近一年,周围的朋友觉得我变得矫情起来,因为我戒糖啦~不吃水果、不吃甜点、不吃奶制品,又加上择食规则,我基本成了美食...
    思如思如阅读 1,807评论 0 4
  • 沟通的基础一定是信任。如果两个人之间没有什么信任的话。好话也会因为猜忌而变味,坏话也会加重,啥都变味了。是的,我和...
    野比小夫阅读 257评论 0 0