1. 程式人生 > 其它 >【Android 安全】DEX 加密 ( Application 替換 | 建立使用者自定義 Application | 替換 ContextImpl 物件的 mOuterContext 成員 )

【Android 安全】DEX 加密 ( Application 替換 | 建立使用者自定義 Application | 替換 ContextImpl 物件的 mOuterContext 成員 )

技術標籤:Android 效能優化# Android 安全dex 加密

文章目錄



dex 解密時 , 需要將 代理 Application 替換為 真實 Application ; 替換 Application 首先要理解系統如何註冊應用的 Application 的 ;

上一篇部落格 【Android 安全】DEX 加密 ( Application 替換 | 判定自定義 Application 存在 | 獲取 ContextImpl 物件 ) , 繼續後續步驟 ;





一、建立使用者自定義 Application



獲取 app_name 元資料 , 該元資料就是使用者自定義的 Application 的全型別 , 即 包名.類名 , 這裡是 kim.hsl.dex.MyApplication ;

通過 反射 獲取 Application 類 , 系統也是進行的反射操作 , 並建立使用者真實配置的 Application ;

            // 通過反射獲取 Application , 系統也是進行的反射操作
            Class<?> delegateClass = Class.forName(app_name)
; // 建立使用者真實配置的 Application Application delegate = (Application) delegateClass.newInstance();

呼叫 Application 的 attach 函式 , 該函式無法直接呼叫 , 也需要通過反射呼叫 , 該方法是私有的 , 需要 設定 attach 方法允許訪問 ;

            // 呼叫 Application 的 attach 函式
            // 該函式無法直接呼叫 , 也需要通過反射呼叫
            // 這裡先通過反射獲取 Application 的 attach 函式
Method attach = Application.class.getDeclaredMethod("attach", Context.class); // attach 方法是私有的 , 設定 attach 方法允許訪問 attach.setAccessible(true);

attach 方法需要傳入兩個引數 , Application 物件 Context 物件 ,

該 Context 是通過呼叫 Application 的 attachBaseContext 方法傳入的 ContextImpl , 因此通過呼叫 getBaseContext() 方法即可獲取 Context 物件 ;

將上面 delegateClass.newInstance() 建立的 Application 物件 , 和 getBaseContext() 獲取的 Context 物件 , 傳入 attach 方法中 , 即可建立完整的 Application 物件 ;

            // 獲取上下文物件 ,
            // 該 Context 是通過呼叫 Application 的 attachBaseContext 方法傳入的 ContextImpl
            // 將該上下文物件傳入 Application 的 attach 方法中
            attach.invoke(delegate, baseContext);

本步驟完整程式碼示例 :

            // 獲取上下文物件 , 儲存下來 , 之後要使用
            Context baseContext = getBaseContext();

            // 通過反射獲取 Application , 系統也是進行的反射操作
            Class<?> delegateClass = Class.forName(app_name);

            // 建立使用者真實配置的 Application
            Application delegate = (Application) delegateClass.newInstance();

            // 呼叫 Application 的 attach 函式
            // 該函式無法直接呼叫 , 也需要通過反射呼叫
            // 這裡先通過反射獲取 Application 的 attach 函式
            Method attach = Application.class.getDeclaredMethod("attach", Context.class);
            // attach 方法是私有的 , 設定 attach 方法允許訪問
            attach.setAccessible(true);

            // 獲取上下文物件 ,
            // 該 Context 是通過呼叫 Application 的 attachBaseContext 方法傳入的 ContextImpl
            // 將該上下文物件傳入 Application 的 attach 方法中
            attach.invoke(delegate, baseContext);




二、替換 ContextImpl 物件的 mOuterContext 成員



ContextImpl 的 private Context mOuterContext 成員是 kim.hsl.multipledex.ProxyApplication 物件 , 這是外層的殼 Application , 現在替換成上面建立的使用者自定義的 kim.hsl.dex.MyApplication 物件 ;

首先通過反射獲取 ContextImpl 類 ,

            Class<?> contextImplClass = Class.forName("android.app.ContextImpl");

然後獲取類成員 mOuterContext 欄位 ,

            // 獲取 ContextImpl 中的 mOuterContext 成員
            Field mOuterContextField = contextImplClass.getDeclaredField("mOuterContext");

設定反射中私有成員的可訪問性 ,

            // mOuterContext 成員是私有的 , 設定可訪問性
            mOuterContextField.setAccessible(true);

ContextImpl 就是應用的 Context , 直接通過 getBaseContext() 獲取即可 ,

            // ContextImpl 就是應用的 Context , 直接通過 getBaseContext() 獲取即可
            mOuterContextField.set(baseContext, delegate);

本步驟完整程式碼 :

            // I . 替換 ① ContextImpl 的 private Context mOuterContext
            //  成員是 kim.hsl.multipledex.ProxyApplication 物件
            Class<?> contextImplClass = Class.forName("android.app.ContextImpl");
            // 獲取 ContextImpl 中的 mOuterContext 成員
            Field mOuterContextField = contextImplClass.getDeclaredField("mOuterContext");
            // mOuterContext 成員是私有的 , 設定可訪問性
            mOuterContextField.setAccessible(true);
            // ContextImpl 就是應用的 Context , 直接通過 getBaseContext() 獲取即可
            mOuterContextField.set(baseContext, delegate);