原創文章,轉載請標明出處(https://www.cnblogs.com/boycelee/p/13418371.html)
HOOK工具原理系列之Xposed
安卓系統啟動什么zygote?安卓應用運行?Xposed介紹Xposed構成Xposed初始化大體工作流程源碼分析初始化app_main#mainapp_main#initializeframeworks.base.core.jni.AndroidRuntime#startXposed.cpp#onVmCreatedlibxposed_art.cpp#xposedInitLiblibxposed_common.cpp#onVmCreatedCommonlibxposed_common.cpp#initXposedBridgelibxposed_art.cpp#onVmCreatedde.robv.android.xposed.XposedBridge#main例子Hook原理分析XposedBridge#findAndHookMethodXposedBridge#hookMethodlibxposed.cpp#hookMethodNativeEnableXposedHookartQuickProxyInvokeHandlerInvokeXposedHandleHookedMethodInvokeXposedHandleHookedMethodXposed.java#handleHookedMethodART函數調用原理總結參考
安卓系統啟動
什么zygote?
init是內核啟動的第一個用戶級進程,zygote是由init進程通過解析init.zygote.rc文件而創建的,zygote所對應的具體可執行程序是app_process,所對應的源文件是App_main.cpp,進程名稱為zygote。
init.zygote.rc:
1service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
2 class main
3 socket zygote stream 660 root system
4 onrestart write /sys/android_power/request_state wake
5 onrestart write /sys/power/state on
6 onrestart restart media
7 onrestart restart netd
8 writepid /dev/cpuset/foreground/tasks
安卓應用運行?
在ART模式下,zygote被init進程創建出來,用來孵化和啟動其他App。zygote進程具有App所需要的所有核心庫。

新的App進程在生成后,就會加載本App的程序代碼(apk中的dex文件)
Xposed介紹
Xposed是安卓系統上能夠修改系統或三方應用信息的框架。

Xposed構成
名稱 | 介紹 |
---|---|
Xposed | Xposed框架Native部分 |
XposedBridge | Xposed向開發者提供的API與相應工具類庫 |
XposedInstaller | Xposed框架Android端本地管理,環境框架,以及第三方module資源下載的工具 |
Xposed初始化大體工作流程
(1)xposed的主要接口在XposedBrigde.jar中,核心功能在替換的虛擬機中實現。
(2)app_process是Android App的啟動程序(具體形式是zygote fork() 調用app_process作為Android app的載體)。

源碼分析
初始化
app_process有兩個對應源文件,Android.mk會在編譯時根據sdk版本選擇對應源文件作為入口(app_main.cpp或app_main2.cpp)
1...
2
3ifeq (1,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>= 21)))
4 LOCAL_SRC_FILES := app_main2.cpp
5 LOCAL_MULTILIB := both
6 LOCAL_MODULE_STEM_32 := app_process32_xposed
7 LOCAL_MODULE_STEM_64 := app_process64_xposed
8else
9 LOCAL_SRC_FILES := app_main.cpp
10 LOCAL_MODULE_STEM := app_process_xposed
11endif
12...
13ifeq (1,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>= 21)))
14 include frameworks/base/cmds/xposed/ART.mk
15else
16 include frameworks/base/cmds/xposed/Dalvik.mk
17endif
app_main#main
在系統開機時,會通過app_process去創建zygote虛擬機,就會調用到app_main2.cpp中的main函數。
main函數中主要做兩件事:(1)初始化xposed;(2)創建虛擬機
1int main(int argc, char* const argv[])
2{
3 if (xposed::handleOptions(argc, argv))
4 return 0;
5
6 //代碼省略...
7
8 runtime.mParentDir = parentDir;
9 // 初始化xposed,主要是將jar包添加至Classpath中
10 isXposedLoaded = xposed::initialize(zygote, startSystemServer, className, argc, argv);
11 if (zygote) {
12 // 如果xposed初始化成功,將zygoteInit 替換為 de.robv.android.xposed.XposedBridge,然后創建虛擬機
13 runtime.start(isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : "com.android.internal.os.ZygoteInit",
14 startSystemServer ? "start-system-server" : "");
15 }
16 ...
17}
app_main#initialize
初始化xposed
(1)初始化xposed內相關變量
(2)調用addJarToClasspath將XposedBridge.jar添加至系統目錄。
1bool initialize(bool zygote, bool startSystemServer, const char* className, int argc, char* const argv[]) {
2 ...
3 // 初始化xposed的相關變量
4 xposed->zygote = zygote;
5 xposed->startSystemServer = startSystemServer;
6 xposed->startClassName = className;
7 xposed->xposedVersionInt = xposedVersionInt;
8 ...
9 // 打印 release、sdk、manufacturer、model、rom、fingerprint、platform相關數據
10 printRomInfo();
11
12 // 主要在於將jar包加入Classpath
13 return addJarToClasspath();
14}
frameworks.base.core.jni.AndroidRuntime#start
創建對應虛擬機
start做了4件事:
(1)創建虛擬機
(2)初始化虛擬機
(3)傳入調用類de.robv.android.xposed.XposedBridge
(4)初始化XposedBridge
1/*
2 * Start the Android runtime. This involves starting the virtual machine
3 * and calling the "static void main(String[] args)" method in the class
4 * named by "className".
5 *
6 * Passes the main function two arguments, the class name and the specified
7 * options string.
8 */
9void AndroidRuntime::start(const char* className, const Vector<String8>& options)
10{
11 /* start the virtual machine */
12 JniInvocation jni_invocation;
13 jni_invocation.Init(NULL);
14 JNIEnv* env;
15 //創建虛擬機
16 if (startVm(&mJavaVM, &env) != 0) {
17 return;
18 }
19
20 // 初始化虛擬機,xposed對虛擬機進行修改
21 onVmCreated(env);
22
23 // 虛擬機初始化完成后,會調用傳入的de.robv.android.xposed.XposedBridge類,初始化java層XposedBridge.jar
24 char* slashClassName = toSlashClassName(className);
25 jclass startClass = env->FindClass(slashClassName);
26 if (startClass == NULL) {
27 ...
28 } else {
29
30 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
31 ...
32 }
33}
Xposed.cpp#onVmCreated
xposed重寫了onVmCreated。
onVmCreated做了什么:
1、xposedInitLib->onVmCreatedCommon->initXposedBridge,初始化XposedBridge
(1)將register_natives_XposedBridge中的函數注冊為Native方法
2、xposedInitLib->onVmCreatedCommon->onVmCreated,為xposed_callback_class與xposed_callback_method賦值;
(1)xposed_callback_class和xposed_callback_method變量賦值
3、 de.robv.android.xposed.XposedBridge#main,初始化java層XposedBridge.jar
(1)hook 住系統資源相關的方法;
(2)hook 住zygote 的相關方法;
(3)加載系統中已經安裝的xposed 模塊。
1void onVmCreated(JNIEnv* env) {
2 // Determine the currently active runtime
3 ...
4
5 // Load the suitable libxposed_*.so for it 通過dlopen加載libxposed_art.so
6 void* xposedLibHandle = dlopen(xposedLibPath, RTLD_NOW);
7 ...
8
9 // Initialize the library 初始化xposed相關庫
10 bool (*xposedInitLib)(XposedShared* shared) = NULL;
11 // 根據動態鏈接庫操作句柄與符號,返回符號對應的地址
12 *(void **) (&xposedInitLib) = dlsym(xposedLibHandle, "xposedInitLib");
13 if (!xposedInitLib) {
14 ALOGE("Could not find function xposedInitLib");
15 return;
16 }
17 ...
18 // xposedInitLib -> onVmCreatedCommon -> initXposedBridge -> 注冊Xposed相關Native方法
19 if (xposedInitLib(xposed)) {
20 xposed->onVmCreated(env);
21 }
22}
libxposed_art.cpp#xposedInitLib
1/** Called by Xposed's app_process replacement. */
2bool xposedInitLib(XposedShared* shared) {
3 xposed = shared;
4 xposed->onVmCreated = &onVmCreatedCommon;
5 return true;
6}
libxposed_common.cpp#onVmCreatedCommon
1void onVmCreatedCommon(JNIEnv* env) {
2 if (!initXposedBridge(env) || !initZygoteService(env)) {
3 return;
4 }
5
6 if (!onVmCreated(env)) {
7 return;
8 }
9
10 xposedLoadedSuccessfully = true;
11 return;
12}
libxposed_common.cpp#initXposedBridge
1bool initXposedBridge(JNIEnv* env) {
2 classXposedBridge = env->FindClass(CLASS_XPOSED_BRIDGE);
3 ...
4 classXposedBridge = reinterpret_cast<jclass>(env->NewGlobalRef(classXposedBridge));
5 ALOGI("Found Xposed class '%s', now initializing", CLASS_XPOSED_BRIDGE);
6 // 將register_natives_XposedBridge中的函數注冊為Native方法
7 if (register_natives_XposedBridge(env, classXposedBridge) != JNI_OK) {
8 ALOGE("Could not register natives for '%s'", CLASS_XPOSED_BRIDGE);
9 logExceptionStackTrace();
10 env->ExceptionClear();
11 return false;
12 }
13
14 // 獲取XposedBridge.jar中的handleHookedMethod方法,並將該方法賦值給methodXposedBridgeHandleHookedMethod,后續會賦值至全局變量中
15 methodXposedBridgeHandleHookedMethod = env->GetStaticMethodID(classXposedBridge, "handleHookedMethod",
16 "(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
17 ...
18 return true;
19}
libxposed_art.cpp#onVmCreated
1/** Called very early during VM startup. */
2bool onVmCreated(JNIEnv*) {
3 // TODO: Handle CLASS_MIUI_RESOURCES?
4 ArtMethod::xposed_callback_class = classXposedBridge;
5 ArtMethod::xposed_callback_method = methodXposedBridgeHandleHookedMethod;
6 return true;
7}
de.robv.android.xposed.XposedBridge#main
虛擬機初始化完成后,會調用傳入的de.robv.android.xposed.XposedBridge類,初始化java層XposedBridge.jar,調用main函數
(1)hook 系統資源相關的方法;
(2)hook zygote 的相關方法;
(3)加載系統中已經安裝的xposed 模塊。
1protected static void main(String[] args) {
2 // Initialize the Xposed framework and modules
3 try {
4 if (!hadInitErrors()) {
5 initXResources();
6
7 SELinuxHelper.initOnce();
8 SELinuxHelper.initForProcess(null);
9
10 runtime = getRuntime();
11 XPOSED_BRIDGE_VERSION = getXposedVersion();
12
13 if (isZygote) {
14 XposedInit.hookResources();
15 XposedInit.initForZygote();
16 }
17
18 XposedInit.loadModules();
19 } else {
20 Log.e(TAG, "Not initializing Xposed because of previous errors");
21 }
22 }
23
24 // Call the original startup code
25 if (isZygote) {
26 ZygoteInit.main(args);
27 } else {
28 RuntimeInit.main(args);
29 }
30 }
初始化結束。
例子
1static final String TAG = "XposedTest001";
2 //final XC_MethodReplacement replacementTrue = XC_MethodReplacement.returnConstant(true);
3
4 public CheckSNHook(ClassLoader cl) {
5 super();
6
7 XposedBridge.log("hooking checkSN.");
8 try {
9 Class clz = (Class<?>) XposedHelpers.findClass("com.droider.crackme0201.MainActivity", cl);
10 //XposedBridge.hookAllMethods(clz, "checkSN", replacementTrue);
11 Log.d(TAG, "hooking clz");
12 XposedHelpers.findAndHookMethod(clz,
13 "checkSN",
14 String.class, String.class,
15 new XC_MethodHook() {
16
17 @Override
18 protected void afterHookedMethod(MethodHookParam param)
19 throws Throwable {
20 XposedBridge.log("1CheckSN afterHookedMethod called.");
21 String s1 = (String) param.args[0];
22 String s2 = (String) param.args[1];
23
24 Log.d(TAG, "s1:" + s1);
25 Log.d(TAG, "s2:" + s2);
26 param.setResult(true);
27
28 super.afterHookedMethod(param);
29 }
30 });
31
32 } catch (Exception e) {
33 e.printStackTrace();
34 }
35 XposedBridge.log("1hook checkSN done.");
36 }
Hook原理分析
XposedBridge#findAndHookMethod
1、根據函數名獲取對應Method對象
2、調用XposedBridge.hookMethod函數
1public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
2 if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-1] instanceof XC_MethodHook))
3 throw new IllegalArgumentException("no callback defined");
4 // 封裝回調函數
5 XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-1];
6 // 主要函數Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
7 Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));
8 // 核心函數
9 return XposedBridge.hookMethod(m, callback);
10 }
XposedBridge#hookMethod
1、將回調函數、參數類型、返回類型記錄到AdditionalHookInfo中
2、攔截指定函數調用,並使用其他函數替代(native函數)
1public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
2 ...
3 // 將回調函數、參數類型、返回類型記錄到AdditionalHookInfo中
4 AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType);
5 // 攔截指定函數調用,並使用其他函數替代
6 hookMethodNative(hookMethod, declaringClass, slot, additionalInfo);
7 }
8
9 return callback.new Unhook(hookMethod);
10 }
11
12private native synchronized static void hookMethodNative(Member method, Class<?> declaringClass, int slot, Object additionalInfo);
libxposed.cpp#hookMethodNative
1、查找我們需要hook的java Method對應的ArtMethod (每一個java層函數在ART下都有一個對應的ArtMethod)
1void XposedBridge_hookMethodNative(JNIEnv* env, jclass, jobject javaReflectedMethod,
2 jobject, jint, jobject javaAdditionalInfo) {
3 ...
4
5 // 獲取Java層Method對應native層的ArtMethod指針,將java函數描述為ArtMethod,查找我們需要hook的java Method對應的ArtMethod
6 ArtMethod* artMethod = ArtMethod::FromReflectedMethod(soa, javaReflectedMethod);
7
8 // Hook the method
9 artMethod->EnableXposedHook(soa, javaAdditionalInfo);
10}
EnableXposedHook
1、創建原函數備份
2、創建 XposedHookInfo 保存原函數、before函數、after函數
3、設置機器指令入口地址,此時跳入到GetQuickProxyInvokeHandler()地址
1void ArtMethod::EnableXposedHook(ScopedObjectAccess& soa, jobject additional_info) {
2 ...
3
4 // 創建原函數備份
5 auto* cl = Runtime::Current()->GetClassLinker();
6 auto* linear_alloc = cl->GetAllocatorForClassLoader(GetClassLoader());
7 ArtMethod* backup_method = cl->CreateRuntimeMethod(linear_alloc);
8 backup_method->CopyFrom(this, cl->GetImagePointerSize());
9 // 設置標識符kAccXposedOriginalMethod
10 backup_method->SetAccessFlags(backup_method->GetAccessFlags() | kAccXposedOriginalMethod);
11
12 // Create a Method/Constructor object for the backup ArtMethod object
13 mirror::AbstractMethod* reflected_method;
14 if (IsConstructor()) {
15 reflected_method = mirror::Constructor::CreateFromArtMethod(soa.Self(), backup_method);
16 } else {
17 reflected_method = mirror::Method::CreateFromArtMethod(soa.Self(), backup_method);
18 }
19 reflected_method->SetAccessible<false>(true);
20
21 // 創建 XposedHookInfo 保存原函數、before函數、after函數(reflected_method:被hook的函數,XposedHookInfo包含回調函數)
22 XposedHookInfo* hook_info = reinterpret_cast<XposedHookInfo*>(linear_alloc->Alloc(soa.Self(), sizeof(XposedHookInfo)));
23 hook_info->reflected_method = soa.Vm()->AddGlobalRef(soa.Self(), reflected_method);
24 hook_info->additional_info = soa.Env()->NewGlobalRef(additional_info);
25 hook_info->original_method = backup_method;
26 ...
27 //將entry_point_from_jni_指針指向hook信息(目的是存儲),hook信息包括原函數、before函數、after函數
28 SetEntryPointFromJniPtrSize(reinterpret_cast<uint8_t*>(hook_info), sizeof(void*));
29
30 // 設置機器指令入口地址,此時跳入到GetQuickProxyInvokeHandler()地址
31 SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
32 SetCodeItemOffset(0);
33
34 // Adjust access flags.
35 // 進行標志位清除,此時這個ArtMethod對象對應是Hook后的方法,這個方法的實現不是native的
36 const uint32_t kRemoveFlags = kAccNative | kAccSynchronized | kAccAbstract | kAccDefault | kAccDefaultConflict;
37 SetAccessFlags((GetAccessFlags() & ~kRemoveFlags) | kAccXposedHookedMethod);
38
39 MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
40 Runtime::Current()->GetThreadList()->ForEach(StackReplaceMethodAndInstallInstrumentation, this);
41}
artQuickProxyInvokeHandler
1extern "C" uint64_t artQuickProxyInvokeHandler(
2 ArtMethod* proxy_method, mirror::Object* receiver, Thread* self, ArtMethod** sp)
3 const bool is_xposed = proxy_method->IsXposedHookedMethod();//判斷 GetAccessFlags() 的kAccXposedHookedMethod 字段
4 ......
5 if (is_xposed) {
6 jmethodID proxy_methodid = soa.EncodeMethod(proxy_method);
7 self->EndAssertNoThreadSuspension(old_cause);
8 JValue result = InvokeXposedHandleHookedMethod(soa, shorty, rcvr_jobj, proxy_methodid, args);
9 local_ref_visitor.FixupReferences();
10 return result.GetJ();
11 }
12 ......
13 }
InvokeXposedHandleHookedMethod
1JValue InvokeXposedHandleHookedMethod(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty, jobject rcvr_jobj, jmethodID method, std::vector<jvalue>& args) {
2 //獲取ArtMethod 的 hookinfo 信息,該信息是EntryPointFromJniPtrSize所指向的信息
3 const XposedHookInfo* hookInfo = soa.DecodeMethod(method)->GetXposedHookInfo();
4 //將hookinfo 轉為一個數組,以便和java 層進行通信調用
5 jvalue invocation_args[5];
6 invocation_args[0].l = hookInfo->reflectedMethod;
7 invocation_args[1].i = 1;
8 invocation_args[2].l = hookInfo->additionalInfo;
9 invocation_args[3].l = rcvr_jobj;
10 invocation_args[4].l = args_jobj;
11 //通過CallStaticObjectMethodA 調用 xposed_callback_class 類里面 xposed_callback_method 的方法
12 //xposed_callback_class: XposedBridge.java
13 //xposed_callback_method: handleHookedMethod 方法
14 //ArtMethod 的這兩個值,在系統開機時 在 onVmCreated 進行賦值的
15 jobject result = soa.Env()->CallStaticObjectMethodA(ArtMethod::xposed_callback_class,
16 ArtMethod::xposed_callback_method,
17 invocation_args);
18 }
InvokeXposedHandleHookedMethod
(1)獲取ArtMethod 的 hookinfo 信息,該信息是EntryPointFromJniPtrSize所指向的信息
(2)通過CallStaticObjectMethodA 調用 xposed_callback_class 類里面 xposed_callback_method 的方法
(3)此處xposed_callback_class,xposed_callback_method 是libxposed_art.cpp#onVmCreated重寫時做的事
1const XposedHookInfo* GetXposedHookInfo() {
2 DCHECK(IsXposedHookedMethod());
3 // 前面存儲EntryPointFromJniPtrSize指向的信息
4 return reinterpret_cast<const XposedHookInfo*>(GetEntryPointFromJniPtrSize(sizeof(void*)));
5}
GetXposedHookInfo:獲取EntryPointFromJniPtrSize存儲的信息
Xposed.java#handleHookedMethod
1private static Object handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,
2 Object thisObject, Object[] args) throws Throwable {
3 AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj;
4 ...
5 // call "before method" callbacks
6 int beforeIdx = 0;
7 do {
8 try {
9 ((XC_MethodHook) callbacksSnapshot[beforeIdx]).beforeHookedMethod(param);
10 } catch (Throwable t) {
11 XposedBridge.log(t);
12
13 // reset result (ignoring what the unexpectedly exiting callback did)
14 param.setResult(null);
15 param.returnEarly = false;
16 continue;
17 }
18
19 if (param.returnEarly) {
20 // skip remaining "before" callbacks and corresponding "after" callbacks
21 beforeIdx++;
22 break;
23 }
24 } while (++beforeIdx < callbacksLength);
25
26 // call original method if not requested otherwise
27 if (!param.returnEarly) {
28 try {
29 param.setResult(invokeOriginalMethodNative(method, originalMethodId,
30 additionalInfo.parameterTypes, additionalInfo.returnType, param.thisObject, param.args));
31 } catch (InvocationTargetException e) {
32 param.setThrowable(e.getCause());
33 }
34 }
35
36 // call "after method" callbacks
37 int afterIdx = beforeIdx - 1;
38 do {
39 Object lastResult = param.getResult();
40 Throwable lastThrowable = param.getThrowable();
41
42 try {
43 ((XC_MethodHook) callbacksSnapshot[afterIdx]).afterHookedMethod(param);
44 } catch (Throwable t) {
45 XposedBridge.log(t);
46
47 // reset to last result (ignoring what the unexpectedly exiting callback did)
48 if (lastThrowable == null)
49 param.setResult(lastResult);
50 else
51 param.setThrowable(lastThrowable);
52 }
53 } while (--afterIdx >= 0);
54
55 // return
56 if (param.hasThrowable())
57 throw param.getThrowable();
58 else
59 return param.getResult();
60 }
XposedBridge.java 類的handleHookedMethod 方法,真正去處理 before、Original、after 這三個方法的調用關系。
ART函數調用原理
每一個Java函數在ART(虛擬機)內部都由一個ArtMethod對象表示,ArtMethod對象中包含了函數名、參數類型、方法體代碼入口地址等。
1class ArtMethod {
2 ...
3 protect:
4 HeapReference<Class> declaring_class_;
5 HeapReference<ObjectArray<ArtMethod>> dex_cache_resolved_methods_;
6 HeapReference<ObjectArray<Class>> dex_cache_resolved_types_;
7 uint32_t access_flags_;
8 uint32_t dex_code_item_offset_;
9 uint32_t dex_method_index_;
10 uint32_t method_index_;
11 struct PACKED(4) PtrSizedFields {
12 void* entry_point_from_interpreter_;
13 // 用於存儲jni函數信息,非jni函數的無用,所以經常被hook框架將原方法保存在entry_point_from_jni_
14 void* entry_point_from_jni_;
15 // ART HOOK常見的方法是替換入口點,執行hook的函數。(此處指向的是匯編代碼,運行的是已經預處理過的機器碼)
16 void* entry_point_from_quick_compiled_code_;
17
18#if defined(ART_USE_PORTABLE_COMPILER)
19 void* entry_point_from_portable_compiled_code_;
20#endif
21 } ptr_sized_fields_;
22 static GcRoot<Class> java_lang_reflect_ArtMethod_;
23}

替換entrypoint。將原函數對應的ArtMethod對象中entrypoint指向的機器碼替換為目標函數的機器碼,即可達到hook的目的。
總結
(1)准備包名、函數、參數類型、回調函數調用Hook接口
(2)Xposed在找到art虛擬機中找到方法對應的ArtMethod對象
(3)對ArtMethod對象進行備份
(4)修改備份對象的機器指令入口
(5)回調handleHookedMethod函數
參考
Xposed 源碼剖析1(初始話相關):https://blog.csdn.net/xiaolli/article/details/107506138
Xposed 源碼剖析2:https://blog.csdn.net/a314131070/article/details/81092526
Xposed 源碼剖析3:https://blog.csdn.net/a314131070/article/details/81092548
Xposed 源碼剖析4:https://blog.csdn.net/xiaolli/article/details/107517039
Xposed 源碼剖析5:https://egguncle.github.io/2018/02/04/xposed-art-hook-%E6%B5%85%E6%9E%90/
Xposed dalvik 源碼剖析6:https://bbs.pediy.com/thread-247030.htm
ART入口點替換分析:https://www.jianshu.com/p/820eceabf219
ArtMethod結構:https://zhuanlan.zhihu.com/p/92267192
ArtMethod結構:https://bbs.pediy.com/thread-248898.htm
Dalvik與ART:https://www.jianshu.com/p/59d98244fb52
定制xposed:https://blog.csdn.net/qq_35834055/article/details/103256122