在學習Android插件化的過程當中有用到Hook相關技術,本篇文章對Hook相關技術作也給簡單的介紹,並寫兩個小Demo,當你瞭解了Hook以後可能會對你之後的碰到問題時多了一個解題思路java
Hook單詞的意思就是鉤子,那咱們在何時用到這個鉤子呢,如上圖所示,在一個事件或者動做執行的過程當中,截獲相關事件或者動做,加入本身的代碼或者替換裝本身的代理對象,這就叫Hookandroid
本文主要是採用java反射機制拿到要執行的對象或者方法就行修改或者替換app
**關注點:**在hook的時候咱們首先須要找到要Hook的對象,什麼樣的對象比較好Hook呢,那就是單例和靜態變量,單例和靜態變量在進程中不容易發生變化,相對容易被定位到,二普通象則比價容易發生變化(隨時有可能被銷燬),。咱們根據這個原則找到所謂的Hook點ide
以上就是我對Hook的理解,且是還挺簡單的,但實踐是檢驗真理的惟一標準,下面我會寫兩個小Demo工具
本例子Hook的是一個工具類學習
/** * 打印機工具類,提供黑白打印和彩色打印 */ public class PrintUtil { private static IPrint colorPrint = new ColorPrint(); //彩色打印機 private static IPrint blackWhitePrint = new BlackWhitePrint(); //黑白打印機 public static void colorPrint(String content){ colorPrint.print(content); } public static void blackWhitePrint(String content){ blackWhitePrint.print(content); } }
工具類如上插件
private void operate4(){ // HookHelper.hookPrint(); PrintUtil.blackWhitePrint("黑白內容"); PrintUtil.colorPrint("彩色內容"); }
正常結果如上 ,下面咱們對PrintUtil進行hook ,首先咱們先找Hook點,在PrintUtil中有兩個靜態變量,這就是咱們要找的Hook點 具體代碼以下線程
/** * 對printUtil進行hook處理 */ public static void hookPrint(){ try { Class<?> printClass = Class.forName("com.example.shiyagang.myapplication.util.PrintUtil"); Field colorPrintField= printClass.getDeclaredField("colorPrint"); Field blackWhitePrintField = printClass.getDeclaredField("blackWhitePrint"); colorPrintField.setAccessible(true); blackWhitePrintField.setAccessible(true); colorPrintField.set(null,new BlackWhitePrint()); blackWhitePrintField.set(null,new ColorPrint()); }catch (Exception e){ e.printStackTrace(); } }
咱們經過反射對PrintUtil的兩個靜態變量進行替換代理
替換完執行結果以下日誌
彩色打印機打出了黑白內容,咱們成功了,嘿嘿
這個例子咱們在context.startActivity的調用鏈,找到相關的hook點進行替換。咱們首先分下context.startActivity的流程,Context.startActivity其實走到了ContextImpl的startActivity
如上圖所示最終調用了ActivityThread類的mInstrumentation成員的execStartActivity方法;注意到,ActivityThread 其實是主線程,而主線程一個進程只有一個,所以這裏是一個良好的Hook點
經過以上步驟咱們就能進行相關hook了
/** * 對activityThread進行Hook * */ public static void attachContext() throws Exception{ // 先獲取到當前的ActivityThread對象 Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread"); currentActivityThreadMethod.setAccessible(true); Object currentActivityThread = currentActivityThreadMethod.invoke(null); // 拿到mInstrumentation 字段 Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation"); mInstrumentationField.setAccessible(true); Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread); // 建立代理對象 Instrumentation evilInstrumentation = new EvilInstrumentation(mInstrumentation); // 偷樑換柱 mInstrumentationField.set(currentActivityThread, evilInstrumentation); }
EvilInstrumentation的代理對象以下:
/** * Instrumentation 的靜態代理類 */ public class EvilInstrumentation extends Instrumentation { private static final String TAG = EvilInstrumentation.class.getSimpleName(); // ActivityThread中原始的對象, 保存起來 Instrumentation mBase; public EvilInstrumentation(Instrumentation base) { mBase = base; } public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { Log.e(TAG, "咱們Hook了 Activity的啓動流程"); try { Method execStartActivity = Instrumentation.class.getDeclaredMethod( "execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class); execStartActivity.setAccessible(true); return (ActivityResult) execStartActivity.invoke(mBase, who, contextThread, token, target, intent, requestCode, options); } catch (Exception e) { throw new RuntimeException("出問題了,去適配吧"); } } }
下面咱們看下Activity的代碼 ,咱們在attachBaseContext中進行Hook
private void operate3(){ Intent intent = new Intent(getApplicationContext(),SecondActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent); } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); try { // 在這裏進行Hook HookHelper.attachContext(); } catch (Exception e) { e.printStackTrace(); } }
入上圖所示咱們已經成功了,咱們在這只是打印了一個日誌,固然你能夠幹任何事情
到此已經對Hook作了簡單的介紹
今年年初我花一個月的時間收錄整理了一套知識體系,若是有想法深刻的系統化的去學習的,能夠點擊傳送門,我會把我收錄整理的資料都送給你們,幫助你們更快的進階。