Hook,英文直譯是”鉤子“的意思。在程序中將其理解為”劫持“可能會更好理解,我們可以通過hook技術來劫持某個對象,從而控制它與其他對象的交互。
創建一個代理對象,然后把原始對象替換為我們的代理對象,這樣就可以在這個代理對象為所欲為,修改參數或替換返回值。
正常的調用和返回:
Hook的調用和返回:
Hook的過程
Step1. 尋找Hook點,原則是
靜態變量
或者單例對象
,盡量Hookpublic
的對象和方法,非public不保證每個版本都一樣,需要適配。Step2. 選擇合適的代理方式,如果是接口
可以用動態代理
;如果是類可以用靜態代理
。Step3. 偷梁換柱——用代理對象替換原始對象。
尋找Hook點:
Activity的startActivity方法的調用鏈:
// android/app/Activity.java// Step1@Overridepublic void startActivity(Intent intent) { this.startActivity(intent, null);}// Step2@Overridepublic void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { startActivityForResult(intent, -1); }}// Step3public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { options = transferSpringboardActivityOptions(options); // Hook點 Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } if (requestCode >= 0) { mStartedActivity = true; } cancelInputsAndStartExitTransition(options); } else { if (options != null) { mParent.startActivityFromChild(this, intent, requestCode, options); } else { mParent.startActivityFromChild(this, intent, requestCode); } }}
Hook點分析:
當調用Activity的startActivity方法時,最后會調用 mInstrumentation
的execStartActivity方法來完成Activity的開啟,而 mInstrumentation
是Activity的成員變量,所以是一個很好的Hook點,用代理Instrumentation來替代原始的Instrumentation完成Hook。
Hook代碼:
代理類:InstrumentationProxy.java
/** * 1. InstrumentationProxy繼承Instrumentation * 2. InstrumentationProxy持有Instrumentation實例的引用 * 3. 實現execStartActivity方法,并在內部通過反射調用Instrumentation的execStartActivity方法 */public class InstrumentationProxy extends Instrumentation { private static final String TAG = "InstrumentationProxy"; private Instrumentation的 mInstrumentation; public InstrumentationProxy(Instrumentation instrumentation) { mInstrumentation = instrumentation; } public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { Log.i(TAG, "Hook成功" + "--who:" + who); try { Method execStartActivityMethod = Instrumentation.class.getDeclaredMethod("execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class); return (ActivityResult) execStartActivityMethod.invoke(mInstrumentation, who, contextThread, token, target, intent, requestCode, options); } catch (Exception e) { throw new RuntimeException(e); } }}
用InstrumentationProxy來替換Instrumentation:
public class HookHelper { public static void hookActivityInstrumentation(Activity activity) { try { // 得到Activity的mInstrumentation字段 Field field = Activity.class.getDeclaredField("mInstrumentation"); field.setAccessible(true); // 得到Activity中的Instrumentation對象 Instrumentation instrumentation = (Instrumentation) field.get(activity); // 創建InstrumentationProxy對象來代理Instrumentation對象 InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation); // 用代理去替換Activity中的Instrumentation對象 field.set(activity, instrumentationProxy); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }}
執行Hook:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Hook HookHelper.hookActivityInstrumentation(this); Intent intent = new Intent(this, DetailActivity.class); startActivity(intent); }}
運行結果:
I/InstrumentationProxy: Hook成功--who:com.github.xch168.hooktest.MainActivity@bd3e1b1
Context的實現類為ContextImpl。
尋找Hook點:
ContextImpl中startActivity的調用鏈:
// Step1@Overridepublic void startActivity(Intent intent) { warnIfCallingFromSystemProcess(); startActivity(intent, null);}// Step2@Overridepublic void startActivity(Intent intent, Bundle options) { warnIfCallingFromSystemProcess(); final int targetSdkVersion = getApplicationInfo().targetSdkVersion; if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && (targetSdkVersion < Build.VERSION_CODES.N || targetSdkVersion >= Build.VERSION_CODES.P) && (options == null || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) { throw new AndroidRuntimeException( "Calling startActivity() from outside of an Activity " + " context requires the FLAG_ACTIVITY_NEW_TASK flag." + " Is this really what you want?"); } // Hook點 mMainThread.getInstrumentation().execStartActivity(getOuterContext(), mMainThread.getApplicationThread(), null, (Activity) null, intent, -1, options);}
Hook點分析:
Hook代碼:
public class HookHelper { public static void hookContextInstrumentation() { try { // 獲取ActivityThread類 Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); // 獲取ActivityThread類中的靜態變量sCurrentActivityThread Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread"); currentActivityThreadField.setAccessible(true); // 獲取sCurrentActivityThread字段的值,即ActivityThread的對象 Object currentActivityThread = currentActivityThreadField.get(null); // 獲取ActivityThread的mInstrumentation字段 Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation"); mInstrumentationField.setAccessible(true); // 獲取mInstrumentation對象 Instrumentation instrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread); // 創建Instrumentation的代理對象 InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation); // 用InstrumentationProxy替換ActivityThread中的Instrumentation mInstrumentationField.set(currentActivityThread, instrumentationProxy); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }}
執行Hook:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Hook HookHelper.hookContextInstrumentation(); Intent intent = new Intent(this, DetailActivity.class); getApplicationContext().startActivity(intent); }}
運行結果:
I/InstrumentationProxy: Hook成功--who:android.app.Application@7e13696
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
sony油壺和香水瓶哪個好?香水瓶不錯。索尼-KW1神器采用香水瓶的設計風格,并有白色、粉色、紫色和綠色,以及四種珠光顏色可供選擇。鏡頭的設計融入了施華洛世奇元素,高貴典雅,采用透明保護殼,可以起到一定的保護作用。也更像是香水瓶的蓋子,設計簡潔時尚。這款神器整體設計小巧,僅重120g,攜帶方便。索尼香水瓶和魚雷哪個高端?索尼香水瓶和索尼魚雷都是mp3產品。如果看價格,魚雷更高檔。索尼的香水瓶配什么...
ig和dwg和fpx都是lpl戰隊嘛?ig和dwg和fpx三支戰隊不都是lpl戰隊。其中的ig戰隊和fpx戰隊是中國的lpl聯賽的戰隊,而dwg戰隊是韓國lck聯賽的戰隊。ig戰隊和fpx戰隊分別是由中國的富豪王思聰出資建立和滔博體育出資建立的中國賽區戰隊,而dwg戰隊是韓國的啟亞集團出資贊助的戰隊,他們并不是一個賽區的戰隊。fpx改名了嗎?fpx戰隊沒有改名,fpx戰隊在2017年收購了nb戰隊...
成都工商銀行什么地方可以辦理ETC?以下是四川etc工商銀行的辦理點:工商銀行成都江西街支行四川省成都市江西街1號工商銀行成都濱江支行棲霞路支行四川省成都市武侯區棲霞路1號工商銀行股份有限公司成都武侯科技園支行四川省成都市武侯區武侯科技園吳克東二路11號工商銀行股份有限公司成都瑞興路支行四川省成都市青羊區瑞興路99號工商銀行股份有限公司成都草市支行舒慧路支行四川省成都市青羊區清江西路380號、38...