Mac hook——DYLD_INSERT_LIBRARIES
(2013-06-27 10:32:20) 标签: dyld_insert_librarieit | 分类: IOS学习 |
转自: http://danqingdani.blog.163.com/blog/static/186094195201311105254605
网易微博:碳基体。
Mac可以通过设置DYLD_INSERT_LIBRARIES环境变量(linux上对应的环境变量是LD_PRELOAD ,效果实例可见 Android hook——LD_PRELOAD),重写动态链接库中的函数,实现hook功能。
以下是演示实例
一、替换动态链接库中的c函数
实例一:使用openhook.dylib中的f()
(一)、源文件
1. mysharedlib.h
void f();
2. mysharedlib.c
#include #include "mysharedlib.h" void f(){ printf("hello,dani \n"); }
3. main.c
#include #include "mysharedlib.h" int main(){ f(); return 0; }
#include #include #include #include "mysharedlib.h" typedef void (*fType) (); static void (*real_f)()=NULL; void f(){ if (! real_f){ void * handle = dlopen("mysharedlib.dylib", RTLD_NOW); real_f = (fType) dlsym(handle,"f"); if(! real_f) printf("NG"); } printf("--------zz------"); real_f(); }
关键函数:
dlsym函数原型,
void* dlsym(void* handle,const char* symbol),
handle是由dlopen
打开动态链接库
后返回的指针
,symbol是指定获取的符号
名,对c语言而言,符号名就是函数名,我们可以使用nm查看
mysharedlib.dylib
dani-2:testC leedani$ nm mysharedlib.dylib 0000000000000f20 T _f U _puts U dyld_stub_binder
1. 生成mysharedlib.dylib, 该动态链接库的功能就是f(),打印“hello,dani”
gcc -dynamiclib -o mysharedlib.dylib mysharedlib.c
dynamiclib选项是指生成动态链接库
2. 编译
mysharedlib.dylib与main.c文件,生成最终的可执行文件
3. 生成openhook.dylib,该动态链接库的功能就是替换mysharedlib.dylib中的
f()
gcc mysharedlib.dylib main.c -o main
gcc -flat_namespace -dynamiclib -o openhook.dylib openhook.c
flat_namespace选项指定了链接模式,有两种模式,flat-namespace与two-levelnamespace,模式不一样生成的符号表也会不一样(具体区别)。
实例中mysharedlib.dylib没有采用该选项,而openhook.dylib采用了该选项,我们可以查看以下这两个文件的头结构,来对比一下
dani-2:testC leedani$ otool -hV mysharedlib.dylib mysharedlib.dylib: Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags MH_MAGIC_64 X86_64 ALL 0x00 DYLIB 13 1200 NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS
dani-2:testC leedani$ otool -hV openhook.dylib openhook.dylib: Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags MH_MAGIC_64 X86_64 ALL 0x00 DYLIB 13 1272 DYLDLINK NO_REEXPORTED_DYLIBS
1. 正常的运行结果
dani-2:test leedani$ ./main hello,dani2. Hook后的运行结果
通过设置环境变量DYLD_INSERT_LIBRARIES(linux上对应的环境变量是
LD_PRELOAD ,效果实例可见
Android hook——LD_PRELOAD
)
dani-2:test leedani$ export DYLD_FORCE_FLAT_NAMESPACE=1 dani-2:test leedani$ export DYLD_INSERT_LIBRARIES=openhook.dylib dani-2:test leedani$ ./main --------zz------hello,dani
DYLD_INSERT_LIBRARIES与DYLD_FORCE_FLAT_NAMESPACE环境变量在apple官方手册中有说明,如下所示:
实例二:替换系统动态链接库中的函数,如下所示替换/usr/lib/libSystem.dylib中的time函数
(一)、源码
time .c
#include //This function will override the one in /usr/lib/libSystem.dylib time_t time(time_t *tloc){ //January 1st,2013 struct tm timeStruct; timeStruct.tm_year= 2013-1900; timeStruct.tm_mon = 0; timeStruct.tm_mday = 1; timeStruct.tm_hour = 0; timeStruct.tm_min = 0; timeStruct.tm_sec = 0; timeStruct.tm_isdst = -1; *tloc = mktime(&timeStruct); return *tloc; }
(二)、编译
gcc -flat_namespace -dynamiclib -current_version 1.0 time.o -o libTime.dylib
(三)、运行
1. 正常的运行结果
dani-2:test leedani$ date 2013年 2月 1日 星期五 14时46分16秒 CST2.替换系统函数后的运行结果
dani-2:test leedani$ export DYLD_FORCE_FLAT_NAMESPACE=1
dani-2:test leedani$ export DYLD_INSERT_LIBRARIES=libTime.dylib dani-2:test leedani$ date 2013年 1月 1日 星期二 00时00分00秒 CST
</pre><div style="line-height: normal; font-family: Georgia, serif; font-size: 13px;"><a target=_blank target="_blank" href="http://koichitamura.blogspot.com/2008/11/hooking-library-calls-on-mac.html" style="text-decoration: none; color: rgb(62, 115, 160);">实例来源</a></div><div style="line-height: normal; font-family: Georgia, serif;"><span style="word-wrap: normal; word-break: normal; line-height: 23px; font-size: 13px;">(一)、</span><span style="font-size:14px;word-wrap: normal; word-break: normal; line-height: 28px;"><strong>源码</strong></span></div><div style="line-height: normal; font-family: Georgia, serif; font-size: 13px;">1. mysharedlib.h</div><div><pre style="white-space: normal; padding: 2px; border: 1px solid rgb(136, 136, 136);"><span style="font-size:14px;word-wrap: normal; word-break: normal; line-height: 23px;"><span style="word-wrap: normal; word-break: normal; line-height: 20px;"><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 136);">class</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);"> AAA</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">{</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 136);">public</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">:</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 136);">int</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);"> m</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">;</span><br style="line-height: 23px;" /><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);">AAA</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">()</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">{</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);">m </span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">=</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);"> </span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 102, 102);">1234</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">;</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">}</span><br style="line-height: 23px;" /><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 136);">void</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);"> fff</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">(</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 136);">int</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(0, 0, 0);"> a</span><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">);</span><br style="line-height: 23px;" /><span style="word-wrap: normal; word-break: normal; line-height: 23px; color: rgb(102, 102, 0);">};</span></span></span>2. mysharedlib.cpp
#include
#include "mysharedlib.h"
void AAA::fff(int a)
{
printf("-- Original: %d --", a);
}
3. main.cpp
#include #include "mysharedlib.h" int main() { AAA a; printf("---------main1-------\n"); a.fff(50); printf("\n---------main2-------\n"); return 0; }4. openhook.cpp
#include #include #include #include "mysharedlib.h" typedef void (*AAAfffType)(AAA*,int); static void (*real_AAAfff)(AAA*,int); extern "C" { void _ZN3AAA3fffEi(AAA* a, int b) { printf("---------AAA::fff------\n"); printf("%d,%d \n",b,a->m); void * handle = dlopen("mysharedlib.dylib", RTLD_NOW); real_AAAfff = (AAAfffType)dlsym(handle, "_ZN3AAA3fffEi"); if(real_AAAfff) printf("OK"); real_AAAfff(a,b); } }
关键函数:
dlsym函数原型,
void* dlsym(void* handle,const char* symbol),
handle是由dlopen
打开动态链接库
后返回的指针
,symbol是指定获取的符号
名,对c++语言而言,由于存在name mangling,符号名不再是函数名了,编译器不同生成的符号名也会有所区别,
我们可以使用nm查看
mysharedlib.dylib
dani-2:testCPP leedani$ nm mysharedlib.dylib
0000000000000f0c T __ZN3AAA3fffEi
U _printf
U dyld_stub_binder
使用关键字extern "C"是为了防止符号名被mangle,使其可以像c一样被dlsym加载,
具体的如何在unix环境下使用dlopen 动态加载c++类函数可以看这篇文章《
c++ dlopen mini HOWTO
》
(二)、
编译
1. 生成mysharedlib.dylib, 该动态链接库的功能就是f(),打印“hello,dani”
gcc -dynamiclib -lstdc++ -o mysharedlib.dylib mysharedlib.cpp
2. 编译
mysharedlib.dylib与main.c文件,生成最终的可执行文件
3. 生成openhook.dylib,该动态链接库的功能就是替换mysharedlib.dylib中的
f()
gcc -lstdc++ mysharedlib.dylib main.cpp -o main
gcc -flat_namespace -dynamiclib -lstdc++ -o openhook.dylib openhook.cpp
(三)、
运行
1. 正常运行
dani-2:testCPP leedani$ ./main ---------main1------- -- Original: 50 -- ---------main2-------
2. hook后的结果,通过设置环境变量DYLD_INSERT_LIBRARIES
dani-2:test leedani$ export DYLD_FORCE_FLAT_NAMESPACE=1
dani-2:test leedani$ export DYLD_INSERT_LIBRARIES=openhook.dylib
dani-2:testCPP leedani$ ./main ---------main1------- ---------AAA::fff------ 50,1234 OK -- Original: 50 -- ---------main2-------
三、小结
这种通过设置环境变量DYLD_INSERT_LIBRARIES,动态加载函数、类方法来实现使用自己编写的动态连接库dylib来patch运行中的应用的手段,是外挂、MobileSubstrate插件的主要原理,推广到PC windows平台(dll hook),Android平台(linux平台)(so hook),iOS平台(mac平台)(dylib hook),可以说动态加载技术奠定了软件patch的基础,需要深入了解。
http://koichitamura.blogspot.com/2008/11/hooking-library-calls-on-mac.html
http://hactheplanet.com/blog/80
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man1/dyld.1.html
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/dlopen.3.html
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/dlsym.3.html
https://developer.apple.com/library/mac/#documentation/developertools/conceptual/MachOTopics/1-Articles/executing_files.html