iOS安全攻防(十七):Fishhook

原文地址:http://blog.csdn.net/yiyaaixuexi/article/details/19094765


众所周知,Objective-C的首选hook方案为Method Swizzle,于是大家纷纷表示核心内容应该用C写。
接下来进阶说说iOS下C函数的hook方案,先介绍第一种方案————fishhook .


什么是fishhook

fishhook是facebook提供的一个动态修改链接Mach-O符号表的开源工具。



什么是Mach-O

Mach-O为Mach Object文件格式的缩写,也是用于iOS可执行文件,目标代码,动态库,内核转储的文件格式。
Mach-O有自己的dylib规范。



fishhook的原理

详见官方的How it works,这里我作个简要说明。
dyld链接2种符号,lazy和non-lazy,fishhook可以重新链接/替换本地符号。





如图所示,__DATA区有两个section和动态符号链接相关:__nl_symbol_ptr 、__la_symbol_ptr。__nl_symbol_ptr为一个指针数组,直接对应non-lazy绑定数据。__la_symbol_ptr也是一个指针数组,通过dyld_stub_binder辅助链接。<mach-o/loader.h>的section头提供符号表的偏移量。
图示中,1061是间接符号表的偏移量,*(偏移量+间接符号地址)=16343,即符号表偏移量。符号表中每一个结构都是一个nlist结构体,其中包含字符表偏移量。通过字符表偏移量最终确定函数指针。

fishhook就是对间接符号表的偏移量动的手脚,提供一个假的nlist结构体,从而达到hook的目的。


fishhook替换符号函数:

  1. int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {  
  2.   int retval = prepend_rebindings(rebindings, rebindings_nel);  
  3.   if (retval < 0) {  
  4.     return retval;  
  5.   }  
  6.   // If this was the first call, register callback for image additions (which is also invoked for  
  7.   // existing images, otherwise, just run on existing images  
  8.   if (!rebindings_head->next) {  
  9.     _dyld_register_func_for_add_image(rebind_symbols_for_image);  
  10.   } else {  
  11.     uint32_t c = _dyld_image_count();  
  12.     for (uint32_t i = 0; i < c; i++) {  
  13.       rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));  
  14.     }  
  15.   }  
  16.   return retval;  
  17. }  

关键函数是 _dyld_register_func_for_add_image,这个函数是用来注册回调,当dyld链接符号时,调用此回调函数。 rebind_symbols_for_image 做了具体的替换和填充。




fishhook替换Core Foundation函数的例子



以下是官方提供的替换Core Foundation中open和close函数的实例代码
  1. #import <dlfcn.h>  
  2.   
  3. #import <UIKit/UIKit.h>  
  4.   
  5. #import "AppDelegate.h"  
  6. #import "fishhook.h"  
  7.   
  8. static int (*orig_close)(int);  
  9. static int (*orig_open)(const charchar *, int, ...);  
  10.   
  11. void save_original_symbols() {  
  12.   orig_close = dlsym(RTLD_DEFAULT, "close");  
  13.   orig_open = dlsym(RTLD_DEFAULT, "open");  
  14. }  
  15.   
  16. int my_close(int fd) {  
  17.   printf("Calling real close(%d)\n", fd);  
  18.   return orig_close(fd);  
  19. }  
  20.   
  21. int my_open(const charchar *path, int oflag, ...) {  
  22.   va_list ap = {0};  
  23.   mode_t mode = 0;  
  24.   
  25.   if ((oflag & O_CREAT) != 0) {  
  26.     // mode only applies to O_CREAT  
  27.     va_start(ap, oflag);  
  28.     mode = va_arg(ap, int);  
  29.     va_end(ap);  
  30.     printf("Calling real open('%s', %d, %d)\n", path, oflag, mode);  
  31.     return orig_open(path, oflag, mode);  
  32.   } else {  
  33.     printf("Calling real open('%s', %d)\n", path, oflag);  
  34.     return orig_open(path, oflag, mode);  
  35.   }  
  36. }  
  37.   
  38. int main(int argc, charchar * argv[])  
  39. {  
  40.   @autoreleasepool {  
  41.     save_original_symbols();  
  42.     //fishhook用法  
  43.     rebind_symbols((struct rebinding[2]){{"close", my_close}, {"open", my_open}}, 2);  
  44.   
  45.     // Open our own binary and print out first 4 bytes (which is the same  
  46.     // for all Mach-O binaries on a given architecture)  
  47.     int fd = open(argv[0], O_RDONLY);  
  48.     uint32_t magic_number = 0;  
  49.     read(fd, &magic_number, 4);  
  50.     printf("Mach-O Magic Number: %x \n", magic_number);  
  51.     close(fd);  
  52.   
  53.     return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));  
  54.   }  
  55. }  



注释//fishhook用法 处

  1. rebind_symbols((struct rebinding[2]){{"close", my_close}, {"open", my_open}}, 2);  

传入rebind_symbols的第一个参数是一个结构体数组,大括号中为对应数组内容。




不得不说,facebook忒NB。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值