那些年的Xposed开发经验记录

把之前写的Xposed相关文章合并到一块,方便查阅

多进程App的Hook问题

以及App中单个方法被多个模块Hook时的Hook代码优先级问题

XposedHelper中的静态变量

在这里插入图片描述

demo的AndroidManifest.xml的测试核心代码

        <activity
            android:name=".ProcessActivity"
            android:process=":process"></activity>//私有进程
        <activity
            android:name=".PublicProcessActivity"
            android:process="com.publicProcess">//公共进程

        </activity>

结论

以下"所有进程"都包括应用内创建的私有进程和公共进程
经过测试[测试代码过多就不贴了],得出结论:
1.所有进程的创建都会执行而且会多次执行handleLoadPackage函数;
2.每个进程都会重新创建一个fieldCache,methodCache,constructorCache静态变量;
3.若两个模块Hook了当前App的同一个函数则beforeHookedMethod执行顺序是按Xposed框架私有目录下conf/modules.list的顺序执行的,afterHookedMethod则与beforeHookedMethod执行顺序相反[测试数据是这样的,具体真实情况就不太想探究了,应该90%正确],举个例子:

模块A和模块B同时Hook了应用C的方法D,modules.list中模块A比模块B的顺序靠前,则Hook代码执行顺序为:
A->beforeHookedMethod,B->beforeHookedMethod,D,B->afterHookedMethod,A->afterHookedMethod

4.lpparam.isFirstApplication并不是仅仅在主进程执行handleLoadPackage函数时才会置为true,在所有进程执行该函数时都会置为true[测试数据是这样的,具体真实情况就不太想探究了,应该90%正确];
5.在App的一个进程A中对某函数进行Hook只会影响进程A执行该函数,不会影响该App其它未被Hook的进程执行该函数。

限制handleLoadPackage被单个进程多次执行的问题

    /**
     *防止重复执行Hook代码
     * @param flag 判断标识,针对不同Hook代码分别进行判断
     * @return 是否已经注入Hook代码
     */
    private boolean isInjecter(String flag) {
        try {
            if (TextUtils.isEmpty(flag)) return false;
            Field methodCacheField = XposedHelpers.class.getDeclaredField("methodCache");
            methodCacheField.setAccessible(true);
            HashMap<String, Method> methodCache = (HashMap<String, Method>) methodCacheField.get(null);
            Method method=XposedHelpers.findMethodBestMatch(Application.class,"onCreate");
            String key=String.format("%s#%s",flag,method.getName());
            if (methodCache.containsKey(key)) return true;
            methodCache.put(key, method);
            return false;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return false;
    }

在handleLoadPackage做判断


    @Keep
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
            if (isInjecter(this.getClass().getName())) {
                return;
            }
            //hook代码
}

多dex Hook问题

//解决多dex问题
    public static void findHideDex(final OnFindDexListener listener) {
        XposedBridge.hookAllMethods(ContextWrapper.class, "attachBaseContext", new XC_MethodHook() {

            public void beforeHookedMethod(MethodHookParam param) {
                ClassLoader classLoader = ((Context) param.args[0]).getClassLoader();
                if (classLoader == null) return;
                if (listener != null) listener.onFind(classLoader);
            }
        });
        XposedBridge.hookAllConstructors(ClassLoader.class, new XC_MethodHook() {
            public void beforeHookedMethod(MethodHookParam param) {
                ClassLoader classLoader = (ClassLoader) param.args[0];
                if (classLoader == null) return;
                if (listener != null) listener.onFind(classLoader);
            }
        });
    }
public interface OnFindDexListener {
        void onFind(ClassLoader classLoader);
    }

为应用增加权限

利用Xposed删除权限

这个已经有人实现了,就是Xposed的作者,我们就先来研究研究他是怎么实现的,先上他的实现代码

public class PackagePermissions extends BroadcastReceiver {
	private final Object pmSvc;
	private final Map<String, Object> mPackages;
	private final Object mSettings;

	@SuppressWarnings("unchecked")
	public PackagePermissions(Object pmSvc) {
		this.pmSvc = pmSvc;
		this.mPackages = (Map<String, Object>) getObjectField(pmSvc, "mPackages");
		this.mSettings = getObjectField(pmSvc, "mSettings");
	}

/*这个函数主要hook了 PackageManager 服务(负责系统中Package的管理,应用程序的安装、卸载、信息查询),实现了通过监听我们自己发出的广播,拦截权限授予功能来进行修改apk的权限的*/
	public static void initHooks() {
		try {
			final Class<?> clsPMS = findClass("com.android.server.pm.PackageManagerService", XposedMod.class.getClassLoader());//获取这个PackageManager类

			//注册监听广播,监听我们的设置更改,以实现立即应用设置
			findAndHookMethod(clsPMS, "systemReady", new XC_MethodHook() {
				@Override
				protected void afterHookedMethod(MethodHookParam param)
						throws Throwable {
					Context mContext = (Context) getObjectField(param.thisObject, "mContext");//这个应该是系统的上下文,具体待研究
					mContext.registerReceiver(new PackagePermissions(param.thisObject),
							new IntentFilter(Common.MY_PACKAGE_NAME + ".UPDATE_PERMISSIONS"),
							Common.MY_PACKAGE_NAME + ".BROADCAST_PERMISSION",
							null);//注册广播
				}
			});

//拦截PackageManager类中的grantPermissionsLPw函数
			findAndHookMethod(clsPMS, "grantPermissionsLPw", "android.content.pm.PackageParser$Package", boolean.class,
					new XC_MethodHook() {
				@SuppressWarnings("unchecked")
				@Override
				protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
					String pkgName = (String) getObjectField(param.args[0], "packageName");
					if (!XposedMod.isActive(pkgName) || !XposedMod.prefs.getBoolean(pkgName + Common.PREF_REVOKEPERMS, false))
						return;

					Set<String> disabledPermissions = XposedMod.prefs.getStringSet(pkgName + Common.PREF_REVOKELIST, null);
					if (disabledPermissions == null || disabledPermissions.isEmpty())
						return;

					ArrayList<String> origRequestedPermissions = (ArrayList<String>) getObjectField(param.args[0], "requestedPermissions");
					param.setObjectExtra("orig_requested_permissions", origRequestedPermissions);

					ArrayList<String> newRequestedPermissions = new ArrayList<String>(origRequestedPermissions.size());
					for (String perm: origRequestedPermissions) {
						if (!disabledPermissions.contains(perm))
							newRequestedPermissions.add(perm);
						else
							// you requested those internet permissions? I didn't read that, sorry
							Log.w(Common.TAG, "Not granting permission " + perm
									+ " to package " + pkgName
									+ " because you think it should not have it");
					}

					setObjectField(param.args[0], "requestedPermissions", newRequestedPermissions);
				}

				@SuppressWarnings("unchecked")
				@Override
				protected void afterHookedMethod(MethodHookParam param) throws Throwable {
					// restore requested permissions if they were modified
					ArrayList<String> origRequestedPermissions = (ArrayList<String>) param.getObjectExtra("orig_requested_permissions");
					if (origRequestedPermissions != null)
						setObjectField(param.args[0], "requestedPermissions", origRequestedPermissions);
				}
			});
		} catch (Throwable e) {
			XposedBridge.log(e);
		}
	}

	@Override
	public void onReceive(Context context, Intent intent) {
		try {
			// The app broadcasted a request to update settings for a running app

			// Validate the action being requested
			if (!Common.ACTION_PERMISSIONS.equals(intent.getExtras().getString("action")))
				return;

			String pkgName = intent.getExtras().getString("Package");
			boolean killApp = intent.getExtras().getBoolean("Kill", false);

			XposedMod.prefs.reload();

			Object pkgInfo;
			synchronized (mPackages) {
				pkgInfo = mPackages.get(pkgName);
				callMethod(pmSvc, "grantPermissionsLPw", pkgInfo, true);
				callMethod(mSettings, "writeLPr");
			}

			// Apply new permissions if needed
			if (killApp) {
				try {
					ApplicationInfo appInfo = (ApplicationInfo) getObjectField(pkgInfo, "applicationInfo");
					if (Build.VERSION.SDK_INT <= 18)
						callMethod(pmSvc, "killApplication", pkgName, appInfo.uid);
					else
						callMethod(pmSvc, "killApplication", pkgName, appInfo.uid, "apply App Settings");
				} catch (Throwable t) {
					XposedBridge.log(t);
				}
			}
		} catch (Throwable t) {
			XposedBridge.log(t);
		}
	}
}

这段代码的地址

参考

1.AppSettingshook权限代码
2.Android5.1.1源码 - 添加应用权限

Hook框架集锦

在这里插入图片描述

原始思维导图文件下载

ProcessOnAndroid-Hook框架集锦.pos

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jitcor

觉得有用,不赏点?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值