這篇文章將為大家詳細講解有關如何進行Android Hook技術的實踐,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
在學習Android插件化的過程中有用到Hook相關技術,下文對Hook相關技術做也給簡單的介紹,并寫兩個小Demo,當你了解了Hook之后可能會對你以后的碰到問題時多了一個解題思路

image.png
Hook單詞的意思就是鉤子,那我們在什么時候用到這個鉤子呢,如上圖所示,在一個事件或者動作執行的過程中,截獲相關事件或者動作,加入自己的代碼或者替換裝自己的代理對象,這就叫Hook
本文主要是采用java反射機制拿到要執行的對象或者方法就行修改或者替換
關注點:在hook的時候我們首先需要找到要Hook的對象,什么樣的對象比較好Hook呢,那就是單例和靜態變量,單例和靜態變量在進程中不容易發生變化,相對容易被定位到,二普通象則比價容易發生變化(隨時有可能被銷毀),。我們根據這個原則找到所謂的Hook點
以上就是我對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("彩色內容");
}
image.png
正常結果如上 ,下面我們對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的兩個靜態變量進行替換
替換完執行結果如下

image.png
彩色打印機打出了黑白內容,我們成功了,嘿嘿
這個例子我們在context.startActivity的調用鏈,找到相關的hook點進行替換。我們首先分下context.startActivity的流程,Context.startActivity其實走到了ContextImpl的startActivity
[圖片上傳中...(image-318cbb-1573653549464-1)]
<figcaption></figcaption>
如上圖所示最終調用了ActivityThread類的mInstrumentation成員的execStartActivity方法;注意到,ActivityThread 實際上是主線程,而主線程一個進程只有一個,因此這里是一個良好的Hook點
我們要拿到ActivityThread的mInstrumentation ,首先得拿到ActivityThread的實例
ActivityThread類里面有一個靜態方法currentActivityThread可以幫助我們拿到ActivityThread的實例
通過以上步驟我們就能進行相關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();
}
}
image.png
入上圖所示我們已經成功了,我們在這只是打印了一個日志,當然你可以干任何事情
關于如何進行Android Hook技術的實踐就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。