iOS代碼混淆原理初探

我們在手遊平臺SDK的iOS版本中, 除了AppStore官方支付之外還集成了第三方支付(微信支付H5和支付寶支付H5版本)。 如果用於企業籤,不需要做處理,直接使用即可。 但是如果需要上架AppStore,我們需要屏蔽第三方支付。 這個我們後臺設置開關,直接後臺切換支付方式即可。 上架審覈的時候, 切換爲Appstore支付;審覈通過的時候,切換爲第三方支付。因爲第三方支付,是H5方式,不會被機審檢測到。 同時,防止被抽查,後臺也可以設置,將每次前多少次支付,設置爲AppStore支付,之後用第三方支付,降低被抽查到的風險。

但是隻是做到這個還不夠, 如果需要用這套SDK上多個遊戲,或者多個馬甲包。 防止一樣的代碼被4.3的風險或者被代碼標記的風險,我們需要對SDK的代碼進行混淆, 每次出一個馬甲SDK。
關於iOS代碼的混淆, 查閱了網上很多文章,混淆的原理性文章都是多年之前的了純字符隨機替換,這種按照目前的機審政策,已經很難過審了。另外也有一些混淆工具,不過是按時間收費的。

所以,我們這裏就U8SDK下面的XSDK(手遊平臺SDK)這個項目,來談一談iOS中的代碼混淆。

如果在開發之初, 開發者經驗豐富, 或者運營經驗豐富, 提前將混淆這個事情重視起來, 那麼混淆就會很簡單。 可以事先指定代碼編寫規則,儘量保證類方法變量等的唯一性。 比如所有的類以X開頭,所有的方法函數以F開頭,所有的屬性以P開頭, 所有的內部變量以S開頭等等這樣的規則。 那麼在後續寫混淆的時候,幾行代碼就可以搞定了。

但是我相信多數項目和XSDK一樣,可能都是事後諸葛亮,等到需要做這件事情的時候,才發現代碼命名隨心所欲帶來的代價。 但是,爲了方便混淆來重寫框架是不可能的了,程序也不願意呀。

所以,我們就只能來費些心思來寫混淆腳本了。 我們採用python來寫混淆腳本,用python來幹這個事情,還是很合適的。

首先,我們確定一下混淆目標:

列出了混淆目標, 我們來設計混淆思路了。

一、詞彙替換

混淆,也就是替換, 將老的名稱替換爲新的名稱。 之前網上很多都是使用純隨機字符來替換,但是目前這個方式風險很大,很容易被蘋果檢測出來有隱藏功能的意圖。

所以,我們採用雙詞庫的形式來進行混淆。 我們準備兩套詞庫。 一套是常用的單詞詞庫(詞彙量大概1000個);一套是程序常用單詞詞庫(詞彙量大概100個)。

在生成混淆後的新名稱的時候, 我們根據需要, 從兩套詞庫中隨機單詞,進行拼接。

比如混淆類名稱的時候, 當前有一個類名是AppStorePay。 我們先從常用詞庫中隨機單詞進行拼接,直到長度大於等於AppStorePay長度的時候爲止。 然後再從程序詞庫中隨機一個單詞作爲後綴。 這樣混淆後的名稱可能是OneForTestListener這樣的形式。 看起來就接近了正常的類名命名。

另外混淆的時候, 我們記錄一個已經生成的新的名稱的列表, 如果生成的新名稱已經存在,那麼重新生成。 防止生成的新名稱重複導致問題。

二、混淆思路

混淆的時候, 我們可以逐行混淆, 但是這種方式, 誤差可能會很大。 我們希望執行混淆之後, 一次性編譯通過, 不需要再手動修改某些混淆失敗的地方。 所以我們放棄了逐行混淆的方式。採用一種更加精細化的混淆方式。

另外混淆的方式,我們希望儘可能地符合語法通用的規則,而不簡簡單單地適應XSDK這個項目。 (防止後續我們其他項目也需要做混淆)

首先,我們將代碼目錄下所有的代碼文件加載進來, 於是我們設計一個符合代碼結構的層級:

圖中我們可以看到, 我們首先設計了四個類。

XFolder代表一個代碼目錄;

XClass類代表一個類文件;

XFunction類代表一個類中的一個函數;

XProperty類代表一個類中的一個屬性。

設計好了這個之後,我們就可以調用XFolder中的load方法,加載XFolder對應目錄下的所有class文件,以及所有Class文件中的函數和屬性。

三、混淆實現

將代碼類文件都加載到內存之後, 現在我們就需要對混淆目標中的各個目標的混淆進行實現了。 我們設計一系列混淆實現類,來進行混淆:

1、PCHCodeMixer: 對XSDK.pch文件中定義的全局變量進行混淆,同時對源碼中所有引用的地方進行替換

2、PropertyCodeMixer: 對每個類中定義的屬性進行混淆, 同時對源碼目錄中所有引用的地方進行替換

3、FunctionCodeMixer: 對每個類中定義的函數進行混淆,同時對源碼目錄中所有引用的地方進行替換

4、FunctionCodePostMixer: 對函數內部定義的屬性進行混淆,同時在合適的地方插入垃圾代碼。

5、ClassCodeMixer:對類名稱進行混淆,同時對源碼目錄以及xcode工程文件中所有引用的地方進行替換

6、ResourceMixer:對資源進行混淆, 對所有圖片文件進行md5變更,對所有圖片名稱進行混淆,對所有源碼目錄以及xcode工程文件中所有引用的地方進行替換

7、GlobalNameMixer: 對目錄,對框架名稱,對Bundle名稱等全局名稱進行混淆。 同時對所有文件和xcode工程文件中所有引用的地方進行替換

有了以上這些組件,就可以完成對框架代碼和資源進行混淆和替換。另外還有兩個輔助的mixer類,主要完成對demo工程和文檔內容的替換:

8、DemoMixer: 對demo工程中的引用進行替換。

9、DocMixer:對文檔中對應的引用進行替換。

另外注意下,混淆的時候, 通過正則表達式來解析對應的函數和屬性, 但是因爲iOS的特殊性, 函數中有中括號,而且函數的地方可以無限嵌套。 所以,在對函數進行處理的時候,可以採用棧結構來解析和匹配。
另外解析函數體內容的時候, 我們也是採用棧結構來解析。 也就是先解析出了類中所有的函數名稱, 然後從後往前解析函數體內容。這樣解析也方便很多。 其他地方的混淆,基本用正則表達式就可以完成,只是寫正則的時候或者用正則匹配替換的時候, 儘可能的精細化規則,嚴謹地匹配。替換的時候, 按照被替換串的長度,優先替換長串,再替換短串。

目前XSDK代碼經過混淆工具混淆之後, 無需再手動替換, 直接xcode打開,編譯重新生成XSDK的framework和bundle文件,然後替換到XSDK的Demo工程中的SDK目錄下,然後直接運行XSDK Demo就可以了。

如果提供給研發那邊的話, 只需要將上面替換過的XSDK Demo和文檔提供給研發那邊即可。 經過混淆工具混淆之後, Demo工程和文檔中都會被替換,無需手動替換操作。

 

 

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