学了一段时间的XPosed,发现XPosed真的好强,只要技术强,什么操作都能实现...
这次主要记录一下我对这款应用的逆向思路
使用MT管理器检查apk的加壳情况
发现是某数字的免费版本
直接使用frida-dexdump
脱下来后备用
通过对应用的检查发现在添加虚拟机设备的时候用到了会员
权限
同时弹出一个对话框,应用也贴心的告诉我们VIP
的使用场景
打开算法助手,算法助手对应用进行了常见功能的Hook,最重要的是支持免费加固的Hook
将这3项勾选
重复1、2步,在日志中检查OnClick和弹窗是否有用的信息
很幸运,在这一步就获取有关的逻辑
且函数名称并没有被混淆,能够从调用堆栈读出以下逻辑:点击下载按钮->检查是否VIP->用户没有登录->显示购买VIP的弹窗
打开jadx将脱壳后的dex文件载入,搜索checkVip
选择第一个函数,发现无有用信息,继续进入checkVip
函数
在此函数中发现getUserConf,即获取用户的配置
通过对此函数的阅读,得出此函数的返回值为UserBean
然后检查
UserBean
很明显,有关VIP的数据都在此,使用XPosed来修改这些成员变量,即可达到对显示UI的修改,即使服务器对这些数据有校验也不影响,至少在UI层面已经成功了
使用抓包工具检查网络请求,当点击底部的导航栏的时候,应用会发送网络请求
通过检查getInfo
,获取一个Post请求的链接
对此链接进行引用查询,发现有关用户的逻辑
阅读此函数,网络请求库可能为Retrofit,当请求成功的时候会将用户的信息保存起来并移除广告?同样也能得到UserBean
,这个关键的信息
通过对网上公开资料的查询,发现即使应用加固也需要在运行时进行还原修复,使用jadx打开加固的apk文件,找到attachBaseContext
Hook完成后,能够发现nickName
是正确的,能够对应上UI的显示
接下来只需要对循环里的数据进行判断赋值,然后返回即可
获取到VIP
后,发现还有一个插件下载的逻辑没有效果
当点击Root或者XPosed的时候,会提示加载失败
但是点击谷歌服务的时候却有效果,猜测是网络请求
打开抓包工具,通过对两者的对比,发现是其中少了一些数据,所以才会加载失败
在jadx中搜索getPluginUrl
,通过阅读此函数发现有2个匿名函数,failure
和success
使用jadx默认给我们的参数Hook不太行,这时候需要使用其他函数来获取vu
XposedHelpers.findAndHookMethod(
"com.vmos.pro.account.AccountHelper"
, classLoader,
"getUserConf"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super
.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super
.afterHookedMethod(param);
}
});
XposedHelpers.findAndHookMethod(
"com.vmos.pro.account.AccountHelper"
, classLoader,
"getUserConf"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super
.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super
.afterHookedMethod(param);
}
});
XposedHelpers.findAndHookMethod(
"com.stub.StubApp"
, param.classLoader,
"attachBaseContext"
, android.content.Context.
class
, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super
.afterHookedMethod(param);
Context context
=
(Context) param.args[
0
];
/
/
获取运行时的Context
ClassLoader classLoader
=
context.getClassLoader()
/
/
获取真正的ClassLoader
/
/
在此添加Hook VIP等操作,使用classLoader
}
});
XposedHelpers.findAndHookMethod(
"com.stub.StubApp"
, param.classLoader,
"attachBaseContext"
, android.content.Context.
class
, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super
.afterHookedMethod(param);
Context context
=
(Context) param.args[
0
];
/
/
获取运行时的Context
ClassLoader classLoader
=
context.getClassLoader()
/
/
获取真正的ClassLoader
/
/
在此添加Hook VIP等操作,使用classLoader
}
});
XposedHelpers.findAndHookMethod(
"com.vmos.pro.account.AccountHelper"
, classLoader,
"getUserConf"
, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Object
UserBean
=
param.getResult();
for
(Field field : UserBean.getClass().getDeclaredFields()) {
/
/
设置可访问, 极其重要, 不然会崩溃
field.setAccessible(true);
/
/
使用反射来获取运行时的数据
var name
=
field.getName();
var
type
=
field.getType();
var value
=
field.get(UserBean);
Log.i(
"HookTag"
, name
+
": "
+
value);
}
super
.afterHookedMethod(param);
}
});
XposedHelpers.findAndHookMethod(
"com.vmos.pro.account.AccountHelper"
, classLoader,
"getUserConf"
, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Object
UserBean
=
param.getResult();
for
(Field field : UserBean.getClass().getDeclaredFields()) {
/
/
设置可访问, 极其重要, 不然会崩溃
field.setAccessible(true);
/
/
使用反射来获取运行时的数据
var name
=
field.getName();
var
type
=
field.getType();
var value
=
field.get(UserBean);
Log.i(
"HookTag"
, name
+
": "
+
value);
}
super
.afterHookedMethod(param);
}
});
/
/
修改名称,其他自行测试
for
(Field field : UserBean.getClass().getDeclaredFields()) {
......
if
(name.equals(
"nickName"
)) {
field.
set
(UserBean,
"测试文字"
);
}
else
if
(......) {
......
}
}
param.setResult(UserBean);
/
/
设置返回值,替换掉param.getResult()获取的
/
/
修改名称,其他自行测试
for
(Field field : UserBean.getClass().getDeclaredFields()) {
......
if
(name.equals(
"nickName"
)) {
field.
set
(UserBean,
"测试文字"
);
}
else
if
(......) {
......
}
}
param.setResult(UserBean);
/
/
设置返回值,替换掉param.getResult()获取的
/
/
vu<jo4>.
class
无法获取
/
/
使用loadClass来获取,在参数中填写vu即可
Class<?> vu
=
classLoader.loadClass(
"vu"
);
XposedHelpers.findAndHookMethod(
"com.vmos.pro.activities.main.fragments.PluginHelper$getPluginDownloadBean$2$1"
, classLoader,
"success"
, vu, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.i(
"HookTag"
,
"success: "
+
Arrays.toString(param.args));
super
.beforeHookedMethod(param);
}
});
/
/
或者使用XposedBridge.hookAllMethods
/
/
vu<jo4>.
class
无法获取
/
/
使用loadClass来获取,在参数中填写vu即可
Class<?> vu
=
classLoader.loadClass(
"vu"
);
XposedHelpers.findAndHookMethod(
"com.vmos.pro.activities.main.fragments.PluginHelper$getPluginDownloadBean$2$1"
, classLoader,
"success"
, vu, new XC_MethodHook() {
@Override
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2023-10-28 22:46
被墨穹呢编辑
,原因: 格式化