1. 程式人生 > >用黑客思維做測試——神器 Xposed 框架介紹

用黑客思維做測試——神器 Xposed 框架介紹

Xposed 框架

Xposed 框架是一款可以在不修改APK的情況下影響程式執行(修改系統)的框架服務,基於它可以製作出許多功能強大的模組,且在功能不衝突的情況下同時運作。

基本原理

Zygote 程序是 Android 的核心,所有的應用程式程序以及系統服務程序都是由Zygote程序 fork 出來的。Xposed Framework 深入到了 Android 核心機制中,通過改造 Zygote 來實現一些很牛逼的功能。Zygote 的啟動配置在/init.rc 指令碼中,由系統啟動的時候開啟此程序,對應的執行檔案是/system/bin/app_process,這個檔案完成類庫載入及一些初始化函式呼叫的工作。

 

當系統中安裝了 Xposed Framework 之後,會拿自己實現的 app_process 覆蓋掉 Android 原生提供的檔案,使得app_process在啟動過程中會載入XposedBridge.jar這個jar包,從而完成對Zygote程序及其建立的Dalvik虛擬機器的劫持。

更詳細的框架介紹和外掛開發過程可直接參看官方教程或者已有的一些中文教程

本文的主要來由是思寒在我另外一篇文章中的一句留言:

把xposed單獨再發文章吧. 這是個殺手級別的框架. 是測試利器. 只是很多人並不懂其中的奧妙

既然是殺手級的東西,那肯定有不少獨到的招式和技能。所以,趁著週末我也思考和整理了一下,基於該框架,測試人員都能做些什麼,目前想到的主要有以下幾點:

  • 滲透測試
  • 測試資料構造
  • 環境監控
  • 動態埋點
  • 熱補丁
  • 自動化錄製

下面就針對以上幾點,結合例子作些簡單的分享(部分原理和過程可能不會做太細緻的解釋,看不懂的可以留言)。

1、滲透測試

以Testerhome的android客戶端認證授權模組為例,這裡使用了OAuth 2.0的授權協議,其中有個比較重要的訪問令牌access_token。通過看原始碼我們可以發現,在TesterUser類中有個setAccess_token方法

    public void setAccess_token(String access_token) {
        this.access_token = access_token
; }

其輸入引數即是使用者授權後產生的訪問令牌,因此我們可以通過以下方法來擷取該令牌

    public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {

        if (!lpparam.packageName.equals("com.testerhome.nativeandroid"))
            return;
        XposedBridge.log("Loaded app: " + lpparam.packageName);
        findAndHookMethod("com.testerhome.nativeandroid.models.TesterUser", lpparam.classLoader,"setAccess_token", String.class,new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called before the clock was updated by the original method
                XposedBridge.log("Enter->beforeHookedMethod");
                XposedBridge.log("original token: " + (String)param.args[0]);
            }
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called after the clock was updated by the original method
            }
    });

執行後檢視日誌如下:

    12-19 06:19:54.458: I/Xposed(11327): Enter->beforeHookedMethod
    12-19 06:19:54.458: I/Xposed(11327): user token: 0a84d0c29a4b576634baacd5097c39b4e36264f440be5b3affba6b1b5b14603e

獲取到令牌後就可以根據互動協議進一步獲取使用者相關的資訊了。

當然,攻擊者也可以直接修改該令牌值。

    param.args[0] = "b6a8d0b02a651a7759051a5c8b1afa02db35636dd4c20c15dcbf050038d7ae2e";

這樣使用者登入後使用的都是非法的令牌值,也就無法獲取合法的資源了。

    findAndHookMethod("com.testerhome.nativeandroid.models.TesterUser",     lpparam.classLoader,"getAccess_token",new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called before the clock was updated by the original method
                XposedBridge.log("Enter->beforeHookedMethod:getAccess_token");
            }
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called after the clock was updated by the original method
                XposedBridge.log("Enter->afterHookedMethod:getAccess_token");
                XposedBridge.log("hooked token: " + (String)param.getResult());
            }
    }); 

日誌列印:

    12-19 10:37:43.590: I/Xposed(15821): Enter->beforeHookedMethod:setAccess_token
    12-19 10:37:43.590: I/Xposed(15821): original token: 9b7c274a07e7dbcdb99840b0aa3dfb3d9c200972c4c5706750c2922650af36a6
    12-19 10:37:43.662: I/Xposed(15821): Enter->beforeHookedMethod:getAccess_token
    12-19 10:37:43.662: I/Xposed(15821): Enter->afterHookedMethod:getAccess_token
    12-19 10:37:43.662: I/Xposed(15821): hooked token: b6a8d0b02a651a7759051a5c8b1afa02db35636dd4c20c15dcbf050038d7ae2e

類似的場景還有很多,主要就是通過閱讀程式碼(有原始碼或者反編譯的情況下),找到關鍵函式以及編碼上的一些漏洞,獲取關鍵資訊或者篡改方法的出入參,達到攻擊和滲透測試的目的。

2、測試資料構造

有時在客戶端應用測試的過程中需要構造一些特殊的資料,如位置、網路制式、系統版本、螢幕長寬比、電量等等。其中,有些資料可手動構造,但有部分就完全不行了。此時,Xposed框架也能幫你搞定。

以系統時間為例,我們編寫一個Demo應用,通過Calendar類來獲取系統的時間:

    Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);
    int hour = c.get(Calendar.HOUR_OF_DAY);
    int minute = c.get(Calendar.MINUTE);
    String time = ""+year+"-"+month+"-"+day+" "+hour+":"+minute;
    timeTV.setText(time);

正常情況下,其執行結果為:


然後,我們只需要Hook系統Calendar類的get方法,就能構造出自己想要的資料:
    findAndHookMethod("java.util.Calendar", lpparam.classLoader,"get",int.class,new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            // this will be called before the clock was updated by the original method
            XposedBridge.log("Enter->beforeHookedMethod:Calendar.get");
        }
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            // this will be called after the clock was updated by the original method
            XposedBridge.log("Enter->afterHookedMethod:Calendar.get");
            param.setResult((int)11);
        }
    });

其執行結果為:

同理,其它類似的資料都能通過Hook系統的方法來構造,甚至連已Root的手機都能偽裝成未Root的(我們公司有個手機打卡軟體,就可以用Root欺騙和位置偽造的方式在家裡打卡,當然我沒這麼幹過,表查我)。

3、環境監控

由於Xposed框架在系統啟動的時候就載入完成了,所以其監控能力比我們自己寫的後臺Service應用要強很多。至於監控的物件,可以是系統的通知、彈窗、Toast資訊、使用者點選、電量、訊號變化這類顯式可感知的事件,也可以是記憶體、CPU、IO此類內部資料,甚至到統一的異常處理方法(如java.lang.Thread.UncaughtExceptionHandler)、底層socket介面、頁面渲染方法等等,主要看你需要什麼,而非它能做什麼。

    public class XposedHook  implements IXposedHookZygoteInit {

    @Override
    public void initZygote(StartupParam startupParam) throws Throwable {
        //設定hook目標類和方法
        XposedHelpers.findAndHookMethod(Toast.class, "show", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                //獲取Toast物件
                Toast t = (Toast) param.thisObject;
                try {
                    //獲取唯一的TextView,即Toast文字
                    View view  = t.getView();
                    List<TextView> list = new ArrayList<TextView>();
                    if (view instanceof TextView) {
                        list.add((TextView) view);
                    } else if (view instanceof ViewGroup) {
                        finaAllTextView(list, (ViewGroup) view);
                    }
                    if (list.size() != 1) {
                        throw new RuntimeException("number of TextViews in toast is not 1");
                    }
                    TextView text = list.get(0);
                   //獲取文字內容
                    CharSequence toastMsg = text.getText();
                    System.out.println("XposedHookToast:"+toastMsg);

                } catch (RuntimeException e) {
                    XposedBridge.log(e);
                }
            }
        });
    }
    //獲取物件中的所有TextView
    private void finaAllTextView(List<TextView> addTo, ViewGroup view) {
        int count = view.getChildCount();
        for (int i = 0; i < count; ++i) {
            View child = view.getChildAt(i);
            if (child instanceof TextView) {
                addTo.add((TextView) child);
            } else if (child instanceof ViewGroup) {
                finaAllTextView(addTo, view);
            }
        }
    }
    }

獲取到的Toast資訊:

    Line 5251: I/System.out(  815): XposedHookToast:登入失敗,可能原因是使用者名稱或密碼錯誤、密碼過期或者帳號鎖定  
    Line 5959: I/System.out(  815): XposedHookToast:連線伺服器失敗  

通過這種方式,可以處理自動化指令碼執行過程中出現的一些非正常事件,如意外彈窗或者訊息欄通知等;也可以用於遮蔽monkey執行時可能點選退出或者登出按鈕的情況。只要事先設定好目標事件和處理方式,它就能起到很好的監控作用。

4、動態埋點

如果監控的目的不是環境處理,而是資訊獲取,那麼就演化為了埋點。既然通過Xposed能直接控制一個方法的呼叫前後階段,那埋點對於它來說更像是一個天賦技能,根本不用多做修改和適配,就能直接在不動被測APP程式碼分毫的情況下實現易管理、有策略並且可實時變更得動態埋點。

以TesterHome客戶端MainActivity中onCreate方法執行前後的系統剩餘記憶體為例:

    findAndHookMethod("com.testerhome.nativeandroid.views.MainActivity", lpparam.classLoader,"onCreate",Bundle.class,new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            // this will be called before the clock was updated by the original method
            XposedBridge.log("Enter->beforeHookedMethod:onCreate");
            Activity app = (Activity) param.thisObject;
            long availMem =getAvailMemory(app);
            XposedBridge.log("availMem before onCreate:"+availMem+"KB");

        }
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            // this will be called after the clock was updated by the original method
            XposedBridge.log("Enter->afterHookedMethod:onCreate");
            Activity app = (Activity) param.thisObject;
            long availMem =getAvailMemory(app);
            XposedBridge.log("availMem after onCreate:"+availMem+"KB");
        }
    });

獲取系統剩餘記憶體的方法:

    public long getAvailMemory(Activity app) {
        ActivityManager am = (ActivityManager)app.getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        am.getMemoryInfo(mi);
        return mi.availMem >> 10;
    }

安裝模組重啟後執行TesterHome可以看到:

    12-19 23:00:48.442: I/Xposed(4476): Enter->beforeHookedMethod:onCreate
    12-19 23:00:48.442: I/Xposed(4476): availMem before onCreate:1901876KB
    12-19 23:00:48.478: I/Xposed(4476): Enter->afterHookedMethod:onCreate
    12-19 23:00:48.478: I/Xposed(4476): availMem after onCreate:1900760KB

具體所需的埋點資料和過程可以參考恆溫的論客戶端埋點

用這種方式埋點有以下幾個好處:

  1. 無需動APP原始碼,適配成本低;
  2. 方式靈活,有能力介入任何過程,可收集的資訊和資料完全;
  3. 易於管理,可隨時新增啟用或刪除棄用埋點;
  4. 無需開發參與,測試可根據場景自己實現埋點方案;

當然,也有個很大的坑點:

  1. 只適合內部測試使用,無法釋出給真實使用者用於線上監控。

5、熱補丁

與動態埋點原理類似,既然我們可以通過新增前後過程來測試一個方法,那麼當發現這個方法出現問題時,自然也可以通過動態的新增前後過程來修復該方法,也即熱補丁。

目前國內安卓上比較成熟的熱補丁方案主要有Dexposed 、 AndFix 、 ClassLoader 三種,前兩個都是阿里的,第三個是騰訊的。其中Dexposed方案正是基於Xposed框架,但由於它只對應用自身程序的方法進行Hook,所以不需要root許可權。

6、自動化指令碼錄製

這個實際上是環境監控的細分能力,既然能監控裝置的所有事件,那麼如果我們有針對性的對系統互動類介面和事件進行監聽,記錄使用者和裝置之間的互動流程和資訊,是不是有可能直接在使用者操作一遍後把對應的自動化指令碼就生成出來呢?

讓我們繼續看個小例子:

被測應用仍為上文獲取時間的Demo,介面上就一個TextView和Button,要做的事就是捕獲按鈕的點選事件,並解析得到該Button的資訊。

為保證通用性和一致性,這裡要Hook的方法肯定得儘量偏底層,通過看原始碼和事件點選分發的相關機制,最終定位到android.view.View類中的performClick方法,這個方法會最終執行點選相關的操作和事件通知。

    public boolean performClick() {
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        ListenerInfo li = mListenerInfo;
        if (li != null && li
            
           

相關推薦

黑客思維測試——神器 Xposed 框架介紹

Xposed 框架 Xposed 框架是一款可以在不修改APK的情況下影響程式執行(修改系統)的框架服務,基於它可以製作出許多功能強大的模組,且在功能不衝突的情況下同時運作。 基本原理 Zygote 程序是 Android 的核心,所有的應用程式程序以及系統服

小米4測試機怎麽樣

andro roi android androi .com and music 測試 hao123 aNDROID%E5%88%9B%E5%BB%BA%E4%B8%8E%E5%88%A0%E9%99%A4%E6%95%B0%E6%8D%AE%E5%BA%93 http:/

為什麼我堅持Go語言Web應用開發框架

點選上方“CSDN”,選擇“置頂公眾號”關鍵時刻,第一時間送達!【CSDN編者按】很多情況下,企

Android 神器 xposed 框架使用指南

1 簡介 xposed號稱Android上最強大的神器,如果你還不知道xposed是啥,那麼你真的out了,本篇部落格,讓博主帶你來了解xposed。 (1) xposed 是啥? xposed是一個框架,上面有很多模組,這些模組都依賴於xposed這個框

Mindjet MindManager 思維導圖軟件-使用思維導圖跟蹤調流程,繪制軟件框架

tail p s detail tracking ack 文件 image strong 100% 思維導圖。據說是每一個產品經理必備的軟件。假設你閱讀大型源碼。使用思維導圖跟蹤調用流程,繪制軟件框架將會很方便。 特點:沒什麽好說的。用過的都說好。

Python十秒表白神器!雖然520已經過去了,但是還有七夕啊!

渴望 exp 特征 輸入 run 現在 separate imagenet pos 520小編也是吃到了一大波狗糧啊,有錢的超級浪漫,沒錢的也很會玩!所以小編今天決定還是教大家來做一款表白神器,就算這次用不著沒下次也是肯定可以用的著的! 今天,我就來教大家一下,如何用

翻頁測試思維邏輯

翻頁 logs 總頁數 blog 測試 按鈕 邏輯 序列 數值 ruily 翻頁功能的測試用例 翻頁功能我們常碰到的一般有以下幾個功能:1、首頁、上一頁、下一頁、尾頁。2、總頁數,當前頁數3、指定跳轉頁4、指定每頁顯示條數當然,有一些是少於多少頁,全部以數字的形式

框架綜合實踐(6)-例執行和測試報告生成

首先,下載BSTestRunner.py用來生成測試報告樣式 下載地址:https://github.com/easonhan007/HTMLTestRunner 下載成功後進行解壓,BSTestRunner.py複製到python安裝目錄的lib資料夾下 執行測試用例

selenium工具軟體自動化測試的面試題及答案

1、selenium中如何判斷元素是否存在? 答:isElementPresent  2、selenium中hidden或者是display = none的元素是否可以定位到? 答:不可以定位到  3、selenium中如何保證操作元素的成功率?也就是說如何保證我點選

JAVA 程式設計師需要到 10 個測試框架和庫

想要提高你的自動化測試技術?以下是 10 個優秀的測試框架和庫,以及它們常見用法的概述。 最近我寫了一些文章,關於 Java 程式設計師今年應該學習什麼,例如程式語言,庫和框架等,如果只能學習或提高其中一項,那必然是自動化測試技能。 測試是專業程式設計師區別於業餘程式設計師的一項指標,作為專業程式設計師,並

在Jenkins上Dr Memory記憶體測試

打算在Jenkins上執行Gtest測試例的記憶體洩漏測試,因為只能拿到dll,所以選擇Dr Memory作為測試工具。這樣只需要exe和dll就可以完成測試。不過最好使用debug版的,否則最後給出的報告只能有模組和偏移地址,無法給出具體的程式碼行號。 1. 開始嘗試了下Dr Memory的Jenkin

Genymotion虛擬機器在Android 6.0下安裝Xposed框架以及Root

最近在研究Xposed框架下的開發,由於之前玩手機的時候裝了一堆模組,導致框架下一堆別的模組產生的Log,而且開機奇慢無比,但Xposed模組更新後必須重啟,測試程式碼時候簡直就是噩夢。因此想用虛擬機器來進行測試,研究了幾個小時,踩了各種坑,總結一下過程分享給大

NUnit為.NET程式測試 ---Nunit入門

最近在學習的過程中感覺到專案測試的重要性,自己在網上學習了一番。感覺還是收穫頗豐的。在此記下,希望也能為像我這樣的程式設計師一點幫助吧。 接下來開始我們的開發和測試。我寫的是一個簡單的計算功能的類。 首先在VS中新建一個類庫。 新增類 Calculate.cs  程

fiddler工具介面測試

介面測試的原理我理解很簡單,是你傳送資料,看返回資料是否正確,返回值型別是否正常,主要點是多種資料的,返回結果正常 和其他應用程式相同,java中需要知道你的引數,欄位有哪些,我們就去給他造資料,而先公司是給的一個請求引數和地址,開始之前先說下介面的一些規範: 1.前端請求

Spring TestContext 帶事務回滾的JUnit測試

JUnit單元測試框架很常用 但可能會破壞資料庫現場 以及大量的硬編碼出現(applicationContext.getBean(""));今天哥們給新手介紹一下 Spring Test這個Spring自帶的jar包中的一些註解 實現單元測試+事務回滾+註解依賴注入 網上的

Xposed框架抓取微信朋友圈資料

因微信朋友圈為私有協議,從抓包上分析朋友圈資料幾乎不可能,目前也尚未找到開源的抓取朋友圈的指令碼。博主於是嘗試通過使用安卓下的Xposed框架實現從微信安卓版上抓取朋友圈資料。 本文針對微信版本6.3.8。GitHub倉庫 主要思路 從UI獲取文字資訊是最為簡單的

Xposed框架攔截Android作業系統的簡訊接收

簡訊接收原理 關於Android作業系統簡訊的接收和傳送流程的文章網上有一大堆,但是真正說得很清楚的不多,這篇blog寫得不錯。其實要想真正弄懂Android作業系統簡訊的流程,還是Linus的那句話: Read the fucking source code

Python之使用unittest框架和HTMLTestRunner.py檔案實現多個測試例執行與測試報告生成

HTMLTestRunner.py檔案下載連結:http://tungwaiyip.info/software/HTMLTestRunner.html 一直想讓使用HTMLTestRunner生成的測試報告可以儲存在指定的檔案目錄下,並以當前執行的時間進行命名,在網上有找

GUI自動化測試中優化測試思維方法

維度 ui自動化 測試執行 模型 數據 不同 指導 業務 函數 1、測試腳本與數據解耦(數據驅動) 讓操作相同但是數據不同的測試可以通過同一 套自動化測試腳本來實現,只是在每次測試執行時提供不同的測試輸入數據。 2、頁面對象模型(POM) 以頁面為單位來封裝頁面上的控

互聯網思維產品的7個要素

互聯網 成功 stat 包含 ogl 高頻 popu 消失 phoenix 互聯網思維應該是一個比較多元性的概念,涉及不同的方面。不同的人使用該概