记一次带壳子的hook体验

查看 64|回复 4
作者:guohuanxian   
如果图裂了请下载pdf查看,下次我会换图床的
记一次带壳子的hook体验.pdf  https://wwpv.lanzoue.com/iuuI90po44qj记一次带壳子的hook体验
前言
学完正己老师的安卓逆向(七)后,我们知道xposed的hook可以对加壳应用生效。正好NeatReader的安卓端加了360壳,我们就以它为例应用一下对加壳应用的hook。

NeatReader在安卓端是免费软件,除云存储外没有使用限制。因此本次hook仅实现开启本地会员,使底部的“会员”一栏消失。
准备工作
首先下载32位的NeatReader,将它安装到刷入了fart的手机上脱壳,将所得的dex删掉类重复的(一般也就是大小相同的),并用mt/np做dex修复,然后全部打包到一个zip中,这个zip文件可以直接拖入jadx分析,如下图所示:

现在将app安装到pixel2xl上, 这个手机已经root并解锁bl,刷入了Magisk和 lsposed:

安装好原版app后,可以正常启动,接下来就可以着手分析代码开启本地会员了:

分析
分析流程与破解无加固的app大同小异,首先搜索会员,看到明显的提示:

这一行所在的方法如下:
    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的项目:

在项目的gradle脚本中增加一行,使后续所有放入 libs的名字带 -api的jar包都能参与编译,且不会被打包:
compileOnly fileTree(include: '*-api.jar', dir: 'libs')

将教程中的 XposedBridge-89.jar 改名为 XposedBridge-89-api.jar 放入 app\libs 目录下,重新用gradle sync同步项目即可完成导包。
然后我们在AndroidManifest中添加元数据:
   
   
   
   
   
   
接下来我们新建一个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文件,将类的全限定名粘贴进去:

接下来只要在MyHook类中新增符合要求的方法,并将jadx复制的xposed片段粘贴进去就行了:

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

    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);
            }
        });
    }
编译安装,然后到管理界面激活模块:

激活后再强行停止并重启NeatReader,发现会员一栏已经消失了:

在这里, 插入图片

Piz.liu   

太棒了,谢谢
莫问刀   

图裂了..
莫问刀   


Piz.liu 发表于 2023-3-9 14:31
图裂了..

好像真是这样,我这次先传pdf好了,下次换图床
莫问刀   

貌似平台无法直接加载自己的的储存桶,就算我没有任何限制,平台也加载不出来,只能一个个图片上传,这一点每次发帖最头疼了。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部