通过DYLD_INSERT_LIBRARIES实现基于动态库的hook功能

Wrox Press Mac OS X and iOS Internals, To the Apple’s Core (2013).pdf PAGE164也有描述:
支持动态库插入(Interposing)功能,是苹果加载器dyld在传统加载器的一个不同的地方。通过向宏DYLD_INSERT_LIBRARIES里写入动态库完整路径。就可以在执行文件加载时将该动态库插入。
dyld源代码摘列:
include/mach-o/dyld-interposing.h
#if !defined(_DYLD_INTERPOSING_H_)
#define _DYLD_INTERPOSING_H_
/* Example:
* static
* int
* my_open(const char* path, int flags, mode_t mode)
* {
* int value;
* // do stuff before open (including changing the arguments)
* value = open(path, flags, mode);
* // do stuff after open (including changing the return value(s))
* return value;
* }
* DYLD_INTERPOSE(my_open, open)
*/
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; }
_interpose_##_replacee \
__attribute__ ((section (“__DATA,__interpose”))) = { (const void*)(unsigned
long)&_replacment, (const void*)(unsigned long)&_replacee };
#endif
Interposing就是说注入的动态库会创建一个叫做__interpose的数据段,里面放好原始函数的地址,以及替换函数的地址,dyld在加载时对跳转地址进行替换。
《Mac hook——DYLD_INSERT_LIBRARIES》
http://danqingdani.blog.163.com/blog/static/186094195201311105254605/
我测试了一下这种方法也可以用在iOS上
jerry@ubuntu:~/toolchain4/Projects/hook$ ~/toolchain4/pre/bin/arm-apple-darwin9-gcc -dynamiclib -o mysharedlib.dylib mysharedlib.c
jerry@ubuntu:~/toolchain4/Projects/hook$ ~/toolchain4/pre/bin/arm-apple-darwin9-gcc mysharedlib.dylib main.c -o main
jerry@ubuntu:~/toolchain4/Projects/hook$ ~/toolchain4/pre/bin/arm-apple-darwin9-gcc -flat_namespace -dynamiclib -o openhook.dylib openhook.c
JerrysPhone:/home/jerry root# ./main
hello,dani
JerrysPhone:/home/jerry root# export DYLD_FORCE_FLAT_NAMESPACE=1
JerrysPhone:/home/jerry root# export DYLD_INSERT_LIBRARIES=openhook.dylib
JerrysPhone:/home/jerry root# ./main
——–zz——hello,dani
对于系统动态库也同样适用:
############################################################################
#include 
#include 
#include 
#include 
#include  // for malloc_printf()
// This is the expected interpose structure
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
// Our prototypes – requires since we are putting them in
// the interposing_functions, below
void *my_malloc(int size); // matches real malloc()
void my_free (void *); // matches real 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)
{
// In our function we have access to the real malloc() -// and since we don’t want to mess with the heap ourselves,
// just call it.
void *returned = malloc(size);
// call malloc_printf() because the real printf() calls malloc()
// internally – and would end up calling us, recursing ad infinitum
malloc_printf ( “+ %p %d\n”, returned, size);
return (returned);
}
void my_free (void *freed)
{
// Free – just print the address, then call the real free()
malloc_printf ( “- %p\n”, freed);
free(freed);
}
############################################################################
jerry@ubuntu:~/toolchain4/Projects/hook$ ~/toolchain4/pre/bin/arm-apple-darwin9-gcc -dynamiclib malloc_hook.c -o libMTrace.dyli -Wall
JerrysPhone:/home/jerry root# DYLD_INSERT_LIBRARIES=libMTrace.dylib ls
ls(1771) malloc: + 0x147e60 60
ls(1771) malloc: + 0×148450 4
ls(1771) malloc: + 0x1484a0 20
ls(1771) malloc: + 0x1484c0 20
ls(1771) malloc: + 0x1484f0 16
ls(1771) malloc: + 0×148510 20
ls(1771) malloc: – 0×148500
ls(1771) malloc: – 0x1484e0
ls(1771) malloc: – 0×148510
ls(1771) malloc: + 0×148500 16
ls(1771) malloc: + 0×148550 20
ls(1771) malloc: + 0×148570 16
ls(1771) malloc: – 0×148540
ls(1771) malloc: + 0×148590 20
其实Cydia的Substrate框架也是基于DYLD_INSERT_LIBRARIES来实现的。
对于SpringBoard下启动的GUI程序,环境变量里都存在参数DYLD_INSERT_LIBRARIES=/Library/MobileSubstrate/MobileSubstrate.dylib
这个动态库实际是指向/Library/Frameworks/CydiaSubstrate.framework/Libraries/SubstrateBootstrap.dylib
这里写一个重定向stdio代码
############################################################################
#include 
#include 
#include 
#include 
#include 
int save_fd;
void ExampleHookInitialize(void)
{
int fd;
fflush(stdout);
setvbuf(stdout,NULL,_IONBF,0);
save_fd = dup(STDOUT_FILENO);
fd = open(“/home/jerry/log.txt”,(O_RDWR | O_CREAT), 0644);
dup2(fd,STDOUT_FILENO);
printf(“Here is dll init, redirect stdout to logfile\n”);
return;
}
############################################################################
编译命令:这里的-init参数指定了动态库入口
~/toolchain4/pre/bin/arm-apple-darwin9-gcc -init _ExampleHookInitialize -dynamiclib -o testlib.dylib testlib.c
使用下面的命令测试:
DYLD_INSERT_LIBRARIES=testlib.dylib ls
发现ls输出的信息都被写入了/home/jerry/log.txt文件中。
如果用这个动态库替换掉上面说的SubstrateBootstrap.dylib
这样启动GUI程序后可以看到log.txt文件生成,但是除了”Here is dll init, redirect stdout to logfile\n”这句之后在无其他内容。后来我在__interpose里添加了对fopen的hook。但是效果也不好。对 SubstrateBootstrap.dylib的替换会对后启动的进程都造成影响,这样就会不好控制。
因为通过ssh登陆,控制台对应/dev/ttysxxx这样的节点:
0  1035     1   0   0:00.00 ??         0:00.40 sshd: root@ttys002
这样我可以
freopen(“/dev/ttys002″, “w”, stdout);
这样信息就直接送到终端软件上了。
hook这里要解决的问题是:

如何在toolchain4编译环境上使用Substrate框架,产生针对某个进程的hook动态库。 


注:

先感谢楼主。不过更正一下,interpose section 里只有replacement 的地址,被替换的函数地址都是填0的。被替换函数的具体信息是在LC_DYLD_INFO_ONLY load command里,在dyld动态链接的时候被dyld解释执行 

你可能感兴趣的:(ios逆向)