Xposed原理分析

原创文章,转载请标明出处(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所需要的所有核心库。

zygote进程复制

新的App进程在生成后,就会加载本App的程序代码(apk中的dex文件)

Xposed介绍

Xposed是安卓系统上能够修改系统或三方应用信息的框架。

xposed_installer

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的载体)。

xposed初始化流程

源码分析

初始化

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, charconst 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, charconst 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.classString.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<?> clazzString methodNameObject... parameterTypesAndCallback{
2        if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-1instanceof 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

 

Art接口机器码入口

替换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

posted @ 2020-08-02 12:02  码头工人  阅读(2733)  评论(0编辑  收藏  举报