通过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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <malloc/malloc.h> // 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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
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解释执行 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 iOS 中,`_dyld_get_image_vmaddr_slide` 函数法直接获取某个特定动态库的加载地址,它只能用来获取当前进程中加载的动态库的偏移量(Slide)。然而,我们可以结合其他方法来计算出特定动态库的加载地址。 以下是一种获取特定动态库加载地址的方法: ```objective-c #include <mach-o/dyld.h> uintptr_t getLibraryLoadAddress(const char *libraryName) { uint32_t count = _dyld_image_count(); for (uint32_t i = 0; i < count; i++) { const char *imageName = _dyld_get_image_name(i); if (strstr(imageName, libraryName) != NULL) { uintptr_t slide = _dyld_get_image_vmaddr_slide(i); uintptr_t loadAddress = _dyld_get_image_header(i)->vmaddr + slide; return loadAddress; } } return 0; } ``` 在上述代码中,我们定义了一个名为 `getLibraryLoadAddress` 的函数,它接受一个参数 `libraryName` 表示要获取加载地址的动态库的名称。 在函数内部,我们使用 `_dyld_image_count` 函数获取当前进程中加载的动态库数量。然后使用 `_dyld_get_image_name` 函数获取每个动态库的名称,与目标动态库名称进行匹配。 一旦找到目标动态库,我们使用 `_dyld_get_image_vmaddr_slide` 函数获取偏移量(Slide),并使用 `_dyld_get_image_header` 函数获取动态库的头部信息。通过将偏移量与动态库的虚拟内存基地址相加,即可得到目标动态库的加载地址。 如果成功获取到目标动态库的加载地址,则该地址将被返回。否则,返回 0。 使用示例: ```objective-c const char *libraryName = "libYourLibrary.dylib"; uintptr_t loadAddress = getLibraryLoadAddress(libraryName); if (loadAddress != 0) { printf("The load address of %s is 0x%lx\n", libraryName, loadAddress); } else { printf("Failed to get the load address of %s\n", libraryName); } ``` 请确保提供正确的动态库名称,并链接 `mach-o/dyld.h` 头文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值