Android安全指南 之 Xposed Hook實戰

0.jpg

本篇博文主要是介紹如何使用Xposed 框架Hook應用,使用的案例是OWASP提供的UNCRACKABLE1.apk,目的是經過Xposed Hook 獲取到應用內部的flag字符串。java

1.png

咱們發現UNCRACKABLE1這個應用在啓動時會檢測手機是否被root,當探知到手機出於root狀態時會強制中止運行。那麼首先使用JEB來分析如下示例的代碼邏輯。android


1、JEB 分析apkapi

使用JEB打開apk文件,因爲root檢測是在啓動的時候進行的,所以咱們先來看 onCreate方法:安全

2.png

很明顯MainActivity中的a方法執行了對root的檢測,同時也對調試環境進行檢測,看看a方法的實現:網絡

3.png

知道了檢測在哪一部分,接下來就去找哪裏進行了輸入字符串的檢測。看到MainActivity下的verify方法:架構

4.png

verify方法經過a.a()方法返回的結果判斷輸入字符串的正確性,這就是咱們的目標:app

5.png

分析a.a()的代碼邏輯,咱們可知變量v1中保存的字符串是flag字符串加密後的結果,arg5是咱們傳入的字符串,並且咱們能看到方法並無對arg5進行任何的處理,由此可知校驗的方式是對flag字符串解密後的明文對比,而flag明文就保存在v0_2變量中,解密的方法是sg.vantagepoint.a.a.a。框架


2、Xposed 模塊的安裝ide

Xposed框架的安裝與運行是須要root權限的,前往Xposed官網下載安裝包:http://xposed.appkg.com/nav。安裝包下載完畢後放在設備的sdcard中,運行安裝。安裝完畢後打開Xposed installer:函數

6.png

設備或模擬器取得Root權限後,點擊安裝/更新,等待一段時間後設備會重啓,顯示如下界面則安裝成功。

7.png


3、xposed程序的編寫與運行

從本質上來說,Xposed 模塊也是一個 Android 程序。但與普通程序不一樣的是,想要讓寫出的Android程序成爲一個Xposed 模塊,須要完成幾個工做:

  • 1) 讓手機上的xposed框架知道咱們安裝的這個程序是個xposed模塊。

  • 2) 模塊裏要包含有xposed的API的jar包,以實現下一步的hook操做。

  • 3) 這個模塊裏面要有對目標程序進行hook操做的方法。

  • 4) 要讓手機上的xposed框架知道,咱們編寫的xposed模塊中,哪個方法是實現hook操做的。

針對上面四個任務,咱們分別進行處理:

(1) 新建項目並編輯AndroidManifest.xml:

首先咱們須要建立一個Android項目,這個項目有沒有Activity取決於須要,咱們這個Hook模塊不須要Activity,因此建立一個無Activity項目。

8.png

建立完畢後咱們來修改AndroidManifest.xml文件,來講明這個程序是一個xposed模塊。插入如下代碼:

<meta-data android:name="xposedmodule" android:value="true" /> 
<meta-data android:name="xposeddescription" android:value="xposed for CTF" /> 
<meta-data android:name="xposedminversion" android:value="53" />

9.png

插入以上代碼後,Xposed框架就能將咱們這個android應用識別成一個Xposed模塊了:

10.png

(2) 導入Xposed API

讓Xposed框架識別出咱們編寫的模塊是第一步,要讓這個模塊具備Xposed的功能,咱們須要導入Xposed的API,也就是 XposedBridgeApi.jar 。在Android Studio3.0以上的版本中,只須要在build.gradle中進行配置,Android Studio就會去下載XposedBridgeApi.jar並構建到項目中去。

咱們找到在項目app目錄下面的build.gradle文件,添加上兩段代碼:

repositories { 
    jcenter() 
} 
dependencies { 
    compileOnly 'de.robv.android.xposed:api:82' 
    compileOnly 'de.robv.android.xposed:api:82:sources' 
}

build.gradle文件被修改後,Android Studio會彈出提示,此時咱們點擊sync now,完成同步。Android Studio會自行下載XposedBridgeApi.jar。若是因爲網絡問題XposedBridgeApi.jar沒法下載,則須要從網上手動下載XposedBridgeApi.jar,放到項目的libs目錄下,右鍵 Add As Library添加這個jar包。

(3) 實現Hook操做

導入Xposed API後咱們即可以編寫hook代碼了。在Hook模塊的MainActivity的同一目錄下新建了一個Hook類文件,Hook類實現了IXposedHookLoadPackage:

public class Hook implements IXposedHookLoadPackage { 
    @Override 
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable{ 
        ...... 
    } 
}

具體的模塊編寫咱們放在後面,下面接着看第四個須要完成的工做。

(4) 設置模塊的入口點

咱們編寫完模塊後須要告訴Xposed框架那個類實現了Hook操做。在main文件夾下新建assets文件夾:

11.png

在assets文件夾下建立xposed_init,在文件內寫上Hook類的完整包名:

12.png

以上四步完成後,一個Hook模塊就編寫完畢了,接下來選擇 no Activity啓動,而後運行,在Xposed框架中選中模塊便可:

13.png


4、編寫 xposed 模塊

通過上面的分析,咱們知道須要完成兩個工做才能拿到正確的密碼。一是繞過root與debug檢測,二是hook flag的解密函數。對於環境檢測,咱們的思路是無論它檢測的結果如何,只要不結束程序運行就能夠,所以咱們能夠Hook MainActivity內的a方法,替換它的實現,讓它不執行system.exit(),下面是Xposed模塊。

try{ 
    XposedBridge.log("Hook start"); 
    Class mainActivityClass = loadPackageParam.classLoader
         .loadClass("sg.vantagepoint.uncrackable1.MainActivity"); 
    XposedHelpers.findAndHookMethod(mainActivityClass, "a",java.lang.String.class, 
               new XC_MethodReplacement() { 
        @Override 
        protected Object replaceHookedMethod(XC_MethodReplacement 
               .MethodHookParam param) throws Throwable { 
               return null; 
         } 
    }); 
}catch(Throwable e){ 
    XposedBridge.log(e); 
}

當咱們要修改被Hook方法的邏輯時,經常使用replaceHookedMethod,方法體內部是咱們想要被Hook方法完成的工做,這裏咱們直接讓MainActivity.a(),什麼都不作直接結束執行。跳過檢測後咱們再來Hook解密方法sg.vantagepoint.a.a.a,截取它的返回值並經過log打印:

try{ 
    XposedBridge.log("Hook start"); 
    XposedHelpers.findAndHookMethod("sg.vantagepoint.a.a", loadPackageParam.classLoader, "a", byte[].class, byte [].class, 
new XC_MethodHook() { 
        @Override 
        protected void beforeHookedMethod(MethodHookParam param) 
throws Throwable {} 
        protected void afterHookedMethod(XC_MethodHook 
                .MethodHookParam methodHookParam) throws Throwable { 
                byte[] flag_byte = (byte[]) methodHookParam.getResult(); 
                String flag = new String(flag_byte); 
                XposedBridge.log("Flag: " + flag) 
        } 
    }); 
}catch(Throwable e){ 
    XposedBridge.log(e); 
}

完整的Hook類:

public class Hook implements IXposedHookLoadPackage { 
    @Override 
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) 
        throws Throwable{ 
        if(loadPackageParam.packageName.equals("owasp.mstg.uncrackable1")){ 
            try{ 
                XposedBridge.log("Hook start"); 
                Class mainActivityClass = loadPackageParam.classLoader 
                        .loadClass("sg.vantagepoint.uncrackable1.MainActivity"); 
                XposedHelpers.findAndHookMethod(mainActivityClass, "a", 
                        new XC_MethodReplacement() { 
                    @Override 
                    protected Object replaceHookedMethod(MethodHookParam param) 
                        throws Throwable { 
                        return null; 
                    } 
                }); 
        }catch(Throwable e){ 
            XposedBridge.log(e); 
        } 
        try{ 
            XposedBridge.log("Hook start"); 
            XposedHelpers.findAndHookMethod("sg.vantagepoint.a.a", 
                    loadPackageParam.classLoader, "a", byte [].class, byte [].class, 
                new XC_MethodHook() { 
                @Override 
                protected void beforeHookedMethod(MethodHookParam param) 
                    throws Throwable { 
                } 
                protected void afterHookedMethod(XC_MethodHook 
                    .MethodHookParam methodHookParam) throws Throwable { 
                    byte[] flag_byte = (byte[]) methodHookParam.getResult(); 
                    String flag = new String(flag_byte); 
                    XposedBridge.log("Flag: " + flag);
                } 
        }); 
    }catch (Throwable e){ 
        XposedBridge.log(e); 
    } 
} } 
}


5、獲取flag

編寫完畢後安裝到設備中,在xposed裏面勾選並重啓生效,而後啓動UNCRACKABLE1,隨機輸入一串密碼,而後去看輸出的log:

14.png

咱們能夠看到log中打印出了正確的flag,將flag填入輸入框中,能夠看到這就是正確結果。

15.png


做者簡介:葉紹琛,Unix/Linux/Android操做系統內核技術專家,大中華區前50位RHCA系統架構師,曾任網易互娛雲計算平臺技術負責人。


《Android安全指南》系列文章,未完待續。

相關文章
相關標籤/搜索