`
weihe6666
  • 浏览: 440090 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

XPosed解析--XposedBridge--main分析

阅读更多
XposedBridge是Xposed框架替代ZygoteInit的文件,其中main方式是其入口,分析main方法可以更好的理解Xposed的运行模式,下面就来分析一下此函数。

	private static void main(String[] args) {
		// the class the VM has been created for or null for the Zygote process
		String startClassName = getStartClassName();

		// initialize the Xposed framework and modules
		try {
			// initialize log file
			try {
				logFile = new File(BASE_DIR + "log/error.log");
				if (startClassName == null && logFile.length() > MAX_LOGFILE_SIZE_SOFT)
					logFile.renameTo(new File(BASE_DIR + "log/error.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());
			determineXposedVersion();
			log("-----------------\n" + date + " UTC\n"
					+ "Loading Xposed v" + XPOSED_BRIDGE_VERSION
					+ " (for " + (startClassName == null ? "Zygote" : startClassName) + ")...");
			if (startClassName == null) {
				// Zygote
				log("Running ROM '" + Build.DISPLAY + "' with fingerprint '" + Build.FINGERPRINT + "'");
			}

			if (initNative()) {
				if (startClassName == null) {
					// Initializations for Zygote
					initXbridgeZygote();
				}

				loadModules(startClassName);
			} else {
				log("Errors during native Xposed initialization");
			}
		} catch (Throwable t) {
			log("Errors during Xposed initialization");
			log(t);
			disableHooks = true;
		}

		// call the original startup code
		if (startClassName == null)
			ZygoteInit.main(args);
		else
			RuntimeInit.main(args);
	}



initNative()函数对一些JNI函数的注册和回调方法的注册,JNI层对应的方法为XposedBridge_initNative,此方法后续会进行分析。


initXbridgeZygote();对Zygote进行初始化,深入探讨一下此函数,由于比较复杂,耐心跟踪一下

private static void initXbridgeZygote() throws Throwable {
		final HashSet<String> loadedPackagesInProcess = new HashSet<String>(1);

		// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
		findAndHookMethod(ActivityThread.class, "handleBindApplication", "android.app.ActivityThread.AppBindData", new XC_MethodHook() {
			protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
				ActivityThread activityThread = (ActivityThread) param.thisObject;
				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 = true;
					return;
				}
				CompatibilityInfo compatInfo = (CompatibilityInfo) getObjectField(param.args[0], "compatInfo");
				if (appInfo.sourceDir == null)
					return;

				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(sLoadedPackageCallbacks);
				lpparam.packageName = appInfo.packageName;
				lpparam.processName = (String) getObjectField(param.args[0], "processName");
				lpparam.classLoader = loadedApk.getClassLoader();
				lpparam.appInfo = appInfo;
				lpparam.isFirstApplication = true;
				XC_LoadPackage.callAll(lpparam);

				if (appInfo.packageName.equals(INSTALLER_PACKAGE_NAME))
					hookXposedInstaller(lpparam.classLoader);
			}
		});

		// system thread initialization
		findAndHookMethod("com.android.server.ServerThread", null,
				Build.VERSION.SDK_INT < 19 ? "run" : "initAndLoop", new XC_MethodHook() {
			@Override
			protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
				loadedPackagesInProcess.add("android");

				LoadPackageParam lpparam = new LoadPackageParam(sLoadedPackageCallbacks);
				lpparam.packageName = "android";
				lpparam.processName = "android"; // it's actually system_server, but other functions return this as well
				lpparam.classLoader = BOOTCLASSLOADER;
				lpparam.appInfo = null;
				lpparam.isFirstApplication = true;
				XC_LoadPackage.callAll(lpparam);
			}
		});

		// when a package is loaded for an existing process, trigger the callbacks as well
		hookAllConstructors(LoadedApk.class, new XC_MethodHook() {
			@Override
			protected void afterHookedMethod(MethodHookParam param) throws Throwable {
				LoadedApk loadedApk = (LoadedApk) param.thisObject;

				String packageName = loadedApk.getPackageName();
				XResources.setPackageNameForResDir(packageName, loadedApk.getResDir());
				if (packageName.equals("android") || !loadedPackagesInProcess.add(packageName))
					return;

				if ((Boolean) getBooleanField(loadedApk, "mIncludeCode") == false)
					return;

				LoadPackageParam lpparam = new LoadPackageParam(sLoadedPackageCallbacks);
				lpparam.packageName = packageName;
				lpparam.processName = AndroidAppHelper.currentProcessName();
				lpparam.classLoader = loadedApk.getClassLoader();
				lpparam.appInfo = loadedApk.getApplicationInfo();
				lpparam.isFirstApplication = false;
				XC_LoadPackage.callAll(lpparam);
			}
		});

		findAndHookMethod("android.app.ApplicationPackageManager", null, "getResourcesForApplication",
				ApplicationInfo.class, new XC_MethodHook() {
			@Override
			protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
				ApplicationInfo app = (ApplicationInfo) param.args[0];
				XResources.setPackageNameForResDir(app.packageName,
					app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir);
			}
		});

		if (!new File(BASE_DIR + "conf/disable_resources").exists()) {
			hookResources();
		} else {
			disableResources = true;
		}
	}





findAndHookMethod是关键,如何hook method,继续往下看

	public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
		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];
		Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));

		return XposedBridge.hookMethod(m, callback);
	}


findAndHookMethod(ActivityThread.class, "handleBindApplication", "android.app.ActivityThread.AppBindData", new XC_MethodHook() );
这里是要find ActivityThread对象中的AppBindData方法,AppBindData在ActivityThread中是一个内部类。


XposedBridge.hookMethod(m, callback);
这句就是把find的method和callback进行关联,用callback替代AppBindData,看一下原理:


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: " + hookMethod.toString());
		} else if (hookMethod.getDeclaringClass().isInterface()) {
			throw new IllegalArgumentException("Cannot hook interfaces: " + hookMethod.toString());
		} else if (Modifier.isAbstract(hookMethod.getModifiers())) {
			throw new IllegalArgumentException("Cannot hook abstract methods: " + hookMethod.toString());
		}

		boolean newMethod = false;
		CopyOnWriteSortedSet<XC_MethodHook> callbacks;
		synchronized (sHookedMethodCallbacks) {
			callbacks = sHookedMethodCallbacks.get(hookMethod);
			if (callbacks == null) {
				callbacks = new CopyOnWriteSortedSet<XC_MethodHook>();
				sHookedMethodCallbacks.put(hookMethod, callbacks);
				newMethod = true;
			}
		}
		callbacks.add(callback);
		if (newMethod) {
			Class<?> declaringClass = hookMethod.getDeclaringClass();
			int slot = (int) getIntField(hookMethod, "slot");

			Class<?>[] parameterTypes;
			Class<?> returnType;
			if (hookMethod instanceof Method) {
				parameterTypes = ((Method) hookMethod).getParameterTypes();
				returnType = ((Method) hookMethod).getReturnType();
			} else {
				parameterTypes = ((Constructor<?>) hookMethod).getParameterTypes();
				returnType = null;
			}

			AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType);
			hookMethodNative(hookMethod, declaringClass, slot, additionalInfo);
		}

		return callback.new Unhook(hookMethod);
	}


1. sHookedMethodCallbacks寻找要hook的method,如果不存在,则新建一个callback和hookmethod进行关联,sHookedMethodCallbacks.put(hookMethod, callbacks);callbacks.add(callback);
2. 如果是新hookmethod,进行hookMethodNative,进入JNI层调用XposedBridge_hookMethodNative


/** 
@function hookMethodNative 将输入的Class中的Method方法的nativeFunc替换为xposedCallHandler 
@para declaredClassIndirect 类对象 
@para slot Method在类中的偏移位置 
*/ 
void XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect,
            jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) {
    // Usage errors?
    if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) {
        dvmThrowIllegalArgumentException("method and declaredClass must not be null");
        return;
    }

    // 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");
        return;
    }

    if (isMethodHooked(method)) {
        // already hooked
        return;
    }

    // Save a copy of the original method and other hook info
    XposedHookInfo* hookInfo = (XposedHookInfo*) calloc(1, sizeof(XposedHookInfo));
    memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct));
    hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect));
    hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect));

    // Replace method with our own code
    SET_METHOD_FLAG(method, ACC_NATIVE);
    method->nativeFunc = &hookedMethodCallback;
    method->insns = (const u2*) hookInfo;
    method->registersSize = method->insSize;
    method->outsSize = 0;

    if (PTR_gDvmJit != NULL) {
        // reset JIT cache
        char currentValue = *((char*)PTR_gDvmJit + MEMBER_OFFSET_VAR(DvmJitGlobals,codeCacheFull));
        if (currentValue == 0 || currentValue == 1) {
            MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true;
        } else {
            ALOGE("Unexpected current value for codeCacheFull: %d", currentValue);
        }
    }
}
分享到:
评论

相关推荐

    xposed-v89-sdk25-x86.zip

    《Xposed框架详解:深入理解xposed-v89-sdk25-x86.zip》 Xposed框架是一款在Android系统上广泛使用的模块化开发工具,它允许开发者通过编写特定的模块来改变系统的功能或应用的行为,而无需修改APK文件。在本文中,...

    xposed api-82

    - **XposedBridge API**:这是Xposed框架的核心接口,包括`IXposedHookLoadPackage`、`IXposedHookZygoteInit`等,它们定义了如何在系统启动或加载应用时执行自定义逻辑。 - **Hook技术**:理解Java反射和Method ...

    xposed-x86 xposed-x86-64

    由于这两种架构的不同,Xposed框架也需要为每个架构提供相应的版本,即“xposed-x86”和“xposed-x86_64”。这确保了框架在不同硬件平台上能够正常运行。 安装Xposed框架的步骤通常包括以下几步: 1. 获取对应架构...

    0积分 Xposed开发必备 api-82.jar

    Xposed提供`XposedBridge.log()`方法用于调试,帮助开发者查看被Hook的方法何时被调用以及传递的参数。 2. **ClassLoader Hook**:这种方法涉及到类加载过程的修改,可以控制哪些类会被加载,或者在类加载后立即...

    xposed-v88-sdk25-x86.zip

    标题 "xposed-v88-sdk25-x86.zip" 提供了关于这个压缩包的重要信息,它是一个针对特定环境的 Xposed 框架版本。Xposed 是一个在 Android 系统上运行的框架,允许用户通过安装模块来修改系统行为,无需root权限。这里...

    xposed-uninstaller-20180117-arm.zip

    而“xposed-uninstaller-20180117-arm.zip”则是专门为Xposed框架提供的卸载工具,适用于基于ARM架构的Android 5.0系统。 在深入探讨Xposed框架之前,我们需要理解Android系统的运行机制。Android系统基于Linux内核...

    xposed-v89-sdk25合集.zip

    xposed-v89-sdk25-arm86与xposed-v89-sdk25-arm64两个版本对应的系统是安卓5.0以上的

    framework-xposed-v89-sdk25-x86

    "framework-xposed-v89-sdk25-x86"这个标题表明这是Xposed框架的一个版本,针对的是Android SDK Level 25(即Android 7.1.1 Nougat)的x86架构设备。下面我们将深入探讨Xposed框架的基本概念、工作原理以及与SDK 25...

    xposed-v89-sdk25-x86.zip和script.sh

    "xposed-v89-sdk25-x86.zip" 文件名表明这是一款针对Android SDK 25(即Android 7.1 Nougat)的Xposed框架版本,适用于x86架构的设备。"script.sh" 文件则可能是一个脚本,用于帮助用户安装或配置Xposed框架。 1. *...

    XPOSED依赖JAR包下载, XposedBridgeApi-82.jar

    内有XposedBridgeApi-82.jar XposedBridgeApi-82-source.jar两个文件 api-82.jar SHA-1:35866b507b360d4789ff389ad7386b6e8bbf6cc4 api-82-source.jar SHA-1:2030f71764b06b2f39fa1a85660690aa834cfd84

    Xposed工具XposedBridgeApi-89.jar

    《Xposed框架与XposedBridgeApi-89.jar详解》 在Android开发领域,Xposed框架是一个极具影响力的神器,它允许开发者通过修改系统的运行时行为,实现对系统和应用的深度定制,而无需修改APK文件。XposedBridgeApi-89...

    xposed 无法自动下载,采用手动用的xposed-v89-sdk22-x86.zip

    "xposed-v89-sdk22-x86.zip"是针对Android SDK 22(即Android 5.1)的Xposed框架的特定版本,适用于x86架构的设备。 首先,我们来详细了解一下Xposed框架的核心功能和工作原理。Xposed框架通过hooking技术在系统层...

    xposed-v88-sdk23-x86.zip

    xposed-v88-sdk23-x86.zip

    XposedBridgeApi-82.jar

    xposed api 82 AndroidManifest.xml &lt;meta-data android:name="xposedmodule" android:value="true" /&gt; &lt;meta-data android:name="xposeddescription" android:value="..." /&gt; &lt;meta-data ...

    XposedBridgeAPI-82.jar

    XposedBridgeApi是一个用于Android系统的库,它允许开发者在不修改应用程序源代码的情况下,通过使用Xposed框架来实现对应用程序的修改和增强。XposedBridgeApi-54提供了一组API,使得开发者可以在运行时动态地修改...

    xposed-v90-sdk26.zip

    在本例中,我们有两个版本的Xposed框架:xposed-v90-sdk26-arm64-beta3.zip和xposed-v90-sdk26-arm-beta3.zip。它们分别适用于基于ARM64架构和ARM架构的Android 8.0设备。选择适合自己设备架构的版本至关重要,因为...

    xposed-api-82-sources

    xposed-api-82-sources resources 资源文件 和xposed-api-82放到同一个文件夹下

    xposed-v78-sdk22-arm64.zip

    标题中的"xposed-v78-sdk22-arm64.zip"指的是Xposed框架的一个特定版本,适用于基于Android SDK 22(Android 5.1 Lollipop)的arm64架构设备,比如MeiZu(魅族)手机。 在Android生态系统中,Xposed框架由Rovo89...

    XposedBridgeApi-54.jar,XposedBridgeApi-87.jar

    XposedBridgeApi是Xposed框架的核心API库,它为开发者提供了与系统底层交互的接口,使得开发者能够实现各种高级功能,如系统级别的Hook、应用程序的定制化修改等。 XposedBridgeApi-54.jar和XposedBridgeApi-87.jar...

Global site tag (gtag.js) - Google Analytics