高中生
Who am I?

- 金币
- 447
- 好评
- 10
- 信誉
- 106
 
|
本帖最后由 不羁 于 2025-9-6 21:45 编辑
前言:
“授人以鱼不如授人以渔”这句话在逆向学习中尤为关键。真正的逆向价值从不是拿到现成的破解成果,而是掌握分析逻辑、拆解难题的思维与能力 —— 这正是“渔”的核心意义。
本教程不会提供可直接复用的工具包或成品补丁,也不会走“一步到位”的捷径。将完整呈现从定位关键代码到验证方案的全流程,带你亲历每一次拆解与思考的细节。
每处内容都经反复打磨,力求讲透原理与排查思路。请沉下心跟随实操,不必急于求成。逆向的真本事,永远藏在独立解决问题的过程里,而非现成结果中。
一、目标背景与技术环境
1. 应用概况
体重小本(包名:com.ximi.weightrecord)是一款聚焦体重管理的工具类应用,其采用付费会员机制管控核心功能。普通用户需付费开通 "永久会员"(原价 384 元,优惠价 168 元)方可解锁 AI 拍照识图、AI 自动打卡、个性化减重指导等高级功能,未开通会员时此类功能处于锁定状态。
2. 环境与工具
目标应用:体重小本 6.6.7(未加固,支持 V1+V2 签名)
核心工具:MT 管理器(用于 APK 提取、解包、DEX 编辑及重签名)
技术基础:Android逆向入门(了解 DEX 文件结构、Smali 语法基础)
二、原理与逆向思路
1. 核心成因该应用的会员权限校验逻辑完全依赖本地数据模型,未通过服务器端进行加密验证或动态权限校验。核心会员状态信息(包括是否有效、过期时间、会员类型)均存储于本地VipInfo模型类中,应用通过调用该类的getStatus()、getVipExpireTime()、getVipType()等方法获取权限状态,因此可通过修改这些方法的返回值直接伪造永久会员身份。
2. 逆向分析路径定位会员相关字符串→锁定会员界面核心类→追踪会员信息数据模型→识别关键校验方法→修改方法返回值→重打包验证效果
三、详细实战步骤
1. 应用准备与安装包提取
原始应用确认:从应用商店下载并安装体重小本 6.6.7,验证普通用户状态下高级功能(如 AI 拍照识图)被限制,会员页面显示 "永久会员" 付费提示。APK提取:打开MT管理器,点击 "安装包提取",将 APK 保存至本地,确认文件属性:大小 114.13M,签名状态 V1+V2,加固状态为 "未加固"(未加固是后续编辑的前提)。
2. DEX 文件解析与核心类定位
APK解包与DEX选择:在 MT 管理器中点击提取的 APK 文件,选择 "查看" 进入内部目录,定位classes.dex系列文件(包含classes1.dex至classes7.dex,这些文件是 Android 应用的字节码存储载体)。全选所有 DEX 文件,通过 "DEX 编辑器 ++" 打开进入代码编辑模式。
关键词搜索定位:在 DEX 编辑器中点击 "搜索" 功能,设置搜索参数:查找内容:会员(通过业务关键词缩小范围)搜索类型:代码(搜索 DEX 中的字节码内容)其他选项:默认(不区分大小写,搜索子目录)
执行搜索后,筛选结果中包含 "永久会员"" 会员生效中 " 等字符串的代码片段。核心界面类锁定:在搜索结果中定位路径com.ximi.weightrecord.ui.persional.vip,找到PersonalVipActivity类(该类包含 "永久会员"" 会员已过期 " 等核心状态字符串,如const-string/jumbo v3, "永久会员"),确认其为会员状态展示的核心界面类。
3. 数据模型追踪与关键方法识别会员信息模型定位:
在PersonalVipActivity类的导航信息中,发现其依赖Lcom/ximi/weightrecord/mvvm/logic/model/VipInfo(即VipInfo类),该类是存储会员信息的核心数据模型,所有会员状态校验均基于此类的方法返回值。
关键方法识别:通过VipInfo类的导航列表(方法列表),锁定三个核心方法:getStatus():返回会员状态标识(推测 0 代表有效,非 0 代表无效)getVipExpireTime():返回过期时间戳(Long 类型,决定会员是否过期)getVipType():返回会员类型(推测 3 代表 "永久会员" 类型)
4. Smali 代码修改与逻辑绕过
(1)修改getStatus()方法(会员有效性校验)原方法分析:该方法返回整数类型状态值,用于标识会员是否有效。修改操作:长按getStatus()方法选择 "清空代码",重构为固定返回有效状态:
- .method public final getStatus()I # 方法签名:返回整数类型状态
- .registers 1 # 寄存器数量(需与指令匹配)
- const/4 v0, 0x0 # 强制返回0(标识会员有效)
- return v0 # 返回结果
- .end method
复制代码
(2)修改getVipExpireTime()方法(过期时间校验)
原方法分析:返回 Long 类型时间戳,应用通过该值判断会员是否过期。
修改操作:跳转至getVipExpireTime()方法,清空原有代码后插入远期时间戳:
- .method public final getVipExpireTime()Ljava/lang/Long; # 方法签名:返回Long类型时间戳
- .registers 3 # 调整寄存器数量适配新指令(原1→3)
- const-wide v0, 0x3a352943c18L # 设定远期时间戳(对应约2099年,确保永不过期)
- invoke-static {v0, v1}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long; # 转换为Long对象
- move-result-object v0 # 获取转换结果
- return-object v0 # 返回远期时间戳
- .end method
复制代码
(3)修改getVipType()方法(会员类型校验)
原方法分析:返回整数类型会员类型,决定会员权益等级(如体验会员、永久会员)。
修改操作:跳转至getVipType()方法,清空代码后设置永久会员类型标识:
- .method public final getVipType()Ljava/lang/Integer; # 方法签名:返回Integer类型会员类型
- .registers 2 # 调整寄存器数量(原1→2)
- const v0, 0x3 # 设定类型为3(对应"永久会员")
- invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer; # 转换为Integer对象
- move-result-object v0 # 获取转换结果
- return-object v0 # 返回永久会员类型
- .end method
复制代码
四、技术总结与注意事项
1. 关键技术点回顾
DEX 文件是Android逆向的核心对象,未加固应用可直接编辑
字符串搜索是定位业务逻辑的高效手段
数据模型类的getter方法常是权限校验的关键入口
Smali语法中需注意寄存器数量与指令匹配(如registers值需根据参数调整)
2. 合法与安全提示
本教程仅用于逆向技术研究与学习,请勿用于侵犯应用开发者权益的商业用途
实际开发中应通过服务器端加密校验、动态权限令牌等方式避免此类本地校验漏洞
操作前需备份原APK,避免修改失败导致应用无法恢复
通过本实战案例可见,本地权限校验逻辑若缺乏服务器端强验证,极易被逆向篡改。逆向学习者可通过此类案例加深对Android应用结构与Smali语法的理解。
到这里,这次的逆向教程就暂告一段落了。每一处都尽量把原理讲清、把步骤铺实,毕竟比起“给工具”,我更希望大家能练出自己拆解问题的底气。
如果这套教程帮你跨过了逆向的入门坎、看懂了代码的关键逻辑,或者让你敢动手尝试实战案例,各位观众们不妨留个好评和金币打赏 —— 你的肯定会成为我打磨下一期内容的最大动力。咱们一起把逆向的基础打牢~ 感谢同行,下次教程再会!
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|