修改属性
本章主要使用Xposed来修改类和类对象的属性
Xposed不止是可以实现对app自己实现的类构造函数进行hook,对于系统框架层的java函数也可以进行hook
加壳厂商一般使用的加载dex有,DexClassLoader、InMemoryDexClassLoader(8.0以后)、以及动态下发dex
我们先来看一下DexClassLoader
可以使用google提供的源码查看工具 查看源码
- 我们完全可以像hook其它app一样去hook源码中的函数
- 从而可以监控到它都加载了哪些插件dex,或者通过它脱壳都是可以的
- 之后也可以把FART和Xposed结合一下,通过Xposed去hook相关的构造函数,配合FART进行插件dex的脱壳和修复
Hook DexClassLoader
之前在JNI开发的时候写过一个测试demo使用DexClassLoader来动态加载dex这次我们来Hook它的DexClassLoader
方法
主要代码片段
// 在图一的源码里面可以看到DexClassLoader里面一共有四个参数(三个String + ClassLoader)
XposedHelpers.findAndHookConstructor(DexClassLoader.class, String.class, String.class, String.class, ClassLoader.class, new XC_MethodHook() {
@Override
// public Object thisObject;
// public Object[] args;
// private Object result = null;
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object args[] = param.args;
String dexPath = (String) args[0];
String optimizedDirectory = (String) args[1];
String librarySearchPath = (String) args[2];
ClassLoader parent = (ClassLoader) args[3];
XposedBridge.log("HookDexClassLoader->beforeHookedMethod: " + dexPath + "---" + optimizedDirectory + "---" + librarySearchPath + "---" + parent);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
DexClassLoader dexClassLoader = (DexClassLoader) param.thisObject;
XposedBridge.log("HookDexClassLoader->afterHookedMethod: " + dexClassLoader);
}
});
将这个插件编译后安装在设备上,在执行LoadDex的时候就会获取到通过DexClassLoader
加载的dex文件信息
这样就可以获取到加载的dex信息
Xposed除了可以实现对app自己实现的类构造函数的hook,对于系统框架层的java函数也可以进行hook
Xposed插件修改类属性有两种办法
- 使用java反射修改属性:这种方式跟之前的章节中JNI开发中使用的api是一样的
- 使用Xposed的API修改属性:这种方式在内部其实也是调用的java反射的api来完成的,不过它里面已经封装过了我们调用起来比较简洁
// 1. 使用java反射修改属性
ClassLoader pathClassLoader = loadPackageParam.classLoader;
Class stuClass = pathClassLoader.loadClass("com.xiaoeryu.xposedhook01.Student");
XposedBridge.log("stuClass: " + stuClass.getName());
Field teacherField = stuClass.getDeclaredField("teacher");
teacherField.setAccessible(true); // 这里如果是私有属性需要取消权限检查
teacherField.set(null, "xiaoeryu666");
String teacherName1 = (String) teacherField.get(null);
XposedBridge.log("teacherField: " + teacherName1);
// 2. 使用Xposed的API修改属性
// setStaticObjectField(Class<?> clazz, String fieldName, Object value)
XposedHelpers.setStaticObjectField(stuClass, "teacher", "xiaoeryu888");
String teacherName2 = (String) XposedHelpers.getStaticObjectField(stuClass, "teacher");
XposedBridge.log("XposedHelpers.getStaticObjectField: " + teacherName2);
- 使用Xposed的api来获取属性就不需要我们自己来处理权限检查的问题了,框架里面已经帮我们处理过了
- 这里可以看到我们分别使用两种都能获取和修改其属性
看一下LSPosed的源码,使用的setStaticObjectField
方法,是怎么处理私有属性的权限检查的
在github上打开LSPposed的仓库直接搜我们调用的setStaticObjectField
看它是怎么实现的
- 可以看到调用了
findField
跟进去看一下
- 这里也是调用了
setAccessible
来通过权限检查
修改对象属性
使用java反射的方式修改
跟之前使用反射修改属性的代码差不多,也是通过类找到对象修改它的值。这里修改的时候需要传入对象
Field nicknameField = stuClass.getDeclaredField("nickname");
nicknameField.setAccessible(true);
nicknameField.set(thisObj, "bear");
在apk这边可以打印出来查看
使用Xposed的方式修改
XposedHelpers.setObjectField(thisObj,"nickname","duck");
- 使用Xposed的api来修改非常的简介只需要一行代码就可以了,传入对象、要修改的Field、修改后的值
同样在apk那边可以看到打印的结果
setObjectField
的源码跟之前setStaticObjectField
相比需要传入一个obj。都同样是调用了findField
方法
测试
接下来我们拿一个测试app来尝试通过Xposed的方式通过它的验证
用jadx打开查看一下
- 首先这里会拿到我们在编辑框输入的字符串进行check,如果通过就弹出Congratulations
- 如果没有通过,就弹出Sorry,try again?
看一下check
的验证过程
- 首先要我们输入的字符串长度等于16
- 然后还要拿我们输入的content跟**Flag2()**进行字符串对比
- Flag2()是一个无参的构造函数
- 但是Flag2的长度不足16位
所以这里是不存在正确的Flag的,这里使用Xposed的方式hook这两处,使校验通过
public class HookFlag implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
XposedBridge.log("HookFlag->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedflag")) {
XposedBridge.log("HookFlag->app packagename" + loadPackageParam.packageName);
// 修改第一处校验的长度
ClassLoader classLoader = loadPackageParam.classLoader;
Class Flag1Class = classLoader.loadClass("com.kanxue.xposedflag.Flag1");
XposedHelpers.setStaticIntField(Flag1Class, "length", 3);
// 第二处是一个无参的构造函数,修改里面flag的值
XposedHelpers.findAndHookConstructor("com.kanxue.xposedflag.Flag2", classLoader, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("xiaoeryu->beforeHookedMethod");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("xiaoeryu->afterHookedMethod");
Object Flag2obj = param.thisObject;
XposedHelpers.setObjectField(Flag2obj, "flag", "123");
}
});
}
}
}
- 这里修改了两处校验的值,第一处是一个静态变量直接修改即可
- 第二处是一个无参的构造函数用
findAndHookConstructor
方法在afterHookedMethod
之后修改它的值
验证
在LSPosed中勾选上我们要测试的app,然后重启手机
重启后直接运行目标app,将刚刚修改后的值输入进去
验证通过
- 标题: 修改属性
- 作者: xiaoeryu
- 创建于 : 2023-12-11 01:29:52
- 更新于 : 2023-12-13 15:37:46
- 链接: https://github.com/xiaoeryu/2023/12/11/修改属性/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。