【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);