想用应用变量改型号,然后还下了xposed型号伪装,教程说要下载,然而我的下载键是灰色的,按不了,为什么,

摩托罗拉 MOTOROLA库_摩托罗拉 MOTOROLA品牌原创_什么值得买
当前位置:
01-15 15:21
01-15 15:03
01-13 12:10
01-11 18:31
01-11 18:28
01-05 14:51
用户名/邮箱
两周内免登录忘记密码?19128人阅读
自己重新做了文章,希望能更好的交流,若有任何冒犯请及时与我联系并致诚挚歉意
/QDZnvHCQ2QnBJ : PDF下载地址,自己的网盘
开发指南稍等一会放出,如果您有任何开发上的问题请随时给我发邮件: 很荣幸能和您交流技术上面的事情~
1&Introduction
Xposed是上大大设计的一个针对平台的动态劫持项目,通过替换程序控制进程,使得在启动过程中会加载这个包,从而完成对进程及其创建的虚拟机的劫持。与采取传统的方式(详见分析这篇本章&)相比,在开机的时候完成对所有的的劫持,在原执行的前后加上自定义代码。
Xposed框架的基本运行环境如下:
Configuration
RequireMent
Root&Access
因为工作原理是在目录下替换文件,在的时候需要权限,但是运行时不需要权限。
需要在以上版本的机器中
1.1.1&GitHub上资源梳理
XposedBridge.jar:XposedBridge.jar是Xposed提供的jar文件,负责在Native层与FrameWork层进行交互。/system/bin/app_process进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于该jar包的。注意:XposedBridge.jar文件本质上是由XposedBridge生成的APK文件更名而来,有 图为证:install.sh&Xposed:的部分,主要是用来替换,并为提供方法。&XposedInstaller:的安装包,负责配置工作的环境并且提供对基于框架的的管理。在安装之后,与放置在了。&XposedMods:使用开发的一些,其中是一个可以进行权限动态管理的应用
1.2&Mechanism:原理
1.2.1&Zygote
在系统中,应用程序进程都是由进程孵化出来的,而进程是由进程启动的。进程在启动时会创建一个虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的虚拟机实例。这也是Xposed选择替换的原因。
Zygote进程在启动的过程中,除了会创建一个虚拟机实例之外,还会将运行时库加载到进程中来,以及注册一些核心类的方法来前面创建的虚拟机实例中去。注意,一个应用程序进程被进程孵化出来的时候,不仅会获得进程中的虚拟机实例拷贝,还会与一起共享运行时库。这也就是可以将XposedBridge这个包加载到每一个应用程序中的原因。有一个私有的()方法hookMethodNative,这个方法也在中使用。这个函数提供一个方法对象利用的机制来对内置方法覆写。具体的实现可以看下文的源代码分析。
1.2.2&Hook/Replace
Xposed&框架中真正起作用的是对方法的。在技术中,如果要对做修改,则需要修改代码中的指令。而另一种动态修改指令的技术需要在程序运行时基于匹配搜索来替换代码,但因为方法声明的多样性与复杂性,这种方法也比较复杂。
在系统启动的时候,进程加载将所有需要替换的通过方法hookMethodNative指向方法,在转入这个方法执行用户规定的。
XposedBridge这个包含有一个私有的本地方法:,该方法在附加的程序中也得到了实现。它将一个方法对象作为输入参数(你可以使用的反射机制来获取这个方法)并且改变虚拟机中对于该方法的定义。它将该方法的类型改变为并且将这个方法的实现链接到它的本地的通用类的方法。换言之,当调用那个被的方法时候,通用的类方法会被调用而不会对调用者有任何的影响。在的实现中,会调用XposedBridge中的handleHookedMethod这个方法来传递参数。这个方法类似于一个统一调度的例程,其对应的底层的函数是。而实现里面会根据一个全局结构来选择相应的函数,并调用他们的函数。
当多模块同时一个方法的时候,会自动根据的优先级来排序,调用顺序如下:
A.before&-&&B.before&-&&original&method&-&&B.after&-&&A.after
2&源代码分析
本部分参考了看雪论坛某大神的文章,对于上一篇文章中代码分析部分几乎照搬了他的文章深表歉意。最近一直在,个人感觉流程方式叙述函数调用虽然调理比较明晰,但是还是较复杂,本文中采取面向函数对象的介绍方式,在函数的介绍顺序上采取流程式。如果对于某个函数方法有疑问的直接在本文内搜索。
2.1&Application:XposedInstaller
XposedInstaller负责对运行环境的安装配置与的管理,无论对于开发者还是普通用户而言,都是接触到的第一个应用。另一方面,如果我们需要抛弃本来的管理机制,改编为我们自己的应用,也需要了解的基本流程。
2.1.1&InstallerFragment
private String install(); & & & & & & & & & & & &&@function 执行app_process的替换与XposedBridge.jar的写入操作。
2.2&Cpp:app_main.cpp&
正如第一部分所言,会在系统启动的时候加载并进行的替换操作。我们首先从模块的进程的源代码谈起。类似中的,即这个真实身份的应用程序的源代码。关于进程的分析可以参照中的进程详解。
2.2.1&int&main(int&argc,&char*&const&argv[])
Zygote进程首先从函数开始执行。
int main(int argc, char* const argv[])
@function 该函数对于SDK&=18的会获取到atrace_set_tracing_enabled的函数指针,获取到的指针会在Zygote初始化过程中调用,函数定义见代码段下方
initTypePointers();
@function 该函数主要获取一些属性值譬如SDK版本,设备厂商,设备型号等信息并且打印到Log文件中
@description xposedInfo函数定义在xposed.cpp中
xposedInfo();
//变量标志是否需要加载Xposed框架
keepLoadingXposed =
@function 该函数主要分析Xposed框架是否被禁用了。
@description 该函数定义在了xposed.cpp中
!isXposedDisabled()
!xposedShouldIgnoreCommand(className, argc, argv)
@function 将XposedBridge所在路径加入到系统环境变量CLASSPATH中
@para zygote bool类型,描述是否需要重启zygote,参数来源于启动指令“--zygote”参数
@description 该函数定义在了xposed.cpp中
addXposedToClasspath(zygote);
@annotation 1
if (zygote) {
runtime.start(keepLoadingXposed ? XPOSED_CLASS_DOTS : &com.android.internal.os.ZygoteInit&,
startSystemServer ? &start-system-server& : &&);
} else if (className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = classN
runtime.mArgC = argc -
runtime.mArgV = argv +
runtime.start(keepLoadingXposed ? XPOSED_CLASS_DOTS : &com.android.internal.os.RuntimeInit&,
application ? &application& : &tool&);
fprintf(stderr, &Error: no class name or --zygote supplied.\n&);
app_usage();
LOG_ALWAYS_FATAL(&app_process: no class name or --zygote supplied.&);
return 10;
annotation&1
在annotation&1之后,开始执行启动的操作。一般情况下keepLoadingXposed值为true,以启动Zygote为例(zygote==true),分析接下来的代码。如果zygote为,即是启动普通所属的情景。
这一行代码是根据的值来判断是加载框架还是正常的类。值为则会加载类,值为,即类。是的实例,继承自。
@function AppRuntime类的方法,用于启动Dalvik虚拟机。
@description 定义于app_main.cpp中
runtime.start(keepLoadingXposed ? XPOSED_CLASS_DOTS : &com.android.internal.os.RuntimeInit&,
application ? &application& : &tool&);
2.2.2&void&initTypePointers()
@function 该函数对于SDK&=18的会获取到atrace_set_tracing_enabled的函数指针,获取到的指针会在Zygote初始化过程中调用
void initTypePointers()
char sdk[PROPERTY_VALUE_MAX];
const char *
property_get(&ro.build.version.sdk&, sdk, &0&);
RUNNING_PLATFORM_SDK_VERSION = atoi(sdk);
dlerror();
if (RUNNING_PLATFORM_SDK_VERSION &= 18) {
*(void **) (&PTR_atrace_set_tracing_enabled) = dlsym(RTLD_DEFAULT, &atrace_set_tracing_enabled&);
if ((error = dlerror()) != NULL) {
ALOGE(&Could not find address for function atrace_set_tracing_enabled: %s&, error);
static AndroidRuntime* gCurRuntime = NULL;
AndroidRuntime::AndroidRuntime()
assert(gCurRuntime == NULL);
// one per process
gCurRuntime =
2.2.3.1&void&AndroidRuntime::start(const&char*&className,&const&bool&startSystemServer)
AppRuntime继承自,其自身没有方法,则在中调用的还是其父类的方法。AndroidRuntime::start(const&char*&className,&const&char*&options)函数完成虚拟机的初始化和启动以及运行参数指定的类中的方法。当启动完虚拟机后,会调用函数。该函数在类中被覆盖。因此直接看。
void AndroidRuntime::start(const char* className, const bool startSystemServer)
char* slashClassName = NULL;
/* start the virtual machine */
if (startVm(&mJavaVM, &env) != 0)
* Register android functions.
if (startReg(env) & 0) {
LOGE(&Unable to register all android natives\n&);
* We want to call main() with a String array with arguments in it.
* At present we only have one argument, the class name.
* array to hold it.
jclass stringC
jobjectArray strA
jstring classNameS
jstring startSystemServerS
stringClass = env-&FindClass(&java/lang/String&);
assert(stringClass != NULL);
strArray = env-&NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env-&NewStringUTF(className);
assert(classNameStr != NULL);
env-&SetObjectArrayElement(strArray, 0, classNameStr);
startSystemServerStr = env-&NewStringUTF(startSystemServer ?
&true& : &false&);
env-&SetObjectArrayElement(strArray, 1, startSystemServerStr);
* Start VM.
This thread becomes the main thread of the VM, and will
* not return until the VM exits.
jclass startC
jmethodID startM
slashClassName = strdup(className);
for (cp = slashClassN *cp != '\0'; cp++)
if (*cp == '.')
*cp = '/';
startClass = env-&FindClass(slashClassName);
if (startClass == NULL) {
startMeth = env-&GetStaticMethodID(startClass, &main&,
&([Ljava/lang/S)V&);
if (startMeth == NULL) {
env-&CallStaticVoidMethod(startClass, startMeth, strArray);
如果对启动过程熟悉的话,对后续的函数是如何被调用的应该会很清楚。的函数完成环境变量的设置,虚拟机的初始化和启动,同时在中完成了自身方法的注册。此后函数会注册系统的方法,调用传入的指定类的方法,进入世界。
由于此时参数为,因此会调用类的方法。
2.2.3.2&virtual&void&onVmCreated(JNIEnv*&env)
virtual void onVmCreated(JNIEnv* env)
@function 用于加载XposedBridge.jar这个类,本函数只有这个函数是增加的
@para JNI环境指针
@para mClassName runtime.mClassName = className这句指定
@description 定义于xposed.cpp中
keepLoadingXposed = xposedOnVmCreated(env, mClassName);
if (mClassName == NULL) {
// Zygote. Nothing to do here.
char* slashClassName = toSlashClassName(mClassName);
mClass = env-&FindClass(slashClassName);
if (mClass == NULL) {
ALOGE(&ERROR: could not find class '%s'\n&, mClassName);
free(slashClassName);
mClass = reinterpret_cast&jclass&(env-&NewGlobalRef(mClass));
2.3&Cpp:xposed.cpp
2.3.1&isXposedDisabled
这个函数负责来判断框架是否为启用,如果不小心写错了,可以通过手动创建文件来防止手机鸟掉。
@function 判断Xposed框架是否被激活
bool isXposedDisabled() {
//该函数通过读取/data/data/de.robv.android.xposed.installer/conf/disabled文件来判断Xposed框架是否被禁用,如果该文件存在,则表示禁用Xposed。
if (access(XPOSED_LOAD_BLOCKER, F_OK) == 0) {
ALOGE(&found %s, not loading Xposed\n&, XPOSED_LOAD_BLOCKER);
2.3.2&xposedShouldIgnoreCommand
这个函数写的还是极好的,可以看看来增加点见识。
@function 为了避免Superuser类似工具滥用Xposed的log文件,此函数会判断是否是SuperUser等工具的启动请求。
bool xposedShouldIgnoreCommand(const char* className, int argc, const char* const argv[]) {
if (className == NULL || argc & 4 || strcmp(className, &mands.am.Am&) != 0)
if (strcmp(argv[2], &broadcast&) != 0 && strcmp(argv[2], &start&) != 0)
bool mightBeSuperuser =
for (int i = 3; i & i++) {
if (strcmp(argv[i], &com.noshufou.android.su.RESULT&) == 0
|| strcmp(argv[i], &eu.chainfire.supersu.NativeAccess&) == 0)
if (mightBeSuperuser && strcmp(argv[i], &--user&) == 0)
char* lastComponent = strrchr(argv[i], '.');
if (!lastComponent)
if (strcmp(lastComponent, &.RequestActivity&) == 0
|| strcmp(lastComponent, &.NotifyActivity&) == 0
|| strcmp(lastComponent, &.SuReceiver&) == 0)
mightBeSuperuser =
2.3.3&addXposedToClasspath
若有新版本的XposedBridge,重命名为XposedBridge.jar并返回判断XposedBridge.jar文件是否存在,若不存在,返回false,否则将XposedBridge.jar所在路径添加到CLASSPATH环境变量中,返回true。
@function 将XposedBridge.jar添加到CLASSPATH
bool addXposedToClasspath(bool zygote) {
ALOGI(&-----------------\n&);
// do we have a new version and are (re)starting zygote? Then load it!
if (zygote && access(XPOSED_JAR_NEWVERSION, R_OK) == 0) {
ALOGI(&Found new Xposed jar version, activating it\n&);
if (rename(XPOSED_JAR_NEWVERSION, XPOSED_JAR) != 0) {
ALOGE(&could not move %s to %s\n&, XPOSED_JAR_NEWVERSION, XPOSED_JAR);
if (access(XPOSED_JAR, R_OK) == 0) {
char* oldClassPath = getenv(&CLASSPATH&);
if (oldClassPath == NULL) {
setenv(&CLASSPATH&, XPOSED_JAR, 1);
char classPath[4096];
sprintf(classPath, &%s:%s&, XPOSED_JAR, oldClassPath);
setenv(&CLASSPATH&, classPath, 1);
ALOGI(&Added Xposed (%s) to CLASSPATH.\n&, XPOSED_JAR);
ALOGE(&ERROR: could not access Xposed jar '%s'\n&, XPOSED_JAR);
2.3.4&bool&xposedOnVmCreated(JNIEnv*&env,&const&char*&className)
bool xposedOnVmCreated(JNIEnv* env, const char* className) {
if (!keepLoadingXposed)
//将要启动的Class的Name赋值给startClassName
startClassName = classN
@function 根据JIT是否存在对部分结构体中的成员偏移进行初始化。
@description 定义在xposed.cpp中。关于JIT的介绍详见我的关于Dalvik虚拟机的介绍
xposedInitMemberOffsets();
//下面开始对部分访问检查设置为true
patchReturnTrue((void*) &dvmCheckClassAccess);
patchReturnTrue((void*) &dvmCheckFieldAccess);
patchReturnTrue((void*) &dvmInSamePackage);
if (access(XPOSED_DIR &conf/do_not_hook_dvmCheckMethodAccess&, F_OK) != 0)
patchReturnTrue((void*) &dvmCheckMethodAccess);
//针对MIUI操作系统移除android.content.res.MiuiResources类的final修饰符
jclass miuiResourcesClass = env-&FindClass(MIUI_RESOURCES_CLASS);
if (miuiResourcesClass != NULL) {
ClassObject* clazz = (ClassObject*)dvmDecodeIndirectRef(dvmThreadSelf(), miuiResourcesClass);
if (dvmIsFinalClass(clazz)) {
ALOGD(&Removing final flag for class '%s'&, MIUI_RESOURCES_CLASS);
clazz-&accessFlags &= ~ACC_FINAL;
env-&ExceptionClear();
//开始获取XposedBridge类并new一个新的全局引用
xposedClass = env-&FindClass(XPOSED_CLASS);
xposedClass = reinterpret_cast&jclass&(env-&NewGlobalRef(xposedClass));
if (xposedClass == NULL) {
ALOGE(&Error while loading Xposed class '%s':\n&, XPOSED_CLASS);
dvmLogExceptionStackTrace();
env-&ExceptionClear();
ALOGI(&Found Xposed class '%s', now initializing\n&, XPOSED_CLASS);
@function 开始注册XposedBridge中JNI函数
register_de_robv_android_xposed_XposedBridge(env);
register_android_content_res_XResources(env);
2.3.5&JNI函数注册区域
static const JNINativeMethod xposedMethods[] = {
{&getStartClassName&, &()Ljava/lang/S&, (void*)de_robv_android_xposed_XposedBridge_getStartClassName},
{&initNative&, &()Z&, (void*)de_robv_android_xposed_XposedBridge_initNative},
{&hookMethodNative&, &(Ljava/lang/reflect/MLjava/lang/CILjava/lang/O)V&, (void*)de_robv_android_xposed_XposedBridge_hookMethodNative},
static jobject de_robv_android_xposed_XposedBridge_getStartClassName(JNIEnv* env, jclass clazz) {
return env-&NewStringUTF(startClassName);
static int register_de_robv_android_xposed_XposedBridge(JNIEnv* env) {
return env-&RegisterNatives(xposedClass, xposedMethods, NELEM(xposedMethods));
static const JNINativeMethod xresourcesMethods[] = {
{&rewriteXmlReferencesNative&, &(ILandroid/content/res/XRLandroid/content/res/R)V&, (void*)android_content_res_XResources_rewriteXmlReferencesNative},
static int register_android_content_res_XResources(JNIEnv* env) {
return env-&RegisterNatives(xresourcesClass, xresourcesMethods, NELEM(xresourcesMethods));
2.3.6&initNative
该函数主要完成对类中函数的引用,这样可以实现在层对层函数的调用。譬如获取类中的函数的,同时赋值给全局变量。另外,函数还会获取类中的方法,完成对资源文件的处理;调用注册这个方法。
static jboolean de_robv_android_xposed_XposedBridge_initNative(JNIEnv* env, jclass clazz) {
xposedHandleHookedMethod = (Method*) env-&GetStaticMethodID(xposedClass, &handleHookedMethod&,
&(Ljava/lang/reflect/MILjava/lang/OLjava/lang/O[Ljava/lang/O)Ljava/lang/O&);
xresourcesClass = env-&FindClass(XRESOURCES_CLASS);
xresourcesClass = reinterpret_cast&jclass&(env-&NewGlobalRef(xresourcesClass));
if (register_android_content_res_XResources(env) != JNI_OK) {
ALOGE(&Could not register natives for '%s'\n&, XRESOURCES_CLASS);
xresourcesTranslateResId = env-&GetStaticMethodID(xresourcesClass, &translateResId&,
&(ILandroid/content/res/XRLandroid/content/res/R)I&);
xresourcesTranslateAttrId = env-&GetStaticMethodID(xresourcesClass, &translateAttrId&,
&(Ljava/lang/SLandroid/content/res/XR)I&);
@function hookMethodNative 将输入的Class中的Method方法的nativeFunc替换为xposedCallHandler
@para declaredClassIndirect 类对象
@para slot Method在类中的偏移位置
static void de_robv_android_xposed_XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject declaredClassIndirect, jint slot) {
// Usage errors?
if (declaredClassIndirect == NULL) {
dvmThrowIllegalArgumentException(&declaredClass must not be null&);
// Find the internal representation of the method
ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
Method* method = dvmSlotToMethod(declaredClass, slot);
if (method == NULL) {
dvmThrowNoSuchMethodError(&could not get internal representation for method&);
if (findXposedOriginalMethod(method) != xposedOriginalMethods.end()) {
// already hooked
// Save a copy of the original method
xposedOriginalMethods.push_front(*((MethodXposedExt*)method));
// Replace method with our own code
SET_METHOD_FLAG(method, ACC_NATIVE);
method-&nativeFunc = &xposedCallH
method-&registersSize = method-&insS
method-&outsSize = 0;
if (PTR_gDvmJit != NULL) {
// reset JIT cache
MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) =
2.3.8&xposedCallHandler
static void xposedCallHandler(const u4* args, JValue* pResult, const Method* method, ::Thread* self) {
XposedOriginalMethodsIt original = findXposedOriginalMethod(method);
if (original == xposedOriginalMethods.end()) {
dvmThrowNoSuchMethodError(&could not find Xposed original method - how did you even get here?&);
ThreadStatus oldThreadStatus = MEMBER_VAL(self, Thread, status);
JNIEnv* env = MEMBER_VAL(self, Thread, jniEnv);
// get java.lang.reflect.Method object for original method
jobject originalReflected = env-&ToReflectedMethod(
(jclass)xposedAddLocalReference(self, original-&clazz),
(jmethodID)method,
// convert/box arguments
const char* desc = &method-&shorty[1]; // [0] is the return type.
Object* thisObject = NULL;
size_t srcIndex = 0;
size_t dstIndex = 0;
// for non-static methods determine the &this& pointer
if (!dvmIsStaticMethod(&(*original))) {
thisObject = (Object*) xposedAddLocalReference(self, (Object*)args[0]);
srcIndex++;
jclass objectClass = env-&FindClass(&java/lang/Object&);
jobjectArray argsArray = env-&NewObjectArray(strlen(method-&shorty) - 1, objectClass, NULL);
while (*desc != '\0') {
char descChar = *(desc++);
switch (descChar) {
value.i = args[srcIndex++];
obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
dvmReleaseTrackedAlloc(obj, NULL);
value.j = dvmGetArgLong(args, srcIndex);
srcIndex += 2;
obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
dvmReleaseTrackedAlloc(obj, NULL);
= (Object*) args[srcIndex++];
ALOGE(&Unknown method signature description character: %c\n&, descChar);
obj = NULL;
srcIndex++;
env-&SetObjectArrayElement(argsArray, dstIndex++, xposedAddLocalReference(self, obj));
@function 调用Java中方法
@para xposedClass
@para xposedHandleHookedMethod
xposedHandleHookedMethod = env-&GetStaticMethodID(xposedClass, &handleHookedMethod&,
&(Ljava/lang/reflect/MLjava/lang/O[Ljava/lang/O)Ljava/lang/O&);
jobject resultRef = env-&CallStaticObjectMethod(
xposedClass, xposedHandleHookedMethod, originalReflected, thisObject, argsArray);
// exceptions are thrown to the caller
if (env-&ExceptionCheck()) {
dvmChangeStatus(self, oldThreadStatus);
// return result with proper type
Object* result = dvmDecodeIndirectRef(self, resultRef);
ClassObject* returnType = dvmGetBoxedReturnType(method);
if (returnType-&primitiveType == PRIM_VOID) {
// ignored
} else if (result == NULL) {
if (dvmIsPrimitiveClass(returnType)) {
dvmThrowNullPointerException(&null result when primitive expected&);
pResult-&l = NULL;
if (!dvmUnboxPrimitive(result, returnType, pResult)) {
dvmThrowClassCastException(result-&clazz, returnType);
// set the thread status back to running. must be done after the last env-&...()
dvmChangeStatus(self, oldThreadStatus);
2.4&Java:XposedBridge
注意,以下介绍的中所调用的方法都是在
2.4.1&private&static&void&main(String[]&args)
由跳入执行的第一个函数。
private static void main(String[] args) {
@function Native方法,用于获取当前启动的类名
String startClassName = getStartClassName();
// 初始化Xposed框架与模块
// 初始化Log文件
File logFile = new File(&/data/xposed/debug.log&);
if (startClassName == null && logFile.length() & MAX_LOGFILE_SIZE)
logFile.renameTo(new File(&/data/xposed/debug.log.old&));
logWriter = new PrintWriter(new FileWriter(logFile, true));
logFile.setReadable(true, false);
logFile.setWritable(true, false);
} catch (IOException ignored) {}
String date = DateFormat.getDateTimeInstance().format(new Date());
log(&-----------------\n& + date + & UTC\n&
+ &Loading Xposed (for & + (startClassName == null ? &Zygote& : startClassName) + &)...&);
@function 负责获取XposedBridge中Java函数的引用
@description Native函数,定义于xposed.cpp中
if (initNative()) {
if (startClassName == null) {
@function 如果是启动Zygote进程,则执行initXbridgeZygote函数
@description 定义在XposedBridge类中
initXbridgeZygote();
@function 负责加载所有模块
@description 定义在XposedBridge类中
loadModules(startClassName);
log(&Errors during native Xposed initialization&);
} catch (Throwable t) {
log(&Errors during Xposed initialization&);
// 调用原来的启动参数
if (startClassName == null)
@description com.android.internal.os.ZygoteInit
ZygoteInit.main(args);
RuntimeInit.main(args);
2.4.2&void&initXbridgeZygote():Hook系统关键函数
initXbridgeZygote完成对一些函数的操作,主要是调用类中的完成。
private static void initXbridgeZygote() throws Exception {
final HashSet&String& loadedPackagesInProcess = new HashSet&String&(1);
@function 执行Hook替换操作
@para ActivityThread.class 需要hook的函数所在的类;
@para &handleBindApplication& 需要hook的函数名
&android.app.ActivityThread.AppBindData& 不定参数
@description 定义在XposedHelper中
findAndHookMethod(ActivityThread.class, &handleBindApplication&, &android.app.ActivityThread.AppBindData&, new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
ActivityThread activityThread = (ActivityThread) param.thisO
ApplicationInfo appInfo = (ApplicationInfo) getObjectField(param.args[0], &appInfo&);
ComponentName instrumentationName = (ComponentName) getObjectField(param.args[0], &instrumentationName&);
if (instrumentationName != null) {
XposedBridge.log(&Instrumentation detected, disabling framework for & + appInfo.packageName);
disableHooks =
CompatibilityInfo compatInfo = (CompatibilityInfo) getObjectField(param.args[0], &compatInfo&);
if (appInfo.sourceDir == null)
setObjectField(activityThread, &mBoundApplication&, param.args[0]);
loadedPackagesInProcess.add(appInfo.packageName);
LoadedApk loadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
XResources.setPackageNameForResDir(appInfo.packageName, loadedApk.getResDir());
LoadPackageParam lpparam = new LoadPackageParam(loadedPackageCallbacks);
lpparam.packageName = appInfo.packageN
lpparam.processName = (String) getObjectField(param.args[0], &processName&);
lpparam.classLoader = loadedApk.getClassLoader();
lpparam.appInfo = appI
lpparam.isFirstApplication =
XC_LoadPackage.callAll(lpparam);
2.4.3&loadModules(String&startClassName):开始Hook&Module中自定义函数
@function 用于加载所有Xposed模块中定义的Hook操作
@para startClassName 当前打开的Class Name
private static void loadModules(String startClassName) throws IOException {
BufferedReader apks = new BufferedReader(new FileReader(BASE_DIR + &conf/modules.list&));
while ((apk = apks.readLine()) != null) {
loadModule(apk, startClassName);
apks.close();
@function 从各个模块定义的xposed_init文件中进行目标函数的Hook
@para apk 模块名称,即所属Application
@para startClassName 当前打开的Class Name
private static void loadModule(String apk, String startClassName) {
log(&Loading modules from & + apk);
if (!new File(apk).exists()) {
File does not exist&);
ClassLoader mcl = new PathClassLoader(apk, BOOTCLASSLOADER);
InputStream is = mcl.getResourceAsStream(&assets/xposed_init&);
if (is == null) {
log(&assets/xposed_init not found in the APK&);
BufferedReader moduleClassesReader = new BufferedReader(new InputStreamReader(is));
String moduleClassN
while ((moduleClassName = moduleClassesReader.readLine()) != null) {
moduleClassName = moduleClassName.trim();
if (moduleClassName.isEmpty() || moduleClassName.startsWith(&#&))
Loading class & + moduleClassName);
Class&?& moduleClass = mcl.loadClass(moduleClassName);
if (!IXposedMod.class.isAssignableFrom(moduleClass)) {
log(&This class doesn't implement any sub-interface of IXposedMod, skipping it&);
@description 在Zygote启动之前执行自定义的ZygoteInit函数等自定义的Module指令
@annotation 1
final Object moduleInstance = moduleClass.newInstance();
if (startClassName == null) {
if (moduleInstance instanceof IXposedHookZygoteInit) {
IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam();
param.modulePath =
((IXposedHookZygoteInit) moduleInstance).initZygote(param);
if (moduleInstance instanceof IXposedHookLoadPackage)
hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance));
if (moduleInstance instanceof IXposedHookInitPackageResources)
hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
if (moduleInstance instanceof IXposedHookCmdInit) {
IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
param.modulePath =
param.startClassName = startClassN
((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
} catch (Throwable t) {
} catch (IOException e) {
} finally {
is.close();
} catch (IOException ignored) {
annotation&1
以下代码段主要将中定义的类使用操作符确定其所属父类并依次执行操作,提供的接口类主要分为:
IXposedHookZygoteInit
该类主要提供接口函数,用于在进程启动之前执行相关代码。
IXposedHookLoadPackage
主要的操作类。
IXposedHookInitPackageResources
提供资源相关所需要的函数。
IXposedHookCmdInit
Hook并处理启动新的虚拟机时所需要的参数。
2.4.4&hookMethod
XposedBridge类的静态方法实现对函数的和回调函数的注册。
* @function Hook指定方法并设置前后回调函数
* @param 方法名
* @param 回调函数组
public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) {
if (!(hookMethod instanceof Method) && !(hookMethod instanceof Constructor&?&)) {
throw new IllegalArgumentException(&only methods and constructors can be hooked&);
boolean newMethod =
TreeSet&XC_MethodHook&
HookedMethodCallbacks是一个hashMap的实例,存储每个需要hook的method的回调函数。
首先查看hookedMethodCallbacks中是否有hookMethod对应的callbacks的集合,
如果没有,则创建一个TreeSet,将该callbacks加入到hookedMethodCallbacks中,同时将newMethod标志设为true。
接下来将传入的callback添加到callbacks集合中。
synchronized (hookedMethodCallbacks) {
callbacks = hookedMethodCallbacks.get(hookMethod);
if (callbacks == null) {
callbacks = new TreeSet&XC_MethodHook&();
hookedMethodCallbacks.put(hookMethod, callbacks);
newMethod =
synchronized (callbacks) {
callbacks.add(callback);
if (newMethod) {
Class&?& declaringClass = hookMethod.getDeclaringClass();
int slot = (int) getIntField(hookMethod, &slot&);
@function 调用Native方法hookMethodNative,通知Native层declaringClass中的某个method是被hook的
@para declaringClass 要hook的目标类
@para slot Method编号
@description Native方法,定义在了xposed.cpp中
hookMethodNative(declaringClass, slot);
return callback.new Unhook(hookMethod);
2.4.5&handleHookedMethod
handleHookedMethod将被的代码又交还给层实现。
private static Object handleHookedMethod(Member method, Object thisObject, Object[] args) throws Throwable {
if (disableHooks) {
return invokeOriginalMethod(method, thisObject, args);
} catch (InvocationTargetException e) {
throw e.getCause();
首先判断是否被禁用,若是,则直接调用函数,完成对原始函数的执行。关于如何执行原始函数的,可以继续跟踪下去分析。
TreeSet&XC_MethodHook&
synchronized (hookedMethodCallbacks) {
callbacks = hookedMethodCallbacks.get(method);
if (callbacks == null || callbacks.isEmpty()) {
return invokeOriginalMethod(method, thisObject, args);
} catch (InvocationTargetException e) {
throw e.getCause();
synchronized (callbacks) {
callbacks = ((TreeSet&XC_MethodHook&) callbacks.clone());
根据值,从中获取对应的信息。的分析可以参考之前对的分析。中存储了所有对该进行的和。接着从中获取和的迭代器。
Iterator&XC_MethodHook& before = callbacks.iterator();
Iterator&XC_MethodHook& after
= callbacks.descendingIterator();
// call &before method& callbacks
while (before.hasNext()) {
before.next().beforeHookedMethod(param);
} catch (Throwable t) {
XposedBridge.log(t);
// reset result (ignoring what the unexpectedly exiting callback did)
param.setResult(null);
param.returnEarly =
if (param.returnEarly) {
// skip remaining &before& callbacks and corresponding &after& callbacks
while (before.hasNext() && after.hasNext()) {
before.next();
after.next();
// call original method if not requested otherwise
if (!param.returnEarly) {
param.setResult(invokeOriginalMethod(method, param.thisObject, param.args));
} catch (InvocationTargetException e) {
param.setThrowable(e.getCause());
// call &after method& callbacks
while (after.hasNext()) {
Object lastResult =
param.getResult();
Throwable lastThrowable = param.getThrowable();
after.next().afterHookedMethod(param);
} catch (Throwable t) {
XposedBridge.log(t);
// reset to last result (ignoring what the unexpectedly exiting callback did)
if (lastThrowable == null)
param.setResult(lastResult);
param.setThrowable(lastThrowable);
if (param.hasThrowable())
throw param.getThrowable();
   return param.getResult();
通过以上的分析,基本能够弄清楚框架实现的原理。将需要的函数替换成方法,这样在执行被的函数时,就会直接调用,再调用类的完成注册的以及的调用,这两类回调函数之间,会调用原始函数,完成正常的功能。
2.5&Java:Class&XposedHelper
2.5.1&findAndHookMethod
@function 根据输入的类名与方法名进行Hook操作。
@para className 输入的类的名称
@para classLoader 当前上下文中的类加载器
@para methodName 方法名称
@para parameterTypesAndCallback 不定参数组,包括方法参数与回调函数
public static XC_MethodHook.Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) {
return findAndHookMethod(findClass(className, classLoader), methodName, parameterTypesAndCallback);
public static XC_MethodHook.Unhook findAndHookMethod(Class&?& clazz, String methodName, Object... parameterTypesAndCallback) {
@function 判断不定参数组的最后一个参数是否为XC_MethodHook
if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-1] instanceof XC_MethodHook))
throw new IllegalArgumentException(&no callback defined&);
XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-1];
@function 在一个类中查找到指定方法并将该方法设置为Accessible
@para clazz 类对象
@para methodName 方法名称
@para parameterTypesAndCallback 方法参数
@description 该类定义在了XposedHelper中
@exception 如果没有在指定的类中查找到指定方法,则抛出NoSuchMethodError这个异常
Method m = findMethodExact(clazz, methodName, parameterTypesAndCallback);
@function 根据方法对象通知Native函数hookMethodNative执行Hook操作
@para method 要Hook的方法对象
@callback 回调函数组
@description 定义在XposedBridge中
return XposedBridge.hookMethod(m, callback);
2.5.2&findMethodExact
@function findMethodExact(Class&?& clazz, String methodName, Class&?&... parameterTypes)的重载函数
public static Method findMethodExact(Class&?& clazz, String methodName, Object... parameterTypes) {
Class&?&[] parameterClasses =
for (int i = parameterTypes.length - 1; i &= 0; i--) {
Object type = parameterTypes[i];
if (type == null)
throw new ClassNotFoundError(&parameter type must not be null&, null);
// ignore trailing callback
if (type instanceof XC_MethodHook)
if (parameterClasses == null)
parameterClasses = new Class&?&[i+1];
if (type instanceof Class)
parameterClasses[i] = (Class&?&)
else if (type instanceof String)
parameterClasses[i] = findClass((String) type, clazz.getClassLoader());
throw new ClassNotFoundError(&parameter type must either be specified as Class or String&, null);
// if there are no arguments for the method
if (parameterClasses == null)
parameterClasses = new Class&?&[0];
return findMethodExact(clazz, methodName, parameterClasses);
@function 在一个类中查找到指定方法并将该方法设置为Accessible
@para clazz 类对象
@para methodName 方法名称
@para parameterTypesAndCallback 方法参数
@description 该类定义在了XposedHelper中
@exception 如果没有在指定的类中查找到指定方法,则抛出NoSuchMethodError这个异常
public static Method findMethodExact(Class&?& clazz, String methodName, Class&?&... parameterTypes) {
StringBuilder sb = new StringBuilder(clazz.getName());
sb.append('#');
sb.append(methodName);
sb.append(getParametersString(parameterTypes));
sb.append(&#exact&);
String fullMethodName = sb.toString();
@function 判断当前Method是否已经被Hook
if (methodCache.containsKey(fullMethodName)) {
Method method = methodCache.get(fullMethodName);
if (method == null)
throw new NoSuchMethodError(fullMethodName);
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
@annotation 1
methodCache.put(fullMethodName, method);
} catch (NoSuchMethodException e) {
methodCache.put(fullMethodName, null);
throw new NoSuchMethodError(fullMethodName);
annotation&1
在函数中,首先将类名、方法名以及参数信息构建成一个键值,以该键值从中查找是否存在实例,相当于缓存了对应的实例。如果没有找到,会调用类的方法获取实例,同时将该设置为可访问,加入到中。
2.5&Java:Class&XC_MethodHook
XC_MethodHook类中的函数会在被的函数调用之前调用,而函数会在被的函数调用之后调用。这两个函数的方法体为空,需要在实例化时根据情况填充方法体。的内部类保存了相应的信息,如调用方法的参数,对象,函数的返回值等。
public abstract class XC_MethodHook extends XCallback {
public XC_MethodHook() {
public XC_MethodHook(int priority) {
super(priority);
* Called before the invocation of the method.
* &p&Can use {@link MethodHookParam#setResult(Object)} and {@link MethodHookParam#setThrowable(Throwable)}
* to prevent the original method from being called.
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {}
* Called after the invocation of the method.
* &p&Can use {@link MethodHookParam#setResult(Object)} and {@link MethodHookParam#setThrowable(Throwable)}
* to modify the return value of the original method.
protected void afterHookedMethod(MethodHookParam param) throws Throwable
public static class MethodHookParam extends XCallback.Param {
/** Description of the hooked method */
/** The &code&this&/code& reference for an instance method, or null for static methods */
public Object thisO
/** Arguments to the method call */
public Object[]
private Object result =
private Throwable throwable =
/* package */ boolean returnEarly =
/** Returns the result of the method call */
public Object getResult() {
* Modify the result of the method call. In a &before-method-call&
* hook, prevents the call to the original method.
* You still need to &return& from the hook handler if required.
public void setResult(Object result) {
this.result =
this.throwable =
this.returnEarly =
/** Returns the &code&Throwable&/code& thrown by the method, or null */
public Throwable getThrowable() {
/** Returns true if an exception was thrown by the method */
public boolean hasThrowable() {
return throwable !=
* Modify the exception thrown of the method call. In a &before-method-call&
* hook, prevents the call to the original method.
* You still need to &return& from the hook handler if required.
public void setThrowable(Throwable throwable) {
this.throwable =
this.result =
this.returnEarly =
/** Returns the result of the method call, or throws the Throwable caused by it */
public Object getResultOrThrowable() throws Throwable {
if (throwable != null)
public class Unhook implements IXUnhook {
private final Member hookM
public Unhook(Member hookMethod) {
this.hookMethod = hookM
public Member getHookedMethod() {
return hookM
public XC_MethodHook getCallback() {
return XC_MethodHook.
public void unhook() {
XposedBridge.unhookMethod(hookMethod, XC_MethodHook.this);
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:79548次
积分:1380
积分:1380
排名:第18443名
原创:50篇
评论:26条
(7)(4)(1)(1)(2)(2)(1)(7)(9)(3)(1)(19)(1)}

我要回帖

更多关于 xposed框架 型号伪装 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信