一、Unity主程式
如果將Assembly-CSharp.dll直接反編譯,會發現反編譯的工具會出現檔案識別錯誤(執行檔或DLL開頭2 Bytes 是 0x4D 0x5A),透過16禁制編輯器打開,觀察檔案表頭,就會知道這個DLL被加密了,而且不僅只有表頭(有些反反編譯只會破壞表頭),整個程式都被加密過了,因此需要分析它的解密程式,或者直接從記憶體將解密完的DLL抓下來。
二、反反編譯 (Anti-Debugger)
在遊戲執行前,會透過lib\armeabi-v7a\libmono.so (apk完整路徑)將Assembly-CSharp.dll動態載入到記憶體,因此反反編譯就要在它載入完成前,解密DLL (不解密DLL會崩潰)。
不過我們還需要知道它是用libmono.so的哪個函式加載的,因此需要查找相關開啟檔案的函式。
從函式名稱和參數發現mono_image_open_from_data_with_name,是個不錯的分析的進入點。
原本想要攔截(Hooking) mono_image_open_from_data_with_name函式,並將DLL直接抓下來,不過怎麼執行遊戲都會崩潰,因此將它的記憶體印出來,發現它原來已經被Hooking了。
因此我們需要透過IDA將原來的程式碼交叉比對,發現在函式前12 Bytes被修改了,然而程式會先跳到0x14a63629,然後再返回此函式,我們可以大膽假設0x14a63629,就是解密Assembly-CSharp.dll。
a. 00 f0 9f e5 – arm語法為ldr pc,[pc]
b. 29 36 a6 14 – 是記憶體中的0x14a63629位址
c. 29 36 a6 14 – 跟b一樣 (多覆蓋了4 Bytes,防止其他人覆蓋前8 Bytes)
d. 使用IDA,將正確的語法顯示出來
透過cat /proc/pid/maps查找0x14a63629的解密程式放在哪裡,發現解密完成後,它會刪除解密的程式檔案(這個解密程式也是在運行時才會解密= =),不過並不會影響我們抓取Assembly-CSharp.dll。
三、抓取解密Assembly-CSharp.dll
從上一節的分析經驗,我們不能Hooking前面,那反過來我們可以在mono_image_open_from_data_with_name結束函式前,將它加載的結果(Assembly-CSharp.dll)抓下來,就能達到我們要的目的。
在抓取Assembly-CSharp.dll前,我們要知道它的參數相關資訊,像是mono_image_open_from_data_with_name的傳入第六個參數name,我們可以用來判斷是不是Assembly-CSharp.dll,然後再抓取回傳結果,它的回傳結果是一個結構,結構資訊如下:
1. raw_data – 載入記憶體的內容
2. raw_buffer_len – 載入內容大小
我們耗費不少時間在要如何抓取解密完的Assembly-CSharp.dll,終於來到最後關頭了,我們可以從mono_image_open_from_data_with_name函式返回結果前,Hooking R3 (_MonoImage),就可以得到我們要的結果啦!
最後終於成功反編譯Assembly-CSharp.dll,可以好好的玩弄這隻遊戲程式了,並且分析遊戲的相關資訊和任意修改程式的邏輯。