OrientalGlass 发表于 2024-8-19 21:35

Android逆向实战-FridaHook破解极简记账VIP



# 前言

**本文中所有内容仅供研究与学习使用,请勿用于任何商业用途和非法用途,否则后果自负!**

最近在学习frida,平常用极简记账记录日常流水,正好实战一波VIP破解

样本使用了360加固,但java代码没有混淆,总体难度不大适合新手上路

基本思路:

1. 通过vip相关组件定位关键代码所在类
2. frida打印关键代码所在类信息
3. dump dex文件,分析关键代码
4. hook vip判断逻辑

# 一. 相关环境

测试机: Pixel 3XL Android12

主机环境: Windows10 frida-16.0.19 python3.10 Java8

相关工具: MT管理器 Jeb4.32

App版本: 2.4.4 (360加固)

# 二. VIP代码定位

使用MT管理器记录活动,点击已经购买,定位vip检测的相关类

可以发现关键类为**com.luyun.simpleaccout.ui.VipActivity**



使用frida hook打印VipActivity相关信息

```js
function main(){
    Java.perform(function (){
      Java.choose("com.luyun.simpleaccout.ui.VipActivity",{
            onMatch:function(instance){
                console.log("instance:",instance);
                var methods=instance.class.getDeclaredMethods();            //方法
                var fields=instance.class.getDeclaredFields();            //字段
                console.log("\n==========methods==========");
                for(let i=0;i<methods.length;i++){
                  var methodParams=methods.getParameterTypes()
                  var methodReturnType=methods.getReturnType()
                  var methodName=methods.getName();
                  console.log(methodReturnType+" "+methodName+"("+methodParams+")");
                }
                console.log("\n==========fields==========");
                for(let i=0;i<fields.length;i++){
                  var fieldName=fields.getName();
                  var fieldType=fields.getType();
                  var fieldValue=instance.value;
                  console.log(fieldType,fieldName,"=",fieldValue);
                }
            },
            onComplete:function(instance){
            }
      })
    })
}
setTimeout(main,500)

```

发现和支付/vip相关的几个方法



# 三. DumpDex

使用frida-dexdump 拉取dex文件



将所有dex文件拖进jeb工具分析(jadx无法正确反编译VipActivity相关部分代码)

# 四. 代码分析

反编译完成后搜索VipActivity,发现alreadyBuy()方法,该方法即为点击"已经购买"后的检测方法

内部主要通过调用isVip()判断是否为vip用户



跟进发现isVip方法是继承自BaseActivity

该方法内部目测是向服务器拉取vip的起始和终止时间判断是否为有效vip,最终返回值为bool类型



VipActivity中还能看到getVipType()不同返回值对应的vip类型

type=0时未解锁,type=1时可续订,type=2时是永久vip



最初hook了VipActivity的isVip()和getVipType()方法,发现ui显示为永久会员但是仍然需要解锁

于是搜索所有isVip()和getVipType()方法实现





# 五. Hook脚本

将以上所有类的isVip和getVipType方法实现全部hook

```js
function main(){
    Java.perform(function (){
      var baseActivity=Java.use("com.luyun.simpleaccout.ui.BaseActivity")
      baseActivity.isVip.implementation=function(){
            console.log("Hook isVip() method!Origin result=",this.isVip())
            return true;
      }
      baseActivity.getVipType.implementation=function(){
            console.log("Hook getVipType() method!Origin result=",this.getVipType())
            return 2;
      }
      var baseFragment=Java.use("com.luyun.simpleaccout.ui.fragment.BaseFragment")
      baseFragment.isVip.implementation=function(){
            console.log("Hook BaseFragment isVip() Succeeded!Origin result=",this.isVip());
            return true;
      }
      baseFragment.getVipType.implementation=function(){
            console.log("Hook BaseFragment getVipType() Succeeded!Origin result=",this.getVipType())
            return 2;
      }
      var splashActivity=Java.use("com.luyun.simpleaccout.ui.SplashActivity");
      splashActivity.isVip.implementation=function(){
            console.log("Hook SplashActivity isVip() Succeeded!Origin result=",this.isVip());
            return true;
      }
      var accountWidgetProvider=Java.use("com.luyun.simpleaccout.provider.AccountWidgetProvider")
      accountWidgetProvider.isVip.implementation=function(){
            console.log("Hook AccountWidgetProvider isVip() Succeeded!Origin result=",this.isVip());
            return true;
      }
    })
}
setTimeout(main,500)

```

# 六. 效果演示

Hook成功,并且是永久会员



vip的导出账本功能正常使用

林伊轩 发表于 2024-9-16 18:38

经过下面这个网站的学习,可算是把frida的js脚本移植到xposed中了.

https://forum.butian.net/share/2248

// 解决动态加载dex文件hook不到问题
      XposedHelpers.findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//                XposedBridge.log(TAG + " clazz => " + clazz);
                Class<?> clazz = (Class<?>) param.getResult();
                if (clazz != null) {
                  switch (clazz.getName()) {
                        case "com.luyun.simpleaccout.ui.SplashActivity":
                            XposedBridge.hookAllMethods(clazz, "isVip", new XC_MethodHook() {
                              @Override
                              protected void afterHookedMethod(MethodHookParam param) {
                                    XposedBridge.log(TAG + "Hook SplashActivity isVip()");
                                    Object context = XposedHelpers.callMethod(param.thisObject, "getApplicationContext");
                                    Class<?> sharedPreferencesUtilsClass = XposedHelpers.findClass("com.luyun.simpleaccout.utils.SharedPreferencesUtils", loadPackageParam.classLoader);
                                    Class<?> stubAppClass = XposedHelpers.findClass("com.stub.StubApp", loadPackageParam.classLoader);
                                    Object applicationContext = XposedHelpers.callStaticMethod(stubAppClass, "getOrigApplicationContext", context);
                                    Object paramValue = XposedHelpers.callStaticMethod(sharedPreferencesUtilsClass, "getParam", applicationContext, "is_privacy_show", Boolean.valueOf(false));
                                    boolean bl = (Boolean) XposedHelpers.callMethod(paramValue, "booleanValue");
                                    XposedBridge.log(TAG + " Hook SplashActivity isVip() Succeeded! Origin result=" + param.getResult() + " bl=" + bl);
                                    param.setResult(bl);
                              }
                            });
                            XposedBridge.hookAllMethods(clazz, "popPrivacyDialog", new XC_MethodHook() {
                              @Override
                              protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                    XposedBridge.log(TAG + " Hook popPrivacyDialog 确认弹窗,执行相关初始化操作并跳转到主界面");
                                    Object context = XposedHelpers.callMethod(param.thisObject, "getApplicationContext");
                                    Class<?> sharedPreferencesUtilsClass = XposedHelpers.findClass("com.luyun.simpleaccout.utils.SharedPreferencesUtils", loadPackageParam.classLoader);
                                    Class<?> stubAppClass = XposedHelpers.findClass("com.stub.StubApp", loadPackageParam.classLoader);
                                    Object origContext = XposedHelpers.callStaticMethod(stubAppClass, "getOrigApplicationContext", context);
                                    XposedHelpers.callStaticMethod(sharedPreferencesUtilsClass, "setParam", origContext, "is_privacy_show", true);
                                    XposedBridge.log(TAG + " SharedPreferencesUtils.setParam() 已执行");
                                    XposedHelpers.callMethod(param.thisObject, "goToMainActivity");
                                    param.setResult(null);
                              }
                            });
                  }
                }
            }
      });
    }

林伊轩 发表于 2024-9-16 14:41

为什么这个代码转成xp框架代码的时候,报错,提示找不到对应的类,好奇怪

LSPosed-Bridge      EKWs.VughjCuW.z.gAm.sQH.XposedHelpers$ClassNotFoundError: java.lang.ClassNotFoundException: com.luyun.simpleaccout.ui.SplashActivity
                                                     at KWs.VughjCuW.z.gAm.sQH.XposedHelpers.findClass(Unknown Source:12)
                                                     at KWs.VughjCuW.z.gAm.sQH.XposedHelpers.findAndHookMethod(SourceFile:6)
                                                     at yuu.xposed.jjjz.Hook.handleLoadPackage(Hook.java:20)
                                                     at KWs.VughjCuW.z.gAm.sQH.IXposedHookLoadPackage$Wrapper.handleLoadPackage(Unknown Source:2)
                                                     at KWs.VughjCuW.z.gAm.sQH.callbacks.XC_LoadPackage.call(Unknown Source:6)
                                                     at KWs.VughjCuW.z.gAm.sQH.callbacks.XCallback.callAll(Unknown Source:26)
                                                     at h0.a(Unknown Source:320)
                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                     at J.callback(Unknown Source:253)
                                                     at LSPHooker_.createOrUpdateClassLoaderLocked(Unknown Source:11)
                                                     at android.app.LoadedApk.getClassLoader(LoadedApk.java:810)
                                                     at android.app.LoadedApk.getResources(LoadedApk.java:1032)
                                                     at android.app.ContextImpl.createAppContext(ContextImpl.java:2345)
                                                     at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5907)
                                                     at android.app.ActivityThread.access$1100(ActivityThread.java:207)
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1663)
                                                     at android.os.Handler.dispatchMessage(Handler.java:106)
                                                     at android.os.Looper.loop(Looper.java:193)
                                                     at android.app.ActivityThread.main(ActivityThread.java:6840)
                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:860)
                                             Caused by: java.lang.ClassNotFoundException: com.luyun.simpleaccout.ui.SplashActivity
                                                     at java.lang.Class.classForName(Native Method)
                                                     at java.lang.Class.forName(Class.java:470)
                                                     at q.a(Unknown Source:16)
                                                     at KWs.VughjCuW.z.gAm.sQH.XposedHelpers.findClass(Unknown Source:4)
                                                     at KWs.VughjCuW.z.gAm.sQH.XposedHelpers.findAndHookMethod(SourceFile:6) 
                                                     at yuu.xposed.jjjz.Hook.handleLoadPackage(Hook.java:20) 
                                                     at KWs.VughjCuW.z.gAm.sQH.IXposedHookLoadPackage$Wrapper.handleLoadPackage(Unknown Source:2) 
                                                     at KWs.VughjCuW.z.gAm.sQH.callbacks.XC_LoadPackage.call(Unknown Source:6) 
                                                     at KWs.VughjCuW.z.gAm.sQH.callbacks.XCallback.callAll(Unknown Source:26) 
                                                     at h0.a(Unknown Source:320) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                     at J.callback(Unknown Source:253) 
                                                     at LSPHooker_.createOrUpdateClassLoaderLocked(Unknown Source:11) 
                                                     at android.app.LoadedApk.getClassLoader(LoadedApk.java:810) 
                                                     at android.app.LoadedApk.getResources(LoadedApk.java:1032) 
                                                     at android.app.ContextImpl.createAppContext(ContextImpl.java:2345) 
                                                     at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5907) 
                                                     at android.app.ActivityThread.access$1100(ActivityThread.java:207) 
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1663) 
                                                     at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                     at android.os.Looper.loop(Looper.java:193) 
                                                     at android.app.ActivityThread.main(ActivityThread.java:6840) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:860) 
                                             Caused by: java.lang.ClassNotFoundException: Didn't find class "com.luyun.simpleaccout.ui.SplashActivity" on path: DexPathList[,nativeLibraryDirectories=]
                                                     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
                                                     at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
                                                     at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                                                     at java.lang.Class.classForName(Native Method) 
                                                     at java.lang.Class.forName(Class.java:470) 
                                                     at q.a(Unknown Source:16) 
                                                     at KWs.VughjCuW.z.gAm.sQH.XposedHelpers.findClass(Unknown Source:4) 
                                                     at KWs.VughjCuW.z.gAm.sQH.XposedHelpers.findAndHookMethod(SourceFile:6) 
                                                     at yuu.xposed.jjjz.Hook.handleLoadPackage(Hook.java:20) 
                                                     at KWs.VughjCuW.z.gAm.sQH.IXposedHookLoadPackage$Wrapper.handleLoadPackage(Unknown Source:2) 
                                                     at KWs.VughjCuW.z.gAm.sQH.callbacks.XC_LoadPackage.call(Unknown Source:6) 
                                                     at KWs.VughjCuW.z.gAm.sQH.callbacks.XCallback.callAll(Unknown Source:26) 
                                                     at h0.a(Unknown Source:320) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                     at J.callback(Unknown Source:253) 
                                                     at LSPHooker_.createOrUpdateClassLoaderLocked(Unknown Source:11) 
                                                     at android.app.LoadedApk.getClassLoader(LoadedApk.java:810) 
                                                     at android.app.LoadedApk.getResources(LoadedApk.java:1032) 
                                                     at android.app.ContextImpl.createAppContext(ContextImpl.java:2345) 
                                                     at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5907) 
                                                     at android.app.ActivityThread.access$1100(ActivityThread.java:207) 
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1663) 
                                                     at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                     at android.os.Looper.loop(Looper.java:193) 
                                                     at android.app.ActivityThread.main(ActivityThread.java:6840) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:860) 

cuteapi 发表于 2024-8-20 10:44

推荐使用beancount,复式记账,相当好用

332378834 发表于 2024-8-20 12:02

看看好不好,学习一下

xiaobaixuepj 发表于 2024-8-20 13:00

感谢分享,学习

Mathziw1c 发表于 2024-8-20 13:54

最近也遇到类似的apk,这就试验一下

helel223 发表于 2024-8-20 14:27

牛批,刚好在学习frida,我也去试一下

dph5199278 发表于 2024-8-20 14:52

谢谢分享,学习了

MrYuxuan 发表于 2024-8-20 14:57

学习到了,感谢楼主分享

聪本 发表于 2024-8-20 20:42

cuteapi 发表于 2024-8-20 10:44
推荐使用beancount,复式记账,相当好用

这个安卓好像不方便下载把

rEtb1Te 发表于 2024-8-21 08:39

感谢分享。
我有一个问题想问一下:最后给出的hook脚本,需要如何运行?比方说是将该段代码嵌入到原本的代码中,再打包运行?还是有别的运行方式呢?
页: [1] 2 3 4
查看完整版本: Android逆向实战-FridaHook破解极简记账VIP