最近看了一些關(guān)于 iOS 逆向的基礎(chǔ)知識(shí)和一些開源代碼拖云。
根據(jù) Cydia SubStrate 關(guān)于 MSHookMessageEx 這個(gè) API 的介紹:<br />
Objective-C 提供了好用的 high_level runtime API, 允許開發(fā)者使用 class_getInstanceMethod
, method_setImplementation
和更強(qiáng)大的 method_exchangeImpletation
來 swizzle 方法實(shí)現(xiàn)并改變功能节榜。
雖然這些 API 非常好用条获,而且 method swizzling 并不是 iOS 開發(fā)的“日诚纺纾”,但是它們卻不能勝任更復(fù)雜的情況酷含。** 比方說檬某,在繼承層次上的不同 level 上去 hook 同一個(gè) message,那么就會(huì)出現(xiàn)順序的問題钓试。 **
此外装黑,還有一點(diǎn)需要注意:當(dāng)使用 instrument 的時(shí)候,class 會(huì)被修改弓熏,并沒有初始化("initialized")恋谭。這樣做既改變了 target program 的順序,也使得 hook 初始化時(shí)序 變得不可能挽鞠【渭眨總而言之,Objective-C runtime API 的實(shí)現(xiàn)方式改變了信认。
考慮了上述所有問題材义,Substrate 提供了一個(gè)更好的 API :
void MSHookMessageEx(Class _class, SEL message, IMP hook, IMP *old);
不需要初始化一個(gè) class,并且保證在繼承層次上使用正確的 implementation.
根據(jù) New Relic 的文章嫁赏,假如有兩個(gè)方法:
- (void) originalMethod;
- (void) swizzle_originalMethod;
如果直接使用 void method_exchangeImplementations(Method m1, Method m2)
其掂, 而且恰巧代碼的實(shí)現(xiàn)如下(將會(huì)出現(xiàn)錯(cuò)誤,這里使用了 assert):
- (void) originalMethod //m1
{
assert([NSStringFromSelector(_cmd) isEqualToString:@“originalMethod”]);
//this `assert` fails after swizzling
//if using method_exchangedImplementations()
//…
}
正確的方式是去寫 C 函數(shù)潦蝇,并且使用 method_setImplementation()
將 C 函數(shù)強(qiáng)轉(zhuǎn)成 IMP
. 這將避免 Objective-C 傳遞像一個(gè)新的 selector name 這樣額外的信息款熬。
不要忘記一點(diǎn):所有的 Objective-C 方法都帶有 2 個(gè)隱藏的參數(shù)(這一點(diǎn),當(dāng)我們用 Hopper 或者 IDA 來逆向的時(shí)候很容易看到):一個(gè)指向自身的引用 id self
和一個(gè) method selector SEL _cmd
.
如果要使用一個(gè)返回 void 的 IMP
, 那么就必須強(qiáng)轉(zhuǎn)攘乒。這是因?yàn)?ARC 假設(shè)所有的 IMP 會(huì)返回 id, 并嘗試 retain void 和基本類型數(shù)據(jù)贤牛。
IMP anImp; //represents objective-c function
// such as -UIViewController viewDidLoad;
((void(*)(id,SEL))anImp)(self,_cmd); //call with a cast to prevent
// ARC from retaining void.
微信讀書團(tuán)隊(duì)曾經(jīng)分享過由 Peter Steinberger 大神寫的 Aspects 開源庫的代碼分析(文章鏈接)。正如之前在微博上看到的一句話:“別說寫出 Aspects 了则酝,能完全看懂 Aspects 的人也是寥寥殉簸。”
使用 Method Swizzling 是一種最后的手段,盡量應(yīng)該避免喂链。之前有人在 UITableView 上去 hook 了很多方法返十,并且對(duì) UITableView 的 runloop 進(jìn)行觀察和做額外的工作。這些都應(yīng)該謹(jǐn)慎對(duì)待椭微。對(duì)于 UITableView 這樣重要的基礎(chǔ)類來說洞坑,如果不是特別特別熟悉 iOS 系統(tǒng)原理就開始玩“黑魔法”,很容易被“黑魔法”吞噬的蝇率。