吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3982|回复: 24
收起左侧

[Android 原创] 记一次带壳子的hook体验

[复制链接]
侃遍天下无二人 发表于 2023-3-9 14:01
本帖最后由 侃遍天下无二人 于 2023-3-10 11:30 编辑

如果图裂了请下载pdf查看,下次我会换图床的
记一次带壳子的hook体验.pdf  https://wwpv.lanzoue.com/iuuI90po44qj

记一次带壳子的hook体验

前言

学完正己老师的安卓逆向(七)后,我们知道xposed的hook可以对加壳应用生效。正好NeatReader的安卓端加了360壳,我们就以它为例应用一下对加壳应用的hook。
14f76384075c4effbcd978e88e7ff547.png

NeatReader在安卓端是免费软件,除云存储外没有使用限制。因此本次hook仅实现开启本地会员,使底部的“会员”一栏消失。

准备工作

首先下载32位的NeatReader,将它安装到刷入了fart的手机上脱壳,将所得的dex删掉类重复的(一般也就是大小相同的),并用mt/np做dex修复,然后全部打包到一个zip中,这个zip文件可以直接拖入jadx分析,如下图所示:
b66c0ac139d143db9836c3e80dc58591.png

现在将app安装到pixel2xl上, 这个手机已经root并解锁bl,刷入了Magisk和 lsposed:
d1d2a84d2aa745f6869df127a1afe33f.png
安装好原版app后,可以正常启动,接下来就可以着手分析代码开启本地会员了:
145fc3a610ca4fb9aef2af7077118a9f.png

分析

分析流程与破解无加固的app大同小异,首先搜索会员,看到明显的提示:
a700751368b8443dbf708233326c8fec.png
这一行所在的方法如下:

    private void v3(boolean z7) {
        com.gzhi.neatreader.r2.utils.l lVar = com.gzhi.neatreader.r2.utils.l.f9986a;
        lVar.e("账号切换", "updateBottomNavigationTab");
        if (p2()) {
            lVar.e("账号切换", "已登录");
            if (this.H.i() == 1) {
                lVar.e("账号切换", "VIP_USER 隐藏促销按钮");
                k3();
                return;
            } else if (q2()) {
                lVar.e("账号切换", "FREE_USER 显示促销按钮");
                if (z7) {
                    return;
                }
                if (this.f9896x.getMenu().size() == 5) {
                    if (r2()) {
                        return;
                    }
                    p3(com.gzhi.neatreader.r2.utils.g.f9982a.d(this.H.s().b()));
                    return;
                } else if (this.f9896x.getMenu().size() == 4) {
                    if (this.H.s() == null) {
                        this.f9896x.getMenu().add(0, R.id.im_premium, 4, getString(2131755099));
                    } else {
                        this.f9896x.getMenu().add(0, R.id.im_premium, 4, getString(2131755100));
                        p3(true);
                    }
                    e(4);
                    return;
                } else {
                    return;
                }
            } else {
                return;
            }
        }
        lVar.e("账号切换", "未登录, 显示会员按钮");
        if (z7) {
            return;
        }
        k3();
        this.f9896x.getMenu().add(0, R.id.im_premium, 4, getString(2131755099)).setIcon(R.drawable.ic_main_premium);
        e(4);
    }

分析可以得知p2()用于判断账号是否登录;this.H.i()表示当前账号身份,会员为1。
因此我们需要令 p2() 返回true,令 H.i() 返回1。

hook的代码实现

我们先创建一个NoActivity的项目:
c0e1fef0c15a4f46bfd9ddd326d27752.png
在项目的gradle脚本中增加一行,使后续所有放入 libs的名字带 -api的jar包都能参与编译,且不会被打包:

compileOnly fileTree(include: '*-api.jar', dir: 'libs')

0738ea10216f41bf9149915e318536bc.png
将教程中的 XposedBridge-89.jar 改名为 XposedBridge-89-api.jar 放入 app\libs 目录下,重新用gradle sync同步项目即可完成导包。
然后我们在AndroidManifest中添加元数据:

    <!-- 是否是xposed模块,xposed根据这个来判断是否是模块 -->
    <meta-data
        android:name="xposedmodule"
        android:value="true" />
    <!-- 模块描述,显示在xposed模块列表那里第二行 -->
    <meta-data
        android:name="xposeddescription"
        android:value="给NeatReader开个本地会员" />
    <!-- 最低xposed版本号(lib文件名可知) -->
    <meta-data
        android:name="xposedminversion"
        android:value="89" />

接下来我们新建一个Hook类MyHook,这里相比教程略微做一点变化,我们改为通过反射调用方法来注入hook,因为把所有的hook方法都挂在回调函数里不利于阅读。

public class MyHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if ("com.gzhi.neatreader.r2.main".equals(loadPackageParam.packageName)) {
            // 在attach方法中,可以取得真正的类加载器,而attach本身的加载器是壳代{过}{滤}理的加载器
            XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Context context = (Context) param.args[0];
                    // 这是真正的类加载器
                    ClassLoader classLoader = context.getClassLoader();
                    // 取得当前类下的所有方法
                    Method[] methods = MyHook.class.getDeclaredMethods();
                    // 用反射调用所有以 mod_ 开头, 且只有一个 ClassLoader 作为参数的方法
                    for (Method method : methods) {
                        if (method.getName().startsWith("mod_") && method.getParameterTypes().length == 1 && method.getParameterTypes()[0] == ClassLoader.class) {
                            method.setAccessible(true);
                            method.invoke(MyHook.this, classLoader);
                        }
                    }
                }
            });
        }
    }
}

然后在asset目录下新建xposed_init文件,将类的全限定名粘贴进去:
4d8246094a174130843fd165a9e72074.png
接下来只要在MyHook类中新增符合要求的方法,并将jadx复制的xposed片段粘贴进去就行了:
0e974d2dd29a43c58a6b3e2333965f60.png

如图,这个方法将自己设为已登录状态:
2c2e19cb91e14681a1142043038c295b.png

    private void mod_ILoggedIn(ClassLoader classLoader){
        XposedHelpers.findAndHookMethod("com.gzhi.neatreader.r2.ui.MainActivity", classLoader, "p2", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                param.setResult(true);
            }
        });
    }

同理,这个方法将自己设为会员状态:

    private void mod_IamVIP(ClassLoader classLoader){
        XposedHelpers.findAndHookMethod("com.gzhi.neatreader.r2.utils.SharedPreferenceHelper", classLoader, "i", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                param.setResult(1);
            }
        });
    }

编译安装,然后到管理界面激活模块:
a64a91f7c02f4bcf8805c5b8734f9102.png
激活后再强行停止并重启NeatReader,发现会员一栏已经消失了:
aa74fbe8115e4f60a559ac3df1ea8b91.png

免费评分

参与人数 7威望 +1 吾爱币 +31 热心值 +7 收起 理由
T4DNA + 1 + 1 学习了
junjia215 + 1 + 1 谢谢@Thanks!
话痨司机啊 + 2 + 1 谢谢@Thanks!
superworker2022 + 1 + 1 我很赞同!
正己 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
debug_cat + 2 + 1 大佬牛啤啊
GenW + 4 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 侃遍天下无二人 发表于 2023-3-9 20:29
lvbuqing 发表于 2023-3-9 20:08
360壳子我是hook:com.stub.StubApp,a方法或getOrigApplicationContext;这个类里面的所有参数带context的 ...

正己给的那个是通杀的,也就是不区分壳子,没必要专门再hook壳代{过}{滤}理了
lvbuqing 发表于 2023-3-9 20:08
360壳子我是hook:com.stub.StubApp,a方法或getOrigApplicationContext;这个类里面的所有参数带context的,都可以用,我试过了;
有时间试试你这个:XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {

点评

正己给的那个是通杀的,也就是不区分壳子,没必要专美再hook壳代{过}{滤}理了  详情 回复 发表于 2023-3-9 20:29
Piz.liu 发表于 2023-3-9 14:31
图裂了..

点评

好像真是这样,我这次先传pdf好了,下次换图床  详情 回复 发表于 2023-3-9 14:47

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
侃遍天下无二人 + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| 侃遍天下无二人 发表于 2023-3-9 14:47

好像真是这样,我这次先传pdf好了,下次换图床
debug_cat 发表于 2023-3-9 15:26
貌似平台无法直接加载自己的的储存桶,就算我没有任何限制,平台也加载不出来,只能一个个图片上传,这一点每次发帖最头疼了。

点评

你是改名了吗,评分区的名字还没变过来  详情 回复 发表于 2023-3-9 17:03
wfghim 发表于 2023-3-9 16:41
精彩绝伦,可惜丢图了
 楼主| 侃遍天下无二人 发表于 2023-3-9 17:03
debug_cat 发表于 2023-3-9 15:26
貌似平台无法直接加载自己的的储存桶,就算我没有任何限制,平台也加载不出来,只能一个个图片上传,这一点 ...

你是改名了吗,评分区的名字还没变过来
debug_cat 发表于 2023-3-9 17:09
侃遍天下无二人 发表于 2023-3-9 17:03
你是改名了吗,评分区的名字还没变过来

刚刚站长才修改的,应该有缓存
wasm2023 发表于 2023-3-9 17:52
大佬,能否来几篇pc端协议逆向的案例,群里几乎没有

点评

什么群呀  详情 回复 发表于 2023-3-9 17:58
 楼主| 侃遍天下无二人 发表于 2023-3-9 17:58
wasm2023 发表于 2023-3-9 17:52
大佬,能否来几篇pc端协议逆向的案例,群里几乎没有

什么群呀
wasm2023 发表于 2023-3-9 17:59
打错了,是咱论坛几乎没有
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 07:50

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表