1. 程式人生 > >Android中Native ELF的反彙編與破解的一些經驗

Android中Native ELF的反彙編與破解的一些經驗

工具選擇與使用

一般Android執行的HW有:

  • 32Bit的ARM
  • 64Bit的ARM64
  • X86
  • X64

對於Intel/AMD的X86/X64, 可選的工具比較多, 因為ELF執行的Host是Android, 使用靜態反彙編工具Hopper Disassemble與IDA是比較好的選擇.

對於32位ARM的ARM, IDA與Hopper Disassemble都可以完成, 但是對於ARM64就只有Hopper Disassemble了, 當然最新的IDA Pro也可以,但是一般難以獲取得到.

剩下的方式就是用readelf + Android中的Toolchain中的objdump來完成. 

一般情況下, 多種工具需要一起結合使用.

如何快速定位

得到了我們需要反彙編與patch的ELF檔案後, 將其拖入到Disassemble工具中, 就可以看到其Disassemble後的不同Section了, 例如Text, Code段. 那麼要完成patch, 我們需要找到patch的位置. 對此, 個人總結有3種方式來幫助我們快速定位. 

根據字串來快速定位

一般程式執行的時候會有log輸出, 提示是何種錯誤, 例如對於在servicemanager中的add_service, 那麼如果我們的service不在service list中,那麼會提示許可權不足"Permission Denied", 那麼這個字串就是很好的切入點.

在IDA中我們直接使用Search中的Text即可找到.

編譯帶有符號的ELF來輔助定位

對於Android程式碼, 不同板子或者Android裝置的ROM一般都是基於AOSP做的修改, 因此絕大地方的程式碼和AOSP的程式碼是一樣的. 因此我們可以藉助AOSP程式碼來幫助我們定位.

對此第一步是需要獲取Android裝置上面Android的版本, 這個在關於介面, 或者使用getprop, 或者在/system/build.prop中可以獲取tag以及version. 

然後我們就可以根據這些資訊去下載對應版本的AOSP, 然後選擇對應的Arch編譯, 編譯後, 在out目錄中會有一個帶有symbol的可供除錯用的ELF檔案. 這個一般位於:

out/target/product/XXX/symbols/

然後我們可以將這裡面的對應的ELF檔案拖入到IDA Pro或者其他Disassemble工具中進行檢視, 此時因為有Debug 資訊, 反彙編的程式碼與變數等變得很容易被識別, 很容易讓我們定位. 例如下面是對bluedroid stack的反彙編:


圖片1

裡面的變數我們可以都可以找到. 然後使用IDA的pseudo外掛, 可以得到非常好的虛擬碼:


圖片2

而且因為有symbols, 所以我們也就可以知道其位於哪個函式中. 這對我們對應者source code來看instructions, 然後對後面的寫patching tool都很有幫助.

根據立即數來定位

有些程式碼中對某些變數或者引數有臨界值判斷, 這個臨界值一般都是常量const, 或者是立即數. 這個時候, 使用這個立即數來查詢也可以很快幫主我們定位. 例如前面圖片2中的Line49中有一個立即數: 0xC7A. 

這個0xC7A的來源是0xC80-6, 和下面的BTM_BLE_CONN_INT_MAX是匹配的.然後根據ARM中的立即數的表示規則,會發現只能是0xC7A, 即不管任何的Toolchain編譯下得到的arm-v7 的指令集中的這個立即數都是這個值.

  1. stack/include/btm_ble_api.h
  2. 131:#define BTM_BLE_CONN_INT_MAX            0x0C80
  3. 170:#ifndef BTM_BLE_CONN_INT_MAX_DEF
  4. 171:#define BTM_BLE_CONN_INT_MAX_DEF     40/* recommended max: 50 ms = 56 * 1.25 */
  5. bta/include/bta_api.h
  6. 689:#define BTA_DM_BLE_CONN_INT_MAX          BTM_BLE_CONN_INT_MAX

因此我們也還可以使用立即數來查詢:


如何結合原始碼對ELF檔案進行快速破解

對於servicemanager, mediaserver, surfaceflinger等等這些AOSP含有的service, AOSP中含有原始碼, 而一般相同版本的Android,那麼程式碼基本是絕大部分相同的. 

因此, 我們完全可以直接在程式碼中查詢對應的立即數, 字串等有用的資訊, 找到對應的函式, 然後根據相關的程式碼塊來得到對應的instructions. 然後用此在strip過的ELF中查詢.

另外我們還可以根據程式碼的結構來查詢, 例如如果含有switch case, 那麼在IDA Pro中一般也會反彙編有jumptable. 而且使用IDA Pro的虛擬碼生成外掛也可以得到類似的程式碼:


可以看到裡面的case 12下面的Line97 98和source code中對應:


其中裡面的case值為0x12:


如何patching變更

如何替換patched後的檔案

普通檔案直接remount 分割槽,然後cp即可, 但是某些檔案在正常模式無法替換. 可以參考:

製作patching tools

如果是特徵值查詢替換, 那麼patching tools可以直接用C/C++等編寫, 也可以使用現有的框架, 例如:AT4RE Patcher.

直接寫的話, 也可以簡單粗暴的直接fread, 然後memcpy, 然後替換, 然後fwrite即可.

另外patching tools如果使用AT4RE製作, 那麼生成的exe可以在Linux下面藉助Wine執行.

如果使用C/C++編寫, 那麼在Windows下面可以使用msys2來靜態(-static)編譯, 然後只需要拷貝一個msys2的dll即可到處執行, 也相當於只需要寫一次即可在Linux與Windows下面執行.

如何讓自己的Patching tools/破解機適應多個版本的Android

要完成這項任務,我們需要先檢視和跟蹤程式碼在不同版本Android中的變化,這個可以使用git來檢視, 例如servicemanger:


我們可以看到從Android4.4.2到Android 4.4.4_r1幾乎沒有變化, 那麼我們的patching tool就可以適配這些版本. 如果有變化的話, 我們需要更改patching tool中的特徵匹配pattern. 由此來選擇如何search & replace.