鍍金池/ 教程/ iOS/ Fishhook
Hack 實戰(zhàn)——支付寶 App 手勢密碼校驗欺騙
使用 Reveal 分析他人 App
后臺 daemon 非法竊取用戶 iTunesstore 信息
使用 iNalyzer 分析應(yīng)用程序
越獄檢測的攻與防
使用 introspy 追蹤分析應(yīng)用程序
廢除應(yīng)用程序的 ASLR 特性
使用 Cycript 修改支付寶 App 運行時
敏感邏輯的保護方案
Fishhook
使用 class-dump-z 分析支付寶 App
static 和被裁的符號表
iOS7 的動態(tài)庫注入
二進制和資源文件自檢
Hack 實戰(zhàn)——探究支付寶 App 手勢密碼
使用 Keychain-Dumper 導出 keychain 數(shù)據(jù)
數(shù)據(jù)擦除
Hack 實戰(zhàn)——解除支付寶 App 手勢解鎖錯誤次數(shù)限制
Objective-C 代碼混淆
阻止 GDB 依附
基于腳本實現(xiàn)動態(tài)庫注入
Hack 必備的命令與工具
鍵盤緩存與安全鍵盤
數(shù)據(jù)保護 API

Fishhook

眾所周知,Objective-C 的首選 hook 方案為 Method Swizzle,于是大家紛紛表示核心內(nèi)容應(yīng)該用 C 寫。

接下來進階說說 iOS 下 C 函數(shù)的 hook 方案,先介紹第一種方案--- fishhook .

什么是 fishhook

fishhook 是 facebook 提供的一個動態(tài)修改鏈接 Mach-O 符號表的開源工具。

什么是 Mach-O

Mach-O 為 Mach Object 文件格式的縮寫,也是用于 iOS 可執(zhí)行文件,目標代碼,動態(tài)庫,內(nèi)核轉(zhuǎn)儲的文件格式。

Mach-O 有自己的 dylib 規(guī)范。

fishhook 的原理

詳見官方的 How it works,這里我作個簡要說明。

dyld 鏈接 2 種符號,lazy 和 non-lazy ,fishhook 可以重新鏈接/替換本地符號。

http://wiki.jikexueyuan.com/project/ios-security-defense/images/fishhook1.png" alt="fishhook1" />

如圖所示,__DATA區(qū)有兩個 section 和動態(tài)符號鏈接相關(guān):__nl_symbol_ptr__la_symbol_ptr。__nl_symbol_ptr 為一個指針數(shù)組,直接對應(yīng) non-lazy 綁定數(shù)據(jù)。__la_symbol_ptr 也是一個指針數(shù)組,通過dyld_stub_binder 輔助鏈接。<mach-o/loader.h>的 section 頭提供符號表的偏移量。

圖示中,1061 是間接符號表的偏移量,*(偏移量+間接符號地址)=16343,即符號表偏移量。符號表中每一個結(jié)構(gòu)都是一個 nlist 結(jié)構(gòu)體,其中包含字符表偏移量。通過字符表偏移量最終確定函數(shù)指針。

fishhook 就是對間接符號表的偏移量動的手腳,提供一個假的 nlist 結(jié)構(gòu)體,從而達到 hook 的目的。

fishhook 替換符號函數(shù):

int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {  
  int retval = prepend_rebindings(rebindings, rebindings_nel);  
  if (retval < 0) {  
    return retval;  
  }  
  // If this was the first call, register callback for image additions (which is also invoked for  
  // existing images, otherwise, just run on existing images  
  if (!rebindings_head->next) {  
    _dyld_register_func_for_add_image(rebind_symbols_for_image);  
  } else {  
    uint32_t c = _dyld_image_count();  
    for (uint32_t i = 0; i < c; i++) {  
      rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));  
    }  
  }  
  return retval;  
} 

關(guān)鍵函數(shù)是 _dyld_register_func_for_add_image,這個函數(shù)是用來注冊回調(diào),當 dyld 鏈接符號時,調(diào)用此回調(diào)函數(shù)。 rebind_symbols_for_image 做了具體的替換和填充。

fishhook 替換 Core Foundation 函數(shù)的例子

以下是官方提供的替換 Core Foundation 中 open 和 close 函數(shù)的實例代碼

#import <dlfcn.h>  

#import <UIKit/UIKit.h>  

#import "AppDelegate.h"  
#import "fishhook.h"  

static int (*orig_close)(int);  
static int (*orig_open)(const charchar *, int, ...);  

void save_original_symbols() {  
  orig_close = dlsym(RTLD_DEFAULT, "close");  
  orig_open = dlsym(RTLD_DEFAULT, "open");  
}  

int my_close(int fd) {  
  printf("Calling real close(%d)\n", fd);  
  return orig_close(fd);  
}  

int my_open(const charchar *path, int oflag, ...) {  
  va_list ap = {0};  
  mode_t mode = 0;  

  if ((oflag & O_CREAT) != 0) {  
    // mode only applies to O_CREAT  
    va_start(ap, oflag);  
    mode = va_arg(ap, int);  
    va_end(ap);  
    printf("Calling real open('%s', %d, %d)\n", path, oflag, mode);  
    return orig_open(path, oflag, mode);  
  } else {  
    printf("Calling real open('%s', %d)\n", path, oflag);  
    return orig_open(path, oflag, mode);  
  }  
}  

int main(int argc, charchar * argv[])  
{  
  @autoreleasepool {  
    save_original_symbols();  
    //fishhook用法  
    rebind_symbols((struct rebinding[2]){{"close", my_close}, {"open", my_open}}, 2);  

    // Open our own binary and print out first 4 bytes (which is the same  
    // for all Mach-O binaries on a given architecture)  
    int fd = open(argv[0], O_RDONLY);  
    uint32_t magic_number = 0;  
    read(fd, &magic_number, 4);  
    printf("Mach-O Magic Number: %x \n", magic_number);  
    close(fd);  

    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));  
  }  
}  

注釋 // fishhook 用法處: rebind_symbols((struct rebinding[2]){{"close", my_close}, {"open", my_open}}, 2);

傳入 rebind_symbols 的第一個參數(shù)是一個結(jié)構(gòu)體數(shù)組,大括號中為對應(yīng)數(shù)組內(nèi)容。

不得不說,facebook 忒 NB 。