Android日常學習:Android Hook技術小實踐
概述
在學習Android外掛化的過程中有用到Hook相關技術,本篇文章對Hook相關技術做也給簡單的介紹,並寫兩個小Demo,當你瞭解了Hook之後可能會對你以後的碰到問題時多了一個解題思路
定義
Hook單詞的意思就是鉤子,那我們在什麼時候用到這個鉤子呢,如上圖所示,在一個事件或者動作執行的過程中,截獲相關事件或者動作,加入自己的程式碼或者替換裝自己的代理物件,這就叫Hook
Hook的原理
本文主要是採用java反射機制拿到要執行的物件或者方法就行修改或者替換
關注點:在hook的時候我們首先需要找到要Hook的物件,什麼樣的物件比較好Hook呢,那就是單例和靜態變數,單例和靜態變數在程式中不容易發生變化, 相對容易被定位到,二普通象則比價容易發生變化(隨時有可能被銷燬),。我們根據這個原則找到所謂的Hook點
以上就是我對Hook的理解,且是還挺簡單的,但實踐是檢驗真理的唯一標準,下面我會寫兩個小Demo
Demo1
本例子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的兩個靜態變數進行替換
替換完執行結果如下
彩色印表機打出了黑白內容,我們成功了,嘿嘿
Demo2
這個例子我們在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();![整合資料.jpg](https://upload-images.jianshu.io/upload_images/3117364-779ed9dc78882285.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) } }
入上圖所示我們已經成功了,我們在這只是列印了一個日誌,當然你可以幹任何事情
總結
到此已經對Hook做了簡單的介紹
- 我們需要先找到Hook點 ,靜態變數和單例比較好Hook
- 植入我們的程式碼,可以採用代理的方式進行植入
- 進行偷樑換柱
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952849/viewspace-2664089/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android so注入(inject)和Hook技術學習(二)——GAndroidHook
- Android hook 技術淺析AndroidHook
- 愛奇藝 Android PLT hook 技術分享AndroidHook
- Android日常學習:OpenGL 實踐之貝塞爾曲線繪製Android
- Android技術棧(四)Android Jetpack MVVM 完全實踐AndroidJetpackMVVM
- Android日常學習:Android檢視動畫-View AnimationAndroid動畫View
- Android AOP學習之:AspectJ實踐Android
- Android 安全研究 hook 神器frida學習(一)AndroidHook
- Android學習之活動的最佳實踐Android
- Android免清單註冊啟動Activity Hook技術AndroidHook
- Android端程式碼染色原理及技術實踐Android
- Android訊息推送技術原理分析和實踐Android
- Android 日常開發總結的技術經驗Android
- Android:Sqlitedatabase學習小結AndroidSQLiteDatabase
- Hook技術之Hook ActivityHook
- 深度學習技術實踐與圖神經網路新技術深度學習神經網路
- android日常開發總結的技術經驗60條Android
- Android 日常開發總結的技術經驗 60 條Android
- 我的Flutter學習與實踐 | 掘金技術徵文Flutter
- Android 底部導航欄 (底部 Tab) 最佳實踐|掘金技術徵文Android
- Android學習之 WebView使用小結AndroidWebView
- 聲網 PK 連麥功能 Android 入門實踐 | 掘金技術徵文Android
- Android技術分享| 【你畫我猜】Android 快速實現Android
- Android技術提升Android
- 深度學習核心技術實踐與圖神經網路新技術應用深度學習神經網路
- Android ItemTouchHelper 實踐Android
- Android Mvp實踐AndroidMVP
- Android MVP 實踐AndroidMVP
- Android學習系列(42)--Android Studio實戰技巧Android
- 音視訊學習 -- 弱網對抗技術相關實踐
- Android學習—— Android佈局Android
- Android持久化技術Android持久化
- 技術面試 android部分面試Android
- Android推送技術研究Android
- Android Emoji 最佳實踐Android
- Android MVP 最佳實踐AndroidMVP
- Android APP 出海實踐AndroidAPP
- Android APK 瘦身實踐AndroidAPK