歡迎閱讀iOS逆向系列(按序閱讀食用效果更加)git
以前在iOS逆向 代碼注入+Hook篇章講過Method Swizzling
,這是一種基於Runtime
能夠動態改變方法實現的HOOK方案,但Method Swizzling
有本身的侷限性,本文就將系統的介紹一下何謂HOOK
和fishhook
github
HOOK
翻譯成中文爲「掛鉤」、「鉤子」,在iOS逆向領域中指的是改變程序運行流程的一種技術,經過HOOK
可讓別人的程序執行本身所寫的代碼數組
下列示意圖就是對HOOK功能的形象詮釋:安全
在iOS中HOOK技術有如下幾種:微信
SEL(方法編號)
和IMP(方法實現)
的對應關係,達到OC方法調用流程改變的目的Mobile Substrate
,它的主要做用是針對OC方法、C函數以及函數地址進行HOOK操做,且安卓也能使用以前已經介紹過
Method Swizzling
了,OC的Runtime特性讓它有了「黑魔法」之稱,同時也是侷限性所在網絡
三者的區別以下:框架
Method Swizzling
只適用於動態的OC方法(運行時肯定函數實現地址)fishhook
適用於靜態的C方法(編譯時肯定函數實現地址)Cydia Substrate
是一種強大的框架,只須要經過Logos語言(相似於正向開發)就能夠進行Hook,適用於OC方法、C函數以及函數地址在github上找到fishhook
的代碼,將fishhook.c
、fishhook.h
拖入項目中函數
整個fishhook就開放了一個結構體rebinding
和兩個函數工具
rebind_symbols
hook項目中的全部函數名稱rebind_symbols_image
只hook某一個資源庫的函數名稱
使用fishhook的步驟:post
#import "fishhook.h"
複製代碼
rebinding
結構體對象struct rebinding nslog;
nslog.name = "NSLog";
nslog.replacement = fxNSlog;
nslog.replaced = (void *)&sys_nslog;
複製代碼
rebind_symbols
從新綁定符號struct rebinding rebs[] = {nslog};
rebind_symbols(rebs, 1);
複製代碼
完整代碼以下:
#import "fishhook.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
struct rebinding nslog;
nslog.name = "NSLog";
nslog.replacement = fxNSlog;
nslog.replaced = (void *)&sys_nslog;
struct rebinding rebs[] = {nslog};
rebind_symbols(rebs, 1);
}
static void(*sys_nslog)(NSString *format, ...);
void fxNSlog(NSString *format, ...) {
format = [format stringByAppendingFormat:@"已hook"];
sys_nslog(format);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"點擊屏幕");
}
@end
複製代碼
rebinding
來指定交換的函數
name
中指定Hook的函數名稱(C字符串)replacement
中指定新的函數地址
replaced
中存放原始函數地址的指針
NSLog
在Foundation庫中,在每一個手機的內存地址都不同,不能經過CMD+B
就能肯定其內存地址NSLog
的地址,因此這裏定義新的函數指針保存函數實現&
修改變量內部的值(void *)
進行類型轉換rebind_symbols
中須要兩個參數
rebinding
數組rebinding
數組的長度前面介紹了fishhook
是用來hook C函數的,但在此前提下仍是有它的侷限性——沒法交換自定義函數
C函數
是靜態的,在編譯時就已經肯定了函數地址(函數實現地址在MachO本地文件中)系統C函數
則是存在着動態的部分那麼爲何系統級別的C函數就能夠呢?這就要說到PIC技術了
PIC技術
(Position-independent code),又叫作位置獨立代碼
,是爲了系統C函數
在編譯時期可以確認一個地址的一種技術手段
Load Commands
中會依賴Foundation
),在符號表中找到了NSLog
函數,就會進行連接綁定——將Foundation
中NSLog
的真實地址賦值到DATA段
的NSLog
符號上而自定義的C函數不會生成符號表,直接就是一個函數地址,因此fishhook的侷限性就在於只有符號表內的符號能夠hook(從新綁定符號)
由於NSLog
是個懶加載的符號,因此加了行代言代碼
image list
打印全部鏡像資源——第一個就是進程的內存首地址
memory read 內存地址
讀出符號地址
因爲iOS是小端模式,內存地址8位倒着讀dis -s 內存地址
查看彙編
此時的符號並無綁定,由於尚未使用在fishhook的開源網站上有這麼一張工做原理圖
接下來分析下rebind_symbols
:
prepend_rebindings
將rebindings
數組不斷添加到_rebindings_head
鏈表的頭部成爲新的頭節點_rebindings_head->next
是否爲空來判斷是不是第一次調用
_dyld_register_func_for_add_image
進行回調監聽_rebind_symbols_for_image
接下來是_rebind_symbols_for_image
對MachO文件的操做:按照規則計算各類表的地址和指針在表中的偏移量
最後一步,perform_rebinding_with_section
根據算好的符號表地址和偏移量,找到在符號表中用於指向共享庫目標函數的指針,將該指針的值(即目標函數的地址)賦值給rebinding
的*replaced
,最後修改該指針的值爲replacement
(新的函數地址)
接下來就根據字符串對應在符號表中的指針,找到其在共享庫的函數實現的
Lazy Symbol Pointers
中位列第一個,下標爲0
Dynamic System Table->Indirect Symbols
中的value與Lazy Symbol Pointers
一一對應,此表中的Data(0xA9=169)即爲另外一個表的下標
Symbol Table->Symbols
中找到NSLog,此時的Data對應String Table Index
中的偏移值(0x0000009B)
String Table
中計算表頭(0x000061EC)+偏移量(0x0000009B),找到NSLog的函數地址
既然fishhook
能夠交換C函數,那麼就能夠交換method_exchangeImplementations
等函數來防止HOOK,項目自己若是須要使用method_exchangeImplementations
則可使用新的函數地址來進行操做
在安全攻防領域中,hook原理起到相當重要的做用,而使用fishhook作防禦雖然意義不大,可是瞭解fishhook原理對後續的學習仍是挺有幫助的