Android運行的核心是zygote進程,全部app的進程都是經過zygote fork出來的。經過替換system/bin/下面的app_process等文件,至關於替換了zygote進程,實現了控制手機上的全部APP。基本原理是修改了ART/Davilk虛擬機,將須要hook的函數註冊爲Native層函數,當執行到該函數時,虛擬機會先執行Native層函數,而後執行Java層函數,這樣完成hook。html
更詳細的能夠參考:https://blog.csdn.net/wxyyxc1992/article/details/17320911java
環境:網易mumu、Android Studio3.3.1android
github地址:https://github.com/rovo89/XposedInstallergit
Xposedinstaller的apk:https://repo.xposed.info/module/de.robv.android.xposed.installergithub
在網易mumu中安裝好xposedinstaller apk後,關閉應用兼容性(不關閉的話安裝xposed框架會出錯),進去以後點擊小云彩便可安裝完成。api
新建項目,選擇
empty activity
,建立成功後,在AndroidManifest.xml
中添加以下代碼性能優化
<meta-data android:name="xposedmodule" android:value="true" /> <!--告訴xposed框架這是一個xposed模塊--> <meta-data android:name="xposeddescription" android:value="這是一個Xposed例程" /> <!--模塊描述--> <meta-data android:name="xposedminversion" <!--模塊支持的最低版本--> android:value="30" />
在gradle中配置XposedbridgeApi,build.gradle中配置網絡
repositories { jcenter() } dependencies { ... compileOnly 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82:sources' ... }
這是在網絡通暢的狀況下進行的, 網絡不通暢的話,能夠手動下載XposedBridgeApi-82.jar,拖動到/app/libs中,刪除上述gradle中配置的
jcenter
,右鍵"Add As Library"添加這個jar包。app
在界面上畫個按鈕,並在
MainAcitiviy
中編寫以下代碼(單純寫hook的話前面新建項目的時候能夠add no activity)框架
package com.example.myapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Button; import android.widget.Toast; import android.view.View; public class MainActivity2 extends AppCompatActivity { private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Toast.makeText(MainActivity2.this, toastMessage(), Toast.LENGTH_SHORT).show(); } }); } public String toastMessage() { return "我未被劫持"; } }
編寫Hook代碼,在
MainActivity
同級目錄下新建HookTest.java
,而且繼承接口IXposedHookLoadPackage和重寫handleLoadPackage方法
package com.example.myapplication; import java.lang.reflect.Array; import java.security.PublicKey; import java.util.Arrays; import java.util.Map; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class HookTest implements IXposedHookLoadPackage { private static final String HOOK_APP_NAME = "APP名字"; public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { //性能優化,避免操做無關app if (!lpparam.packageName.equals(HOOK_APP_NAME)) return; if (lpparam.packageName.equals("HOOK_APP_NAME")) { XposedBridge.log(" 劫持成功!!!"); XposedBridge.log("XposedMainInit handleLoadPackage 執行"); XposedBridge.log("Loaded app: " + lpparam.packageName); XposedHelpers.findAndHookMethod("APP名字.MainActivity",//hook的類 lpparam.classLoader, "toastMessage", // 被Hook的函數 //Map.class, 被Hook函數的第一個參數 (此處沒有,只是舉個例子) //String.class, 被Hook函數的第二個參數String new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); // 參數獲取 XposedBridge.log("入口函數執行"); //參數1 XposedBridge.log("beforeHookedMethod map:" + param.args[0]); //參數2 XposedBridge.log("beforeHookedMethod hash_key:" + param.args[1]); //函數返回值 XposedBridge.log("beforeHookedMethod result:" + param.getResult()); } protected void afterHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("afterHookedMethod result:" + param.getResult()); param.setResult("你已被劫持"); } }); } } }
在src/mian目錄下添加一個assets目錄,目錄下添加一個xposed_init文件,裏面的代碼是你的Hook類的包名+類名。
com.example.myapplication.HookTest
最後選擇禁用 Instant Run: 單擊 File -> Settings -> Build, Execution, Deployment -> Instant Run,把勾所有去掉。
這個時候鉤子已經執行了,具體想鉤什麼,就看本身的需求了。
注:實際操做中,須要對APP先進行反編譯(反編譯了才能知道要鉤那個函數),反編譯工具備不少,這裏就不細說了。
直接用反編譯工具打開apk,查看加的是哪一種殼,尋找對應的函數,相似
attachBaseContext
這樣的方法。參考連接:https://www.cnblogs.com/xiaobaiyey/p/6442417.html
public class EncryptHook implements IXposedHookLoadPackage { public void handleLoadPackage(LoadPackageParam loadPackageParam) throws Throwable { if (!loadPackageParam.packageName.equals("app包名")) { return; } XposedBridge.log("Start hook " + loadPackageParam.packageName); XposedHelpers.findAndHookMethod("com.stub.StubApp", loadPackageParam.classLoader, //com.stub.StubApp 加殼的類 "attachBaseContext", Context.class, new XC_MethodHook() { // attachBaseContext 加殼的方法 @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Context context = (Context) param.args[0]; ClassLoader classLoader = context.getClassLoader(); XposedBridge.log("Enter stubApp"); XposedHelpers.findAndHookMethod("com.huijiemanager.utils.t", classLoader, "a", byte[].class, PublicKey.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("rsa before params: " + new String( (byte[]) param.args[0]) + "," + param.args[1]); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { XposedBridge.log("rsa after params: " + new String( (byte[]) param.args[0]) + "," + param.args[1]); } }); } }); } }
注:反編譯的代碼不必定準確,逆向的時候最好對每一個關鍵函數都掛上鉤子,查看參數是否正確。
附上xposedAPI文檔:https://api.xposed.info/reference/packages.html