首页
社区
课程
招聘
【Android逆向】记录一次某某虚拟机的逆向
发表于: 2023-10-28 22:45 15078

【Android逆向】记录一次某某虚拟机的逆向

2023-10-28 22:45
15078

学了一段时间的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个匿名函数,failuresuccess

使用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

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-10-28 22:46 被墨穹呢编辑 ,原因: 格式化
收藏
免费 8
支持
分享
最新回复 (11)
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-10-28 23:28
1
雪    币: 3546
活跃值: (3930)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
大佬,厉害。
2023-10-29 11:35
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
userbean里面哪个字段是控制会员的
2023-10-30 14:20
0
雪    币: 1335
活跃值: (1435)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
是不是不开谷歌服务就不用处理最后的问题?
2023-11-1 09:32
0
雪    币: 2073
活跃值: (2627)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
mb_fidppcok 是不是不开谷歌服务就不用处理最后的问题?
不使用Root和XPosed插件后面的不用管
2023-11-1 10:05
0
雪    币: 147
活跃值: (500)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我没太看懂,有壳加固,所以hook哪个函数?
2023-11-1 10:56
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
我没太看懂,有壳加固,所以hook哪个函数?
2023-11-1 13:35
0
雪    币: 2073
活跃值: (2627)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
OYyunshen 我没太看懂,有壳加固,所以hook哪个函数?
attachBaseContext
2023-11-1 15:47
0
雪    币: 478
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
壳和函数没关系,你用xposed,就不用管壳了,壳只要能脱出来,能看到代码就行了,你又不用重新塞进去。
2023-11-9 00:42
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
支持一下 不过也不得不吐糟一下:能写出Vmos Pro的团队一定有着顶尖的开发实力 对安卓底层必定是了如指掌 如数家珍 但在安全这块儿却拉垮得令人震惊 让人没话说
2023-11-13 20:54
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
万里星河 支持一下 不过也不得不吐糟一下:能写出Vmos Pro的团队一定有着顶尖的开发实力 对安卓底层必定是了如指掌 如数家珍 但在安全这块儿却拉垮得令人震惊 让人没话说[em_26]
或许这是对于勇者的奖励
2023-11-23 12:44
1
游客
登录 | 注册 方可回帖
返回
//