逆向block是一個(gè)稍微難點(diǎn)的活,因?yàn)槟悴⒉恢佬枰獋魇裁礃拥膮?shù),也不知道是什么類型的返回。另外,Swift的block的內(nèi)存分布的實(shí)現(xiàn)與OC不一樣會(huì)帶你入坑。
接著上回逆向系列0x01-在Swift中使用Social框架,我們將實(shí)現(xiàn)SLComposeViewController的completion回調(diào)。
crash?
打開ViewController.swift把下面邏輯加入到sharingButtonTapped(_:)中:
...
vc.completionHandler = {
print("SLComposeViewController completed")
}
present(vc, animated: true)
...
請(qǐng)確保你已經(jīng)在設(shè)備上登陸了Facebook賬號(hào)(假設(shè)我們使用的的serviceType是Facebook的)。構(gòu)建并運(yùn)行,點(diǎn)擊分享按鈕,然后在這個(gè)分享vc出現(xiàn)后點(diǎn)擊取消。
嗯,你又會(huì)遇到一個(gè)crash了。我們來(lái)用LLDB分析一下,選擇Frame 1:(lldb) frame select 1

仔細(xì)觀察這里的匯編,紅色線的上一個(gè)指令是個(gè)call指令,地址為對(duì)RDI內(nèi)容的偏移。那現(xiàn)在RDI里面存放的是個(gè)什么鬼呢?
跳回到第一個(gè)棧幀(你不能在frame 1訪問(wèn)寄存器RDI):
(lldb) frame select 0然后打印RDI:
(lldb) po $rdi輸出結(jié)果為:
(Function)。有點(diǎn)意思,來(lái)看看它是否是個(gè)NSObject的子類:
(lldb) po [$rdi class]
_SwiftValue
(lldb) po [$rdi superclass]
NSObject
從我先前的文章常用lldb可以知道,這個(gè)類應(yīng)該繼承自一個(gè)叫NSBlock的私有類。于是編譯器對(duì)Swfit的閉包要轉(zhuǎn)換成的OC類型做了一個(gè)錯(cuò)誤的假設(shè)。
這里的意思是你需要顯示的將Swift閉包轉(zhuǎn)換成OC的block。這是因?yàn)镾wift編譯器沒(méi)有completionHandler的類型信息,所以它沒(méi)有幫我們自動(dòng)轉(zhuǎn)換。
沒(méi)錯(cuò),在上篇的NSObject+P_SLComposeViewController.h中我們的確聲明了completionHandler的類型為id。
打開ViewController.swift用以下內(nèi)容進(jìn)行替換:
@IBAction func sharingButtonTapped(_ sender: Any) {
guard let vcClass =
NSClassFromString("SLComposeViewController") else { return }
let vc = vcClass.composeViewController(forServiceType:
"com.apple.social.twitter") as! UIViewController
vc.setInitialText("Yay! Doggie Love!")
if let originalImage = imageView.image {
vc.addImage(originalImage)
}
typealias CompletionBlock = @convention(block) () -> Void
vc.completionHandler = {
print("SLComposeViewController completed")
} as CompletionBlock
present(vc, animated: true)
}
我們?cè)黾恿艘粋€(gè)叫CompletionBlock的typealias,它將會(huì)把這個(gè)Swift閉包轉(zhuǎn)換成何時(shí)的OC對(duì)象。再次構(gòu)建并運(yùn)行app,程序再不會(huì)crash了!
OC block的參數(shù)
我們先了解以下調(diào)用OC block時(shí)的匯編指令。
在Xcode中創(chuàng)建一個(gè)GUI斷點(diǎn)在給completionHandler賦值的那一行。構(gòu)建并運(yùn)行app然后點(diǎn)擊分享按鈕。這個(gè)時(shí)候斷點(diǎn)就會(huì)命中一次,Continue忽略這一次繼續(xù)執(zhí)行。

接著按Cancel取消按鈕,這時(shí)候斷點(diǎn)會(huì)再一次被觸發(fā)。去到frame2:(lldb) frame select 2
仔細(xì)觀察這里的匯編,會(huì)發(fā)現(xiàn)一個(gè)有趣的指令。沒(méi)錯(cuò)了,就是下面紅框標(biāo)注的那一行。

在調(diào)用OC的block之前,一個(gè)參數(shù)會(huì)被保存到RSI寄存器中。這意味著這個(gè)OC block有一個(gè)參數(shù)。
在當(dāng)執(zhí)行停止時(shí)RSI寄存器沒(méi)有被重寫的前提下,我們可以打印出RSI的內(nèi)容。又因?yàn)槲覀儎偤猛T赽lock執(zhí)行的最開始,所以RSI寄存器的內(nèi)容應(yīng)該是完好如初的。
跳回到frame 0并打印RSI的內(nèi)容:
(lldb) frame select 0
(lldb) register read rsi
rsi = 0x0000000000000000
那兒并沒(méi)有任何東西。這似乎有點(diǎn)悲劇。但它至少能告訴我們一些東西。在經(jīng)過(guò)一番研究折騰蘋果是如何實(shí)現(xiàn)他們的API之后,我們可以假設(shè)一個(gè)為nil的NSObject被傳進(jìn)去了,又或者它是某種東西。在這個(gè)情形里,它可能是個(gè)枚舉值enum來(lái)標(biāo)記vc是否正常結(jié)束。
只有一種途徑來(lái)驗(yàn)證這個(gè)猜想。我們需要一次成功的內(nèi)容推送然后觀察RSI寄存器有什么變化。
那就推送吧(反正圖片是兩只可愛(ài)的狗狗,非常河蟹),點(diǎn)擊Post之后斷點(diǎn)應(yīng)該再一次命中。此時(shí)再來(lái)檢驗(yàn)一下RSI的值:
(lldb) register read rsi
rsi = 0x0000000000000001
完美!現(xiàn)在它的值是1了。這意味著這個(gè)傳進(jìn)來(lái)的參數(shù)是個(gè)會(huì)根據(jù)操作結(jié)果是失敗還是成功而變化的枚舉值(或者布爾值,差不多的)。好了我們要更新一下completionHandlerblock的類型了。
打開NSObject+P_SLComposeViewController.h然后用以下內(nèi)容替換:
typedef enum : NSUInteger {
P_SLComposePostFailed = 0,
P_SLComposePostSuccess = 1
} P_SLComposePost;
@interface NSObject (P_SLComposeViewController)
+ (id)composeViewControllerForServiceType:(NSString *)serviceType;
- (BOOL)setInitialText:(id)text;
- (BOOL)addImage:(id)image;
@property (copy, nonatomic) void (^completionHandler)(P_SLComposePost);
稍微改一下ViewController.swift:
vc.completionHandler = { result in
let resultString = result == P_SLComposePostFailed ? "failed" :
"success"
print("SLComposeViewController completed with result: \(resultString)")
}
注意到我們?cè)僖膊恍枰?code>typealias了。這是因?yàn)槲覀円呀?jīng)把completionHandler的類型從id改為了了一個(gè)block類型,于是編譯器便知道了應(yīng)該把這里的Swift閉包看待成OC的block。
大功告成!我們成功的探索并使用了別人的代碼來(lái)發(fā)送一個(gè)Facebook的post,這個(gè)過(guò)程中我們并沒(méi)有借助任何頭文件或者其他關(guān)于模塊的信息。
下篇預(yù)告:查找和執(zhí)行代碼只是逆向Framework時(shí)的挑戰(zhàn)之一。下一個(gè)挑戰(zhàn)便是修改Framework的函數(shù)的參數(shù)或邏輯來(lái)滿足我們自己的需求!暴走吧!逆向!