iOS 逆向工程

原文  https://realm.io/cn/news/conrad-kramer-reverse-engineering-ios-apps-lyft/

如果你曾經想要知道某一部分代碼如何工作,或者很同情某些人程序裏的 Bug,你要是有代碼,通常可以看看那部分代碼。但是,如果沒有代碼可怎麼辦? 在這個演講裏,Conrad 講到了很多可以逆向 App 的概念和工具,這些方法和工具可以用來 debug 別人的庫和你自己的代碼。他還展示了逆向 iOS 版本的 Lyft (譯者注:Lyft 是美國 Uber 之外的另一款打車軟件),並且成功注入代碼,探測網絡流量,給我們活靈活現地展示逆向的藝術。通過 Conrad 的逆向技術,你也能成功地把 App Store 裏所有的 App 的代碼都暴露在你面前。

Sign up to be notified of new videos — we won’t email you for any other reason, ever.


我是 Conrad Kramer ,工作在 Workflow 的一枚 iOS 工程師,今天要跟大家聊聊 iOS Apps 逆向工程那些事兒。通常來說,逆向工程就是試圖只通過最終產物來了解它背後工作原理的過程。在 iOS app 的世界裏,這意味着你在沒有源代碼的前提下,只通過從 App Store 下載的 .app 來發現你想要的信息。

在做逆向工程的時候,會遇到兩個痛點:

  1. 使用的工具 通常很難用,因爲這些工具本身就缺乏文檔,而且很不出名。他們總是崩潰出錯,而且沒人去修復這些錯誤。另外,花時間找到他們以及用好他們都很難。
  2. 一旦你開始用這些工具了,清楚自己的目標也很重要,因爲有太多事情可以幹了。此外,你還能用工具去逆向蘋果自己的框架,儘管他是閉源的。我們可以用這些技術來探索 UIKit 的某個 bug,或者某個 app 裏的 bug。

所以逆向的第一步是像自己發問:“爲什麼這個 bug 會發生?他們在 UI 裏用了哪些組件?” 比如,如果你很好奇一個 app 裏是否用了 collection view 或者 table view”,你其實很容易回答這個問題,看一眼就好了。但是如果你問:“他們的 REST API 是什麼結構的?”,這個時候逆向工程就能幫你一探究竟。

我決定通過一個項目來開始這個主題,目標是: Lyft’s iOS app ,它整個都是用 Swift 完成的。首先要做的事是我們瞭解我們感興趣的點。假設我對 REST API 很感興趣,比如我想要在另一個平臺或者在 web 上寫一個 Lyft 客戶端,我可以看看他們的 API 然後產生好奇:“他們的 URL scheme 是什麼樣子的?”,當你想對 Lyft 做深度鏈接的時候,你就不得不解決這個問題。對 Workflow 來說,相關性就更高了,因爲 Workflow 就是一個自動工具,我們集成了很多不同的 app。我總是需要做些類似的事情,來發現一些不公開的私有 URL scheme。

從 iTunes 下載下來的 Lyft 是一個 .IPA 文件(其實就是 zip 格式的)。它有很多的元數據,像 Info.plist 文件,資源文件,圖片,本地化的字符串以及很多類似的文件。這裏面也包含一些可執行文件,那些被編譯了的代碼就在裏面。另外,因爲 Lyft 是用 swift 寫的,所以還包含很多附加的框架。Lyft 現在看來是一個完完全全的黑盒子。我們不能直接的看透它,但我們依然有能力從特定的一些角度窺視到。一種方法就是通過監測網絡流量來觀察他的 API, 同時還能看到有哪些信息被它發送到了 Lyft 的服務器,這些通常對 App 而言是沒有什麼傷害的。

然後,我們還能 注入代碼 ,真的非常爽。當 app 運行的時候,你可以打探打探這些 app 裏被實例化而且存活的對象。當停止運行的時候,我們可以嘗試去研究下 .app 是如何被組織的,同時通過特定的視角來看這些代碼。

Charles 是一個 HTTPS 代理工具,它可以讓流量在發往服務器前攔截網絡流量。我們可以用這個工具來觀察所有從 Lyft app 流向服務器的請求。

Lyft 事實上通過 SSL 加密了它的所有流量。但這些都很好破,通過 中間人攻擊 的方法來解決這個問題。其實就是替換了加密證書

當你在用 Lyft 的時候,Lyft 不斷的把你的地理位置發給 Lyft 的服務器。 對車輛的請求和取消等操作會以格式化後的 JSON 在 Charles 中呈現出來。用 Charles,你會看到 app 裏和網絡交互的所有內容。

下一個工具真的很贊,叫 Cycript 。使用這個工具的時候需要一個越獄設備,注入代碼到 app 裏。Cycript 可以讓你看到別人的代碼,當然你自己寫的 app 也逃不過。這個工具是 Objective-C 和 Javascript 的混合 app,只用輸入 Objective-C 的代碼到控制檯裏,就能在 app 運行這些代碼。它的交互編程環境(REPL)比 LLDB 的要好很多。儘管它不能中斷,設置斷點等等,但他對運行時代碼非常友好。你可以直接輸入下面的代碼,基本上都是 Objective-C :

  var application = [UIApplication sharedApplication];

       [application openURL:[NSURL URLWithString:@"https://google.com"]];


我 SSH 進入我的破解過的 iPhone 6 以後,打開 Lyft,運行 Cycript,我可以通過選擇功能來獲取一個運行時的類實例,比如 view controller 的,或者統計類的實例。作爲開發者,要確定設置 ACL 來防止特定 api key 的權限問題。如果 app 能拿到這些 key,那 Cycript 也一定能拿到。

你也可以修改 app 裏的 views。比如,用 UIApp.keyWindow.recursiveDescription 通過內存尋址,把 “呼叫車輛” 的按鈕變成綠色。

var b = new Instance (ADDRESS);

b.backgroundColor = [UIColor greenColor];


Cycript 甚至還支持 tab 智能提示。這個功能不但對於逆向很有用,你還可以來測試你自己的 app,比如快速換個顏色測試測試效果什麼的。

Q: 用 Crcript 測試自己的 app 的時候,設備一定需要越獄麼?

Conrad: 對你自己的 app 的話,並不需要。在 cycript.org 官網上,提供了一些如何把這個工具嵌入到你自己的 app 的文檔。

解密可執行文件 - dumpdecrypted

接下來,我們就要來感受下 app 運行時真正的代碼了。這個稍微有些複雜,而且需要設備越獄,我們的演示會比較簡單。因爲有能力重簽名我們的設備,所以蘋果會加密商店裏所有的 app,防止 app 被大家共享。然而,對於一個越獄設備來說,所有的這些加密的 app 都是可以被解密的。我從其他人那裏 fork 了一個 repo,叫 dumpdecrypted ,原作者寫這個是爲了導出一個 app 的資源,我 fork 了一份,是爲了讓它能夠支持所有的框架,畢竟現在很多 app 都含有 frameworks。

用它的時候,你只要簡單的 clone 到本地,然後執行make,再在你越獄後的設備上對 app 執行一下。我對 Lyft 的 app 執行了這個,很快就解密了所有的文件。你看這些文件的時候,會發現所有的 framework 都以.decrypted後綴結尾。比較有意思的一些模塊是 Lyft,LyftKit 和 LyftSDK,但是我們還發現了它還用了 SocketRocket,Stripe,Pusher,Mixpanel 等等的庫。

分析可執行文件 - IDA 演示

要分析我們導出的文件,查看源代碼,我們要到 IDA ,和 Hopper 及 class-dump 類似的一個工具。當在編譯一個 app 的時候,XCode 會創建一個由彙編組成的可執行文件。IDA 能很漂亮的輸出這些可執行文件裏的彙編代碼,並且相互連接起來,你因此會看到一個由彙編代碼組成的圖。儘管 IDA 很貴,但是它的 免費版本 已經夠用了。除了 64 位以外,基本都有。

要找到 Lyft 的 URL scheme,我們可以在 IDA 裏執行一個簡單的搜索,關鍵字是openURL,在類似的反編譯工具中,Objective-C 是相對友好和容易的,因爲它對於工作原理是相對透明的,Swift 就相對較差,很多工具還沒有很好的支持 Swift,Swift 的彙編代碼也更混亂,它的類信息很難被提取出來,不過,多練習練習,看看這些彙編,你會發現一些技巧來捕獲你所想找的信息。

使用 IDA 的圖表視野,我們發現了_TZFV4Lyft15DeepLinkManager13handleOpenURLfMS0_FCSo5NSURLSb,看起來是個很亂的字符串,然而我們依然可以發現LyftDeepLinkManager,handleOpenURL, 和NSURL這幾個關鍵詞。這些看似隨機的字符串其實是有解釋的,雖然沒有文檔來說明。如果想要了解這些字符串的含義,可以看看 Mike Ash 的博客裏一篇叫做 Friday Q&A 的文章,這些模糊的東西都有解釋。比如_T意思是這是一個 Swift 的符號,F意思是這是一個函數,4Lyft是一個模塊名稱,等等。

尋找 Lyft 的 URL Scheme

想要從我們所見之中發現 URL scheme,我們就要用開發者的思維來思考。

一個 URL scheme 結構大概是這樣的:

lyft://action?parameter=value 

我們現在要去找到action是什麼,parameter可能會是哪些。我首先找到了DeepLinkAbleSwift 協議,瞭解了深度鏈接的工作原理。通過搜索DeepLinkAble關鍵字,我在一個類裏發現了諸如ride,help,invite,profile的請求對象。

我們對如何開始一次打車很好奇,我們可以看一下 Lyft 的DeepLinkToRide類,看看他是如何工作的。想要看這些,你甚至不需要了解彙編,你只需知道如何搜索和掃描彙編中你需要的信息即可。就好比你即使不會法語,卻經常看見到法語,看的足夠多次後,你總是能悟出些東西來。很多時候 IDA 展示給我們的完全就是一種外語,其實我第一次嘗試逆向 Swift 的時候,就是這樣一種感受。

通過大致瀏覽DeepLinkToRide的圖。我發現了一些不同的字符串,比如 “pickup”,“[latitude]”,“[longtitude]”,“destination” 等等。IDA 還展顯示了 ”ridetype“,後面經過測試發現這是個 action,通過查看 “ridetype”,我們發現了 “lyft”, “lyft_line”, “lyft_plus”, 和 “access”,這些都是出行方式。

構造這些不同的 URL 部分,然後測試請求。我發現請求一個出行的 scheme 方式如下:

lyft://ridetype

  ?id=lyft_line

  &pickup[latitude]=0

  &pickup[longitude]=0

  &destination[latitude]=0

  &destination[longitude]=0


現在,我明白了 Lyft 是如何工作的了,我可以集成到 Workflow 裏了。這個過程其實就是二進制分析。儘管這些看起來很複雜,但事實上,只要像個開發者一樣思考,其實也那麼的難。

Q&A

Q: 證書綁定(pinning certificates)能否防止中間人攻擊?

Conrad:證書綁定是一個用來防止中間人攻擊的方法,在實踐中確實很有用,前提是你的手機未越獄。比如 Twitter 就在用證書綁定技術。然而,用逆向工具 Cycript 能夠輕鬆破解。 AFNetworking 支持證書綁定,只要設置一下SSLPinningMode這個屬性。然而… 我們可以用 Cycript,再把它修改成none,如果你的 iPhone 越獄了,或者被人控制了。所以,並沒有一種方案能夠徹底防止你的流量被檢測,如果沒有越獄,倒是一種很好的保護方法。

Q: 是否推薦類似 cocoapods-keys 這樣的工具來混淆字符串?

Conrad: 字符串混淆有以下的好處:

- 如果你用蘋果框架裏的私有 API,能很容易的躲避過蘋果審查的自動掃描工具。- 如果那個人並沒有一部越獄的 iPhone,或者它不知道如何解析混淆,他可能很難找到 app 裏的字符串。

然而,你無法永遠的把字符串藏起來。比如,在 Cycript 中,你可以輕易地解開混淆。所以字符串混淆也不是沒法破的保護方案。

Q: class-dump 和 dumpdecryped 的區別是啥?

Conrad: 他們事實上是不同的工具。 dumpecrypted 能將一個 App Store 加密的工具解密。而 class-dump 能將一個解密後得二進制文件去除他的 Objective-C 接口文件,跟 IDA 有點像,不過很遺憾的是:它不支持 Swift。

Q: 導出 Apple framework 的庫,比如: this one ,是不是也是用的 class-dump?

Conrad: 是的,蘋果的框架沒有加密,可以被輕易地導出所有的class。這意味着那些把蘋果的私有interface 放到GitHub上的,你可以輕易地搞定他們。

Q: 逆向工程是否存在法律問題?Lyft 會不會不同意調用他們的私有代碼和 api?

Conrad: 從法律上講,我覺得沒有太多問題。我們通常會跟所有的合作伙伴去聊到我們在做的事情。比如:我剛剛發現的這些東西我都會和 Lyft 討論一下,在他們允許後集成到 Workflow 裏。這些技術其實也有很多道德上的考慮。不過話說回來,這些技術也能阻止開發者們胡亂搞,就比如之前逆向 Twitter 發現他們上傳用戶手機裏裝的 App 列表到他們的服務器上。所以凡事總有兩面,逆向工程只是個工具,善用就好了。

Q: 如何查看蘋果框架的反彙編代碼?

Conrad: 這個的過程跟我之前展示的一個很像,只不過你不再需要一個越獄後的設備。當你把線插到設備上的時候,iTunes 實際上獲取到了設備的符號,你可以在 Xcode 裏找到一個大概叫 “device symbol” 文件夾,在 IDA 或者 class-dump 裏打開 Apple 的 frameworks,然後展開分析。這些都是沒加密的,而且可以直接拿來用。在修復一些 beta 版本的 UIKit 的 bug 的時候很好使。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章