把之前写的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源码 - 添加应用权限