安卓動態調試七種武器之長生劍 - Smali Instrumentationhtml
做者:蒸米@阿里聚安全java
隨着移動安全愈來愈火,各類調試工具也都層出不窮,但由於環境和需求的不一樣,並無工具是萬能的。另外工具是死的,人是活的,若是能搞懂工具的原理再結合上自身的經驗,你也能夠創造出屬於本身的調試武器。所以,筆者將會在這一系列文章中(共7篇)分享一些本身常常用或原創的調試工具以及手段,但願能對國內移動安全的研究起到一些催化劑的做用。android
長生劍是把神奇的劍,爲白玉京所配,劍名取意來自於李白的詩:「仙人撫我頂,結髮受長生。」長生劍是七種武器系列的第一種武器,而筆者接下來所要介紹的調試方法也是我最先學習的調試方法,而且這種方法就像長生劍同樣,簡單並一直都有很好的效果。這種方法就是Smali Instrumentation,又稱Smali插樁。使用這種方法最大的好處就是不須要對手機進行root,不須要指定android的版本,若是結合一些tricks的話還會有意想不到的效果。git
作安卓逆向最早接觸到的東西確定就是smali語言了,smali最先是由Jasmin提出,隨後jesusfreke開發了最有名的smali和baksmali工具將其發揚光大,幾乎dex上全部的靜態分析工具都是在這個項目的基礎上創建的。什麼?你沒據說過smali和baksmali?你只用過Apktool?若是你仔細閱讀了Apktool官網的說明你就會發現,Apktool其實只是一個將各類工具結合起來的懶人工具而已。而且筆者建議從如今起就拋棄Apktool吧。緣由以下:首先,Apktool更新並無smali/baksmali頻繁,smali/baksmali更新後要過非長久的時間纔會合併到Apktool中,在這以前你可能須要忍受不少詭異的bug。其次,Apktool在反編譯或者重打包dex的時候,若是發生錯誤,僅僅只會提供錯誤的exception信息而已,但若是你使用smali/baksmali,工具會告訴你具體的出錯緣由,會對重打包後的調試有巨大的幫助。最後,不少apk爲了對付反調試會在資源文件中加入不少junk code從而使得Apktool的解析崩潰掉,形成反編譯失敗或者沒法重打包。但若是你僅對classes.dex操做就不會有這些問題了。github
學習smali最好的方法就是本身先用java寫好程序,再用baksmali轉換成smali語句,而後對照學習。好比下面就是java代碼和用baksmali反編譯事後的smali文件的對照分析。數組
MZLog類主要是用Log.d()輸出調試信息,Java代碼以下:安全
對應的smali代碼以下:less
最後簡單介紹一下smali經常使用的數據類型:編輯器
若是僅僅用Smali來分析代碼,效果其實不如用dex2jar和jd-gui更直觀,畢竟看反編譯的java代碼要更容易一些。但Smali強大之處就是能夠爲所欲爲的進行插樁操做。何爲插樁,引用一下wiki的解釋:程序插樁,最先是由J.C. Huang 教授提出的,它是在保證被測程序原有邏輯完整性的基礎上在程序中插入一些探針(又稱爲「探測儀」),經過探針的執行並拋出程序運行的特徵數據,經過對這些數據的分析,能夠得到程序的控制流和數據流信息,進而獲得邏輯覆蓋等動態信息,從而實現測試目的的方法。下面我就來結合一個例子來說解一下何如進行smali插樁。函數
測試程序是一個簡單的crackme (圖1)。輸入密碼,而後點擊check,若是密碼正確會輸出yes,不然輸出no。
圖1 Crackme1的界面
首先咱們對crackme這個apk進行解壓,而後反編譯。咱們會在MainActivity中看到一個getkey(String,int)函數。這個函數貌似很是複雜,咱們暫時無論。咱們首先分析一下點下button後的邏輯。咱們發現程序會經過getkey("mrkxqcroxqtskx",42)來計算出真正的密碼,而後與咱們輸人的密碼進行比較,java代碼以下:
這時候就是smali插樁大顯身手的時候了,咱們能夠經過插樁直接獲取getkey("mrkxqcroxqtskx",42)這個函數的返回值,而後Log出來。這樣咱們就不須要研究getkey這個函數的實現了。具體過程以下:
1 首先解壓apk而後用baksmali進行反編譯。
2 將上一節MZLog類的MZLog.smali文件拷貝到com/mzheng目錄下,這個文件有3個LOG函數,分別能夠輸出String的值,Object的值和Object數組的值。注意,若是原程序中沒有com/mzheng這個目錄,你須要本身用mkdir建立一下。拷貝完後,目錄結構以下:
3 用文本編輯器打開MainActivity$1.smali文件進行插樁。爲何是MainActivity$1.smali而不是MainActivity.smali呢?由於主要的判斷邏輯是在OnClickListener這個類裏,而這個類是MainActivity的一個內部類,同時咱們在實現的時候也沒有給這個類聲明具體的名字,因此這個類用$1表示。加入MZLog.smali這個文件後,咱們只須要在MainActivity$1.smali的第71行後面加上一行代碼,invoke-static {v1}, Lcom/mzheng/MZLog;->Log(Ljava/lang/Object;)V,就能夠輸出getkey的值了。Invoke是方法調用的指令,由於咱們要調用的類是靜態方法,因此使用invoke-static。若是是非靜態方法的話,第一個參數應該是該方法的實例,而後依次是各個參數。具體插入狀況以下:
4 用smali.jar從新編譯修改後的smali文件,把新編譯的classes.dex覆蓋老的classes.dex,而後再用signapk.jar對apk進行簽名。幾條關鍵指令以下:
5 安裝程序到android,隨便輸入點啥,而後點擊check按鈕,隨後在logcat中就能夠看到getkey("mrkxqcroxqtskx",42)這個函數的返回值了(圖2)。
圖2 經過logcat獲取getkey的返回值
經過Smali/baksmali工具,咱們不光能夠插樁,還能夠修改apk的邏輯。幾個須要注意點以下:
1. if條件判斷以及跳轉語句
在smali中最多見的就是if這個條件判斷跳轉語句了,這個判斷一共有12條指令:
好比咱們在crackme1裏判斷密碼是否正確的smali代碼段:
若是咱們不關心密碼內容,只是但願程序輸出」yes」的話。咱們能夠把if-eqz v1, :cond_25改爲if-nez v1, :cond_25。這樣邏輯就變爲:當輸錯密碼的時候,程序反而會輸出」yes」。
2. 寄存器問題
修改Smali時有一件很重要的事情就是要注意寄存器。若是亂用寄存器的話可能會致使程序崩潰。每一個方法開頭聲明瞭registers的數量,這個數量是參數和本地變量總和。參數統一用P表示。若是是非靜態方法p0表明this,p1-pN表明各個參數。若是是靜態方法的話,p0-pN表明各個參數。本地變量統一用v表示。若是想要增長的新的本地變量,須要在方法開頭的registers數量上增長相應的數值。
好比下面這個方法:
由於這不是靜態方法,因此p0表明this。若是想要增長一個新的本地變量,好比v0。就須要把.registers 1改成.registers 2。
3. 給原程序增長大量邏輯的辦法
我很是不建議在程序原有的方法上增長大量邏輯,這樣可能會出現不少寄存器方面的錯誤致使編譯失敗。比較好的方法是:把想要增長的邏輯先用java寫成一個apk,而後把這個apk反編譯成smali文件,隨後把反編譯後的這部分邏輯的smali文件插入到目標程序的smali文件夾中,而後再在原來的方法上採用invoke的方式調用新加入的邏輯。這樣的話無論加入再多的邏輯,也只是修改了原程序的幾行代碼而已。這個思路也是不少重打包病毒慣用的伎倆,確實很是方便好用。
當咱們在實戰中,有時會碰到某些apk在內部實現了本身的簽名檢查。此次咱們介紹的Smali Instrumentation方法由於須要重打包,因此會改變原有的簽名。固然,你能夠經過修改apk把簽名檢查的邏輯刪掉,但這又費時又費力。筆者在這裏簡單介紹兩種很是方便的方法來解決簽名檢查問題。
1. Masterkey
Masterkey漏洞一共有三個,能夠影響android 4.4如下版本。利用這個漏洞,咱們能夠插入新的classes.dex替換掉原有的classes.dex而不須要對apk自己進行從新簽名。若是apk自己有簽名校驗邏輯的話,利用這個漏洞來進行Smali Instrumentation簡直再好不過了。首先,你須要一個android 4.4如下版本的虛擬機或者真機,而後再使用一個masterkey利用工具對apk進行exploit便可。工具下載地址在文章最後,使用的命令以下:
orig.apk是本來的apk文件,moddedClassesDex.zip是修改後的classes.dex並壓縮成zip文件,out.apk就是利用Masterkey漏洞生成的新的apk文件。若是成功的話用rar打開文件會看到兩個classes.dex。
圖3 Masterkey生成的apk文件有兩個classes.dex文件
經過masterkey打包後的apk文件簽名並不會有任何變化,這樣也就不用擔憂簽名校驗問題了。
2. 自定義ROM
簽名的判斷實際上是調用了android系統密碼庫的函數,若是咱們能夠本身定製ROM的話,只須要修改AOSP源碼路徑下的libcore\luni\src\main\java\java\security\MessageDigest.java文件。將isEqual函數中的判斷語句註釋掉:
這樣的話,若是在你自定義的ROM上運行apk,不管你怎麼修改classes.dex文件,都不須要關心簽名問題了,系統會永遠返回簽名正確的。
雖然如今愈來愈多的apk開始使用so文件進行邏輯處理和加固,android 4.4也加入art運行環境,但dalvik永遠是android最經典的東西。若是想要學好android逆向,必定要把這部分知識學好。而且把smali研究透徹之後,會對咱們之後要講的自定義dalvik虛擬機有很大幫助。另外文章中全部提到的代碼和工具均可以在個人github下載到,地址是: https://github.com/zhengmin1989/TheSevenWeapons
Way of the AndroidCracker http://androidcracking.blogspot.hk/p/way-of-android-cracker-lessons.html
Android Master Key Exploit – Uncovering Android Master Key
https://bluebox.com/technical/uncovering-android-master-key-that-makes-99-of-devices-vulnerable/
https://github.com/Fuzion24/AndroidZipArbitrage
Min Zheng, Patrick P. C. Lee, John C. S. Lui. "ADAM: An Automatic and Extensible Platform to Stress Test Android Anti-Virus Systems", DIMVA 2012
做者:蒸米@阿里聚安全,更多安全技術文章,請訪問阿里聚安全博客