Android frida 实战: 分析全民K歌的判断逻辑

本篇进入 Android frida 实战,旨在分析学习全民K歌这个 app 演唱页面的判断逻辑。
版本:8.22.38.278


此 app 为腾讯推出的面向国内的社交娱乐类应用软件,主要功能是提供用户唱歌、录制和分享自己演唱的歌曲。当非 vip 用户演唱某 vip 歌曲等功能时便会触发弹窗,阻止用户使用其功能。

我们进入演唱页面,点击切换音质,触发 vip 弹窗。

借助算法助手,找到点击事件的回调类:e51.a

查看其 smali 代码,一路跟踪 onlick 方法,可以看到 onclick 调用了 e51.e的 V 方法,最终来到了 n0 这个方法处。


省略复杂且漫长的追堆栈过程,最终弹窗在 com.tencent.tme.record.module.vip.RecordPrivilegeAccountModule这个类的 M0方法中被触发,M0 的 smali 太啰嗦,我们直接反编译看逻辑:

@UiThread
public final void M0(ye2.a aVar, boolean z, boolean z2, String str, f51.a aVar2) {byte[] bArr = SwordSwitches.switches1;if (bArr != null && ((bArr[888] >> 1) & 1) > 0) {if (SwordProxy.proxyMoreArgs(new Object[] { aVar, Boolean.valueOf(z), Boolean.valueOf(z2), str, aVar2 }, this,7106).isSupported) {return;}}TaskUtilsKt.s(new RecordPrivilegeAccountModule$showChargeVIPDialog$1(this, z2, z, aVar2, str, aVar));
}

经研究得知,上部分的 SwordProxy是通用逻辑负责合法校验,不起业务判断作用,校验通过后,下部分无条件直接 new 一个 showChargeVIPDialog。也就是说 M0只要被调用,就无条件触发弹窗。因此我们需要查看 M0 的上游,通过追堆栈找到上游为同类中的 m0方法,再次反编译出来如下:

public final boolean m0(int i, boolean z, boolean z2, String str, f51.a aVar) {int i2 = i;boolean z3 = z;f51.a aVar2 = aVar;byte[] bArr = SwordSwitches.switches1;if (bArr != null && ((bArr[882] >> 3) & 1) > 0) {SwordProxyResult proxyMoreArgs = SwordProxy.proxyMoreArgs(new Object[] { Integer.valueOf(i), Boolean.valueOf(z), Boolean.valueOf(z2), str, aVar2 }, this, 7060);if (proxyMoreArgs.isSupported) {return ((Boolean) proxyMoreArgs.result).booleanValue();}}int u = (int) yu1.e.f().b().u();boolean E = yu1.e.f().b().E();String str2 = this.F;StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("handleSuperSoundVIP level = ");stringBuilder.append(i);stringBuilder.append(" isVip = ");stringBuilder.append(z);stringBuilder.append(",userVipLevel:");stringBuilder.append(u);stringBuilder.append(",userIsSubscription:");stringBuilder.append(E);LogUtil.i(str2, stringBuilder.toString());str2 = "record_module#sound_quality_panel#nul";if (z3) {if (u >= i2) {return true;}if (E && aVar2.l) {this.M = true;return true;} else if (aVar2.l) {g5.a.e(this.e, i, aVar2.k, str2);} else {H(i, u, z2, null, aVar);}} else if (aVar2.l) {g5.a.e(this.e, i, aVar2.k, str2);} else if (u >= i2) {M0(null, true, z2, str, aVar);} else {H(i, u, z2, null, aVar);}return false;
}

Finally,看到了熟悉的日志字样,传入参数 z是一个布尔类型,代表 isVip字段。 int u = (int) yu1.e.f().b().u()链式调用的方式得到 u,代表 userVipLevel

代码执行时,将 z 的值赋给 z3,判断 if (z3),若用户是 vip 则走 if 下面的逻辑,若用户不是 vip 则走 else if 的逻辑,其中有一条 else if 调用到 M0(null, true, z2, str, aVar),触发弹窗。

当 isVip 是 true 的时候,接着判断 if (u >= i2),也就是用户的 vip 等级是否大于想要切换的音质的等级,若是则直接返回 true,否则继续判断走下面。


现在已经清晰了,若我们只想 hook 切换音质这一个功能的话,直接让这个 m0 方法返回 true 即可,但我们想找到传入 m0 的代表用户是否是 vip 的参数 z 是哪来的,以及用户的 vip 等级的链式调用最终走到了哪里返回。
或许所有 vip 功能的判断最终在底层走的都是同一个函数调用,这样我们就不需要一个一个去 hook 单功能点了。

篇幅关系,再次省略复杂且漫长的追堆栈过程:

1. isVip 判断逻辑:

isVip 是 true 还是 false 在 yu1.d类中的 F() 方法中返回,F 方法如下:

    public boolean F() {byte[] bArr = SwordSwitches.switches9;if (bArr != null && ((bArr[102] >> 7) & 1) > 0) {SwordProxyResult proxyOneArg = SwordProxy.proxyOneArg(null, this, 192824);if (proxyOneArg.isSupported) {return ((Boolean) proxyOneArg.result).booleanValue();}}return o01.d.d(v());}

先调用 v() 方法,将返回值传入 o01.d类中的 d 方法中,最终返回 true/false。(真啰嗦)

d 方法如下,当传入的参数为 2、3、5 时,返回 true:

public static boolean d(int i) {if (!(3 == i || 2 == i)) {if (5 != i) {return false;}}return true;
}

v 方法如下,再次调用 ah.e中的 o 方法得到要传入 d 方法中的参数:

public int v() {int i = 1;try {i = ah.e.o(this.b, this.c);} catch (Exception e) {dn.e.b(e, "运行时类初始化异常");}return i;
}
// o 方法:
public static int o(long j, long j2) {if (2 == j2) {return 2;}if (1 == j) {return 3;}if (5 != j) {if (5 != j2) {if (3 != j) {if (4 != j2) {return 1;}}return 4;}}return 5;
}

终于,终于,往下终于没有了,这个 o 方法就是最后一层了,它接收两个 long 参数,并返回 int 值,如果返回的是 2、3、5 则是 vip ,否则为非 vip。

梳理一下:yu1.d.v() => ah.e.o()得到 int i ,i 传入 o01.d.d(i)得到 isVip 为 true/false ,最终一层层返回到上层的业务逻辑。

2. userVipLevel 判断逻辑:

int u = (int) yu1.e.f().b().u(),相比之下,这个链式调用就朴素很多,没有那么多花花肠子。一层层最终来到了 yu1.d类中的 u 方法:

public long u() {return this.a;
}

返回此类中的变量 a ,类型为 long,代表 vip 等级。


总结:

明明是要学习 frida 的实战,却发现难点根本不在 hook 代码的编写,而是逆向过程,如何找到 hook 点,以及一层一层寻找调用堆栈。所以请保持敏锐并不断累积经验,这才是提升技术的要点。

附上部分 frida 代码:

Java.perform(function() {// 1.hook isVip truevar hookIsVip = Java.use('ah.e');hookIsVip.o.implementation = function(j,j2) {console.log('[*] Hook userIsVip success ; class:ah.e ; method:o');return 5}// 2.hook vipLevel 8var hookVipLevel = Java.use('yu1.d');hookVipLevel.u.implementation = function() {console.log('[*] Hook vipLevel=8 success ; class:yu1.d ; method:u');return 8}
})

顺便提醒:

用户信息:com.tencent.karaoke.karaoke_db_base.cachedata.user.UserInfoCacheData
演唱分数:com.tencent.karaoke.audiobasesdk.scorer.ScoreResult

为节省大家研究时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/34840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三元前驱体废水回收镍钴工艺:环保与经济效益的双重胜利

在全球新能源产业迅猛发展的背景下,锂离子电池作为绿色能源的核心组件,其需求量激增,带动了上游材料市场,尤其是三元前驱体材料的蓬勃发展。然而,伴随着行业的快速扩张,三元前驱体生产过程中产生的含镍钴废…

Qt开发 | Qmake与CMake | Qt窗口基类 | VS Qt项目与QtCreator项目相互转化 | Qt架构 | Qt学习方法

文章目录 一、Qmake与CMake介绍1.Qmake2.CMake3.使用qmake还是cmake? 二、Qt3个窗口基类的区别三、vs qt与QtCreator项目相互转化方法1.QtCreator项目转VS Qt2.VS Qt项目转QtCreator项目 四、Qt架构介绍与学习方法详解 一、Qmake与CMake介绍 Qmake和CMake都是构建系…

干货分享 | TSMaster 中不同总线报文消息过滤的操作方式

TSMaster软件平台支持对不同总线(CAN、LIN、FlexRay)报文和信号的过滤,包括全局接收过滤、数据流过滤、窗口过滤、字符串过滤、可编程过滤,针对不同的总线信号过滤器的使用方法基本相同。今天重点和大家分享一下关于TSMaster中报文…

全国首场以AI数字内容风控为主题的大会正式官宣,首批演讲嘉宾和议题揭晓!

曾经我们感叹的“AI迎来了iPhone时刻”,如今已变成“iPhone迎来了AI时刻”。前段时间,苹果全球开发者大会的召开,以及闻声而起的资本市场,无一不再次佐证了AI的无穷想象。 从OpenAI直播演示GPT-4o和谷歌的I/O开发者大会2024&…

Unity踩坑记录

1. 如果同时在父物体和子物体上挂载BoxCollider&#xff0c;那么当使用&#xff1a; private void OnTriggerEnter2D(Collider2D collision){if (collision.CompareTag("CardGroup")){_intersectCardGroups.Add(collision.GetComponent<CardGroup>());}} 来判…

【linux学习十七】文件服务管理

一、FTP FTP server:FTP(File Transfer Protocol,文件传输协议 )是 TCP/IP 协议组中的协议之一 软件包&#xff1a;vsftpd/安装 yum -y install vsftpd//准备文件 touch /var/ftp/abc.txt //注释:FTP服务器的主目录:“/var/ftp/”&#xff0c;是FTP程序分享内容的本机目录…

数据库 复习题

有一个关系模式&#xff1a;工程关系&#xff08;工程号&#xff0c;工程名称&#xff0c;职工号&#xff0c;姓名&#xff0c;聘期&#xff0c;职务&#xff0c;小时工资率&#xff0c;工时&#xff09;&#xff0c;公司按照工时和小时工资率支付工资&#xff0c;小时工资率由…

【大数据】—二手车用户数据可视化分析案例

项目背景 在当今的大数据时代&#xff0c;数据可视化扮演着至关重要的角色。随着信息的爆炸式增长&#xff0c;我们面临着前所未有的数据挑战。这些数据可能来自社交媒体、商业交易、科学研究、医疗记录等各个领域&#xff0c;它们庞大而复杂&#xff0c;难以通过传统的数据处…

MySQL数据库(二):数据库基本操作

MySQL是一种流行的关系型数据库管理系统&#xff0c;广泛用于Web应用和各种数据存储需求。通过本次介绍&#xff0c;您将学习如何进行MySQL数据库的基本操作&#xff0c;包括创建数据库和表、插入和查询数据、更新和删除记录。这些基础知识将为您打下坚实的数据库操作基础。 目…

2023国家最高科学技术奖薛其坤院士:科学家的幸福感来自于哪里

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨浪味仙 排版丨沛贤 深度好文&#xff1a;2000字丨8分钟阅读 6 月 24 日&#xff0c;2023 年度国家最高科学技术奖在京揭晓&#xff0c;薛其坤院士荣获中国科技界崇高荣誉&#xff0c;这不…

【软件下载】Camtasia Studio 2024详细安装教程视频

习惯上来说Camtasia Studio是一款简单易用的高清录屏和视频编辑软件&#xff0c;拥有录制屏幕和配音、视频的剪辑和过场动画片、添加说明字幕和水印、制作视频封面和菜单、视频压缩和播放。不得不说Camtasia是一款屏幕录制和视频剪辑软件&#xff0c;教授课程&#xff0c;培训他…

字节跳动联手博通:5nm AI芯片诞生了?

字节跳动联手博通&#xff1a;5nm AI芯片诞生了&#xff1f; 前言 就在6月24日&#xff0c;字节跳动正在与美国博通合作开发一款5纳米工艺的专用集成电路(ASIC) AI处理器。这款芯片旨在降低采购成本并确保高端AI芯片的稳定供应。 根据报道&#xff0c;尽管芯片设计工作进展顺利…

力扣SQL50 即时食物配送 II min函数 嵌套查询

Problem: 1174. 即时食物配送 II &#x1f468;‍&#x1f3eb; 参考题解 Code -- 计算立即配送的订单百分比 select round (-- 计算订单日期与客户偏好配送日期相同的订单数量sum(case when order_date customer_pref_delivery_date then 1 else 0 end) * 100 /-- 计算总订…

【linux学习十六】网络管理

网络管理器(NetworkManager)是一个动态网络的控制器与配置系统&#xff0c;它用于当网络设备可用时保持设备和连接开启并激活 默认情况下&#xff0c;CentOS/RHEL7已安装网络管理器&#xff0c;并处于启用状态。 认识网卡 ens32 ens33 ens34 ens35 一.ip相关 查询网络状态 sy…

2005年下半年软件设计师【下午题】试题及答案

文章目录 2005年下半年软件设计师下午题--试题2005年下半年软件设计师下午题--答案 2005年下半年软件设计师下午题–试题 2005年下半年软件设计师下午题–答案

「全新升级,性能更强大——ONLYOFFICE 桌面编辑器 8.1 深度评测」

文章目录 一、背景二、界面设计与用户体验三、主要新功能亮点3.1 高效协作处理3.2 共同编辑&#xff0c;毫无压力3.3 批注与提及3.4 追踪更改3.5 比较与合并3.6 管理版本历史 四、性能表现4.1 集成 AI 工具4.2 插件强化 五、用户反馈与使用案例 一、背景 Ascensio System SIA -…

JVM-类加载机制

一、基础概念 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把该类加载到JVM。 其主要流程如下&#xff1a; 1.什么是类加载 那么什么是类加载&#xff1f; Java的类加载&#xff0c;就是把字节码格式“.class”文件加载到JVM的方法区…

48、基于深度学习的离群值输入向量(matlab)

1、基于深度学习的离群值输入向量原理及流程 基于深度学习的离群值检测的输入向量原理是通过神经网络模型对数据进行学习和表示&#xff0c;在该表示中探测异常样本。其流程大致如下&#xff1a; 数据预处理&#xff1a;将数据进行归一化处理&#xff0c;确保神经网络模型能够…

pycharm常用快捷键

详细总结了Pycharm的常用快捷键&#xff0c;下文介绍使用方法和场景, 并不需要记忆这些快捷键, 你只需要知道有这些快捷键, 再需要用的时候查看一下, 用的多了自然也就记住了,需要的朋友可以参考下 1.注释(添加/消除)(Ctrl /)这里说下Python的单行注释是 # , 多行注释是 注释内…

L59---101.对称二叉树(广搜)---Java版

1.题目描述 2.思路和知识点 &#xff08;1)根节点为空&#xff1a; 如果根节点为空&#xff0c;树是对称的。 (2)递归检查&#xff1a; isMirror 方法递归检查两个子树是否是镜像对称的。 (3)辅助函数 isMirror&#xff1a; 1)如果两个节点都为空&#xff0c;它们是镜像对称的…