OS X系统中,仅有很少的进程只需要内核加载器就可以完成,几乎所有的程序都是动态连接的,通常采用/usr/lib/dyld作为动态链接器。
作为一个私有的加载器,dyld提供了一些独有的特性,如函数拦截等。DYLD_INTERPOSE宏定义允许一个库将其函数实现替换为另一个函数实现。以下代码取自dyld的源代码,演示了这个功能。
#if !defined(_DYLD_INTERPOSING_H_)
#define _DYLD_INTERPOSING_H_
#define DYLD_INTERPOSE(_replacment,_replacee) \ __attribute__((used)) static strut{const void* replacment;const void* replacee;}
_interpose_##_replace \ __attribute__((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee};
#endif
dyld的函数拦截功能提供了一个新的__DATA区,名为__interpose,在这个区中依次列出了替换函数和被替换的函数,其他事情就交由dyld处理了。
下面通过一个实验展示如何通过函数拦截机制跟踪malloc()函数
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <malloc/malloc.h>
//标准的interpose数据结构
typedef struct interpose_s{
void *new_func;
void *orig_fnc;
}interpose_t;
//我们的原型
void *my_malloc(int size);//对应真实的malloc函数
void my_free(void *);//对应真实的free函数
static const interpose_t interposing_functions[] __attribute__ ((section ("__DATA,__interpose"))) = {{(void *)my_free,(void *)free},{(void *)my_malloc,(void *)malloc}};
void *my_malloc (int size){
//在我们的函数中,要访问真正的malloc()函数,因为不想自己管理整个堆,所以就调用了原来的malloc()
void *returned = malloc(size);
//调用malloc_printf是因为printf中会调用malloc(),产生无限递归调用。
malloc_printf("+ %p %d\n",returned,size);
return (returned);
}
void my_free(void *freed){
malloc_printf("- %p\n",freed);
free(freed);
}
int main(int argc, const char * argv[]) {
// 释放内存——打印出地址,然后调用真正的free()
printf("Hello, World!\n");
return 0;
}
在终端中执行以下代码编译为dylib并强制插入ls中
cc -dynamiclib 1.c -o libMTrace.dylib -Wall
DYLD_INSERT_LIBRARIES=libMTrace.dylib ls
最终会发现调用malloc的地方会打印这样的信息
ls(24346) malloc: + 0x100100020 88
ls(24346) malloc: + 0x100800000 4096
ls(24346) malloc: + 0x100801000 2160
ls(24346) malloc: - 0x100800000
ls(24346) malloc: + 0x100801a00 3312
原文地址:http://blog.csdn.net/abc649395594/article/details/45287439