【逆向安全】- so動態調試之尋找某應用簽名密鑰

背景

公司某同事,想通過python腳本自動調用某應用接口,以達到自己的目的(你懂得)。但是通過抓包發現,幾乎所有接口里面都兩個公共字段"timestamp"和"sign"。timestamp是時間戳很好得到,但是"sign"卻不停在變化,猜測后端會根據"sign"字段值,對數據做校驗。于是開啟了對該App逆向路程。

內容

  • 逆向工具
  • 原生層逆向
  • so逆向
  • so動態調試

逆向工具

  • apktools

    1. apktool d [apk]
      將apk反編譯smali文件形式,通過這種方式,得到的資源文件不會出現亂碼的,并且可以重新編譯成apk,簽名安裝。
    2. apktool b [smali目錄]
      重新生成apk文件,記得要重新簽名,不然安裝不了。
  • dex2jar
    將apk解壓得到的dex文件反編譯成jar文件,方便查看

    1. ./dex2jar/d2j-dex2jar.sh [dex文件]
      生成jar文件
  • jd-gui
    查看jar文件,配合搜索可以方便快速定位代碼位置

  • jadx
    除了可以像jd-gui查看jar文件,還可以對混淆字段重新取名字,更加方便查看,更多功能請自行查看。

  • ida
    查看so文件,so動態調試等功能

原生層逆向

  • dex生成jar文件
    更具前面介紹,接口請求參數里面都會添加"sign"字段,那么我們可以全局搜索"sign",查看跳轉路徑,找到"sign"字段值生成的地方,最終發現native層把接口傳遞參數轉成json字符串后,調用JNI層方法返回一個字符串,這個字符串就是"sign"的值。這下無可奈何了。

  • apk生成smali文件
    為了確定"sign"值就是調用JNI方法生成的,于是我找到了登錄頁面,找到登錄按鈕,通過這里查看調用邏輯。

    1. 如何快速定位到“登錄按鈕”點擊事件處理的地方
      由于點擊事件監聽處,都是10進字的常量值,所有并不知道那個是“登錄按鈕”,而且該apk的資源文件混淆,無法直接找到登錄頁面的布局文件。

      這時,可以借助Android Studio查看apk功能,找到resources.arsc,把10進字轉換成16進字,然后在resources.arsc中找到對應的文件,屬性名。


      截屏2020-12-17 下午3.42.54.png

so逆向

用ida打開so文件,入下圖:


截屏2020-12-17 下午3.47.26.png

該apk調用的是getApiSign這個jni方法,返回的"sign"值。

  • arm轉c
    F5快捷鍵可以將arm指令轉化成可讀的C語言


    截屏2020-12-17 下午4.35.08.png

轉成C語音后,就是這樣,如果能夠看懂,當然可以直接找出計算"sign"值算法,如果看不懂,那么可以使用so動態調試,查看相應的變量值。

注意:這里要用32的ida,64位不支持轉換且動態調試會報錯。

so動態調試

so動態調試,需要root手機一臺。

  • 復制android_server(IDA目錄>dbgsrv>android_server)到設備中

    1. adb push android_server /sdcard
    2. adb shell
    3. mount -o rw,remount /system (出于安全考慮,操作完之后,把文件改回只讀屬性:mount -o ro,remount /system)
    4. mv /sdcard/android_server /system/bin
    5. chmod 777  /system/bin/android_server
    
  • 啟動android_server

    1. su do 切換到root權限(如果不是root權限,后面ida調試找不到應用進程)
    2. ./android_server (root權限下啟動服務 )
    3. 新啟命令行執行:adb forward tcp:23946 tcp:23946建立端口轉發。
    • adb forward --list
      查看端口映射列表
    • adb forward --remove tcp:23946
      移除建立的端口轉發
  • 在手機上運行該apk
    由于其它原因,我把計算"sign"字段的so庫導入我自己新建的android工程,然后寫了一個簡單的點擊事件去調用該jni方法。


    截屏2020-12-17 下午5.01.21.png
  • ida動態調試so
    打開32位ida,點擊"go"打開一個空白頁,選擇要調試的進程。


    截屏2020-12-17 下午5.03.36.png
截屏2020-12-17 下午5.03.49.png
截屏2020-12-17 下午5.04.18.png
  1. 使用Ctrl+S找到需要調試so的基地址:EF606000


    截屏2020-12-17 下午5.07.25.png
  2. 然后通過另外一個IDA打開so文件(可以用64位的打開so),查看函數的相對地址:1794

    截屏2020-12-17 下午5.10.50.png

那么得到了函數的絕對地址就是:EF607794,使用G鍵快速跳轉到這個絕對地址:

截屏2020-12-17 下午5.15.11.png

點擊左邊藍點,下斷點,點擊運行,然后在應用點擊,調用getApiSign JNI方法。


截屏2020-12-17 下午5.20.30.png

觸發getApiSign JNI方法調用后名,程序執行到圖中紅框地方,按F8進行單步調試,F9運行,通過R0寄存器找到算法使用的密鑰。

拿得密鑰后,就可以用其它語言實現。整個破解過程就到這里。

  • 其它配置
    這里是so在調試之前就已經加載,如果要停留在so加載的地方,那么可以打開Debugger setup,配置如下:


    截屏2020-12-17 下午5.26.32.png
  • 使用am命令
    adb am start -D -n com.example.testarm/com.example.testarm.MainActivity
    啟動應用,讓進程處于等待調試中,然后用ida attach進程,進行調試,適用在apk啟動時就加載so并且需要斷點so加載過程。

  • 這里為什么會斷在libc.so中呢
    android系統中libc是c層中最基本的函數庫,libc中封裝了io、文件、socket等基本系統調用。所有上層的調用都需要經過libc封裝層。所以libc.so是最基本的,所以會斷在這里,而且我們還需要知道一些常用的系統so,比如linker

    我們知道,這個linker是用于加載so文件的模塊,所以后面我們在分析如何在.init_array處下斷點

    還有一個就是libdvm.so文件,他包含了DVM中所有的底層加載dex的一些方法,我們在后面動態調試需要dump出加密之后的dex文件,就需要調試這個so文件了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容