這篇文章將為大家詳細(xì)講解有關(guān)如何進(jìn)行Android Hook技術(shù)的實(shí)踐,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
創(chuàng)新互聯(lián)是一家專業(yè)提供卓資企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、H5建站、小程序制作等業(yè)務(wù)。10年已為卓資眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設(shè)計(jì)公司優(yōu)惠進(jìn)行中。
在學(xué)習(xí)Android插件化的過(guò)程中有用到Hook相關(guān)技術(shù),下文對(duì)Hook相關(guān)技術(shù)做也給簡(jiǎn)單的介紹,并寫兩個(gè)小Demo,當(dāng)你了解了Hook之后可能會(huì)對(duì)你以后的碰到問(wèn)題時(shí)多了一個(gè)解題思路

image.png
Hook單詞的意思就是鉤子,那我們?cè)谑裁磿r(shí)候用到這個(gè)鉤子呢,如上圖所示,在一個(gè)事件或者動(dòng)作執(zhí)行的過(guò)程中,截獲相關(guān)事件或者動(dòng)作,加入自己的代碼或者替換裝自己的代理對(duì)象,這就叫Hook
本文主要是采用java反射機(jī)制拿到要執(zhí)行的對(duì)象或者方法就行修改或者替換
關(guān)注點(diǎn):在hook的時(shí)候我們首先需要找到要Hook的對(duì)象,什么樣的對(duì)象比較好Hook呢,那就是單例和靜態(tài)變量,單例和靜態(tài)變量在進(jìn)程中不容易發(fā)生變化,相對(duì)容易被定位到,二普通象則比價(jià)容易發(fā)生變化(隨時(shí)有可能被銷毀),。我們根據(jù)這個(gè)原則找到所謂的Hook點(diǎn)
以上就是我對(duì)Hook的理解,且是還挺簡(jiǎn)單的,但實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),下面我會(huì)寫兩個(gè)小Demo
本例子Hook的是一個(gè)工具類
/**
* 打印機(jī)工具類,提供黑白打印和彩色打印
*/public class PrintUtil {
private static IPrint colorPrint = new ColorPrint(); //彩色打印機(jī)
private static IPrint blackWhitePrint = new BlackWhitePrint(); //黑白打印機(jī)
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("黑白內(nèi)容");
PrintUtil.colorPrint("彩色內(nèi)容");
}
image.png
正常結(jié)果如上 ,下面我們對(duì)PrintUtil進(jìn)行hook ,首先我們先找Hook點(diǎn),在PrintUtil中有兩個(gè)靜態(tài)變量,這就是我們要找的Hook點(diǎn) 具體代碼如下
/**
* 對(duì)printUtil進(jìn)行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();
}
}我們通過(guò)反射對(duì)PrintUtil的兩個(gè)靜態(tài)變量進(jìn)行替換
替換完執(zhí)行結(jié)果如下

image.png
彩色打印機(jī)打出了黑白內(nèi)容,我們成功了,嘿嘿
這個(gè)例子我們?cè)赾ontext.startActivity的調(diào)用鏈,找到相關(guān)的hook點(diǎn)進(jìn)行替換。我們首先分下context.startActivity的流程,Context.startActivity其實(shí)走到了ContextImpl的startActivity
[圖片上傳中...(image-318cbb-1573653549464-1)]
<figcaption></figcaption>
如上圖所示最終調(diào)用了ActivityThread類的mInstrumentation成員的execStartActivity方法;注意到,ActivityThread 實(shí)際上是主線程,而主線程一個(gè)進(jìn)程只有一個(gè),因此這里是一個(gè)良好的Hook點(diǎn)
我們要拿到ActivityThread的mInstrumentation ,首先得拿到ActivityThread的實(shí)例
ActivityThread類里面有一個(gè)靜態(tài)方法currentActivityThread可以幫助我們拿到ActivityThread的實(shí)例
通過(guò)以上步驟我們就能進(jìn)行相關(guān)hook了
/**
* 對(duì)activityThread進(jìn)行Hook
*
*/
public static void attachContext() throws Exception{ // 先獲取到當(dāng)前的ActivityThread對(duì)象
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); // 創(chuàng)建代理對(duì)象
Instrumentation evilInstrumentation = new EvilInstrumentation(mInstrumentation); // 偷梁換柱
mInstrumentationField.set(currentActivityThread, evilInstrumentation);
}EvilInstrumentation的代理對(duì)象如下:
/**
* Instrumentation 的靜態(tài)代理類
*/public class EvilInstrumentation extends Instrumentation { private static final String TAG = EvilInstrumentation.class.getSimpleName(); // ActivityThread中原始的對(duì)象, 保存起來(lái)
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的啟動(dòng)流程"); 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("出問(wèn)題了,去適配吧");
}
}
}下面我們看下Activity的代碼 ,我們?cè)赼ttachBaseContext中進(jìn)行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 { // 在這里進(jìn)行Hook
HookHelper.attachContext();
} catch (Exception e) {
e.printStackTrace();
}
}
image.png
入上圖所示我們已經(jīng)成功了,我們?cè)谶@只是打印了一個(gè)日志,當(dāng)然你可以干任何事情
關(guān)于如何進(jìn)行Android Hook技術(shù)的實(shí)踐就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
新聞標(biāo)題:如何進(jìn)行AndroidHook技術(shù)的實(shí)踐
瀏覽地址:http://chinadenli.net/article24/gesjje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、營(yíng)銷型網(wǎng)站建設(shè)、電子商務(wù)、微信小程序、Google、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)