好友
阅读权限10
听众
最后登录1970-1-1
|
如题,软件如下,外网的一个数学小游戏,主要是给小盆友玩
链接:https://caiyun.139.com/m/i?0g5CLHiJT1ymQ
提取码:e5LJ
复制内容打开移动云盘PC客户端,操作更方便哦
首先是定目标,老是要小盆友点视频加红心,这不科学。
那么就去广告,然后1次加个100红心吧。 然后就祭出ai大法,他当主力 我做辅助就行了
1、去广告第一步
通过字符串广告观看pv 定位到方法c 目的是为了 了解整个架构的流转,然后把方法代码丢ai 喊一句 帮我分析一下流转 得到以下结论
方法概览
方法名: c()V(返回类型为void)
寄存器: 使用了15个寄存器(v0-v14)
主要逻辑:
记录两个统计事件(埋点)
检查成员变量是否为特定Activity实例,并调用其方法。
代码解析
1. 埋点事件记录
第一个事件(对应Java代码行1):
const-string v2, "首页_点击练习_watchVideo"
sget-object v0, Lc/c;->y:Lc/c;
invoke-static/range {v0 .. v6}, Lc/c;->e(...)
事件参数:
事件类型: "赚心途径pv"(可能是业务相关的统计分类)
事件标识: "首页_点击练习_watchVideo"(用户点击练习并观看视频)
其他参数: null、0、0、12(可能是附加数据或标志位)。
第二个事件(对应Java代码行2):
const-string v9, "首页_点练习_无心弹窗_watchVideo"
sget-object v7, Lc/c;->y:Lc/c;
invoke-static/range {v7 .. v13}, Lc/c;->e(...)
事件参数:
事件类型: "广告观看pv"
事件标识: "首页_点练习_无心弹窗_watchVideo"(用户点击练习时触发的无“心”(游戏内货币?)弹窗广告)
其他参数同上。
推测:Lc/c;->e()是一个埋点工具方法,用于上报用户行为事件。参数可能包括事件类型、标识、附加信息、时间戳、配置项等。
2. Activity检查与方法调用
iget-object v0, p0, Lm9/e0;->a:Lp0/f;
instance-of v1, v0, Lsimplemath/math/.../HomeActivity;
if-eqz v1, :cond_27
check-cast v0, Lsimplemath/math/.../HomeActivity;
invoke-virtual {v0}, Lw8/b;->i()V
逻辑:
获取当前对象的成员变量a(类型为Lp0/f)。
检查a是否是HomeActivity的实例。
如果是,调用HomeActivity的父类Lw8/b的i()方法。
推测:
a可能是一个上下文(Context)或Activity的引用。
i()方法可能是界面刷新、数据加载或弹窗关闭等操作(需结合上下文进一步分析)。
代码对应的Java伪代码
public void c() {
// 埋点1:用户点击练习并观看视频
StatHelper.e(StatHelper.y, "赚心途径pv", "首页_点击练习_watchVideo", null, 0, 0, 12);
// 埋点2:用户触发无“心”弹窗广告
StatHelper.e(StatHelper.y, "广告观看pv", "首页_点练习_无心弹窗_watchVideo", null, 0, 0, 12);
// 检查并调用Activity方法
if (this.a instanceof HomeActivity) {
((HomeActivity) this.a).i(); // 可能是刷新界面或处理广告回调
}
}
关键点总结
埋点统计:
记录用户点击练习和观看广告的行为,用于数据分析。
事件标识符中包含中文,可能与业务逻辑强相关(如“心”是应用内货币)。
Activity逻辑:
当成员变量a指向HomeActivity时,触发其i()方法,可能是更新UI或处理广告观看后的奖励。
可能的应用场景
用户在首页点击“练习”按钮,触发观看视频广告(如获取游戏货币“心”)。
广告观看完成后,通过i()方法刷新用户货币余额或关闭弹窗。
进一步分析建议:
查看Lc/c;->e()的具体实现,确认埋点参数含义。
分析HomeActivity的i()方法,明确其实际作用。
2、去广告第二步,找到i方法,把i方法 丢ai 给我出修改方案
然后天生的打工人给出以下方案。
代码功能解析
该方法核心逻辑是加载并展示激励视频广告,并在广告播放完成后触发奖励回调。关键步骤分解如下:
1. 初始化广告组件
# 初始化广告管理器(Lw8/j)
sget-object v0, Lw8/i;->c:Lw8/i$a;
invoke-virtual {v0}, Lw8/i$a;->a()Lw8/j;
move-result-object v0
# 设置广告回调监听器(Lw8/j$a)
new-instance v1, Lw8/b$b;
invoke-direct {v1, p0}, Lw8/b$b;-><init>(Lw8/b;)V
iput-object v1, v0, Lw8/j;->a:Lw8/j$a;
Lw8/j 是广告管理类,Lw8/j$a 是广告播放完成的回调接口。
回调方法 c()(在 Lw8/j$a 中定义)可能是奖励发放的入口。
2. 检查广告缓存状态
# 检查广告是否已缓存(Li7/c)
if-eqz v1, :cond_4f
iget-object v1, v1, Li7/c;->e:Lk7/c;
invoke-virtual {v1}, Lk7/c;->j()Z
move-result v1
# 如果广告已缓存(v1 == 1),直接触发奖励
if-ne v1, v2, :cond_4f
const/4 v1, 0x1
:goto_50
if-eqz v1, :cond_61
sget-object v1, Lu9/a;->a:Lu9/a$a;
const-string v2, "hasAD"
invoke-virtual {v1, v2}, Lu9/a$a;->b(Ljava/lang/String;)V
# 触发奖励回调 c()
iget-object v0, v0, Lw8/j;->a:Lw8/j$a;
invoke-interface {v0}, Lw8/j$a;->c()V
关键点:当广告已缓存时(hasAD 标记存在),直接调用 c() 发放奖励。
漏洞:可以通过强制让 hasAD 始终为真,无需播放广告即可触发奖励。
修改方案
目标
无需观看广告,直接触发奖励发放(c())
方案一:强制跳转到奖励分支
修改位置:if-eqz v1, :cond_61
将条件判断改为无条件跳转,强制进入奖励分支:
# 原始代码
if-eqz v1, :cond_61
# 修改后(删除条件判断,直接跳转)
goto :cond_61
对应Smali修改:
# 定位到条件跳转指令(例如):
if-eqz v1, :cond_61
# 替换为:
goto :cond_61
效果:无论广告是否加载完成,直接触发 c() 发放奖励。
方案二:伪造广告缓存状态
修改位置:广告缓存状态检查逻辑
强制让 Li7/c 的缓存检查返回 true:
# 原始代码
iget-object v1, v1, Li7/c;->e:Lk7/c;
invoke-virtual {v1}, Lk7/c;->j()Z
move-result v1
# 修改后(直接返回1):
const/4 v1, 0x1
对应Smali修改:
# 定位到检查代码块:
iget-object v1, v1, Li7/c;->e:Lk7/c;
invoke-virtual {v1}, Lk7/c;->j()Z
move-result v1
# 替换为:
const/4 v1, 0x1
效果:系统认为广告已缓存,自动触发奖励。
很好,就用第2套方案吧,测试通过。
3、广告现在去除了 然后就修改一次性红心加100吧。把自己需求告诉ai即可,ai拉着我跑了几个方法(过程略了),然后最终才定位到关键方法。
### 终极总结:红心修改全流程
1. 核心问题定位
目标:点击按钮时,红心增加量从 1 → 100。
关键障碍:
隐藏上限:原代码限制红心数≥5时不增加。
寄存器冲突:p2 参数被后续代码覆盖。
多调用点干扰:7处调用需统一修改逻辑。
2. 完整解决方案
步骤1:移除红心上限检查
在 Ld9/c;->b() 方法中,删除红心上限判断代码:
# 删除以下两行:
iget v0, p0, Ld9/c;->g:I
const/4 v1, 0x5
if-lt v0, v1, :cond_6
return-void
步骤2:修复寄存器冲突
修改 Ld9/c;->b() 方法,避免覆盖 p2 参数:
# 原错误代码(覆盖p2):
sget-object p2, Lu9/b;->b:Lu9/b$a;
# 修复后代码(使用v1):
sget-object v1, Lu9/b;->b:Lu9/b$a;
步骤3:统一修改调用点
根据需求选择方案:
方案A(精准修改):定位所有7处调用 Ld9/c;->b() 的代码,将参数改为100:
# 所有调用点修改示例:
const/16 vX, 0x64 # 0x64=100
invoke-virtual {v3, p1, vX}, Ld9/c;->b(Landroid/content/Context;I)V
方案B(全局生效):直接修改 Ld9/c;->b() 内部逻辑,强制每次增加100:
# 在方法内部忽略参数p2,固定增加100:
add-int/lit16 v0, v0, 0x64 # 0x64=100
3. 验证与调试
验证方式 操作步骤 预期结果
静态反编译验证 使用 JADX 检查 Ld9/c;->b() 和调用点代码 无上限检查,参数为100
动态日志注入 在代码中插入 Log 语句输出红心变化值 日志显示 红心+100
FrIDA 监控 拦截 Ld9/c;->b() 方法,打印传入参数和结果 参数=100,红心累计正确
SharedPreferences 检查 使用 adb shell 查看 pi_rh 键值对 值 = 原值 + 100
4. 高频问题与修复
问题现象 原因分析 解决方案
修改后仍只+1 调用点未全部修改 检查所有7处调用点或改用方案B
应用闪退 寄存器数量声明不足 调整 .registers 数量
红心值未保存 SharedPreferences 键名错误 确认 pi_rh 键名一致性
部分场景红心未变化 代码混淆导致多个副本 全项目搜索 Ld9/c;->b( 确保唯一
5. 终极推荐方案
新手友好:使用 方案B(全局修改),直接修改 Ld9/c;->b() 内部逻辑。
精准控制:使用 方案A + Frida 监控,确保所有调用点参数为100。
代码混淆应对:全项目搜索 Ld9/c;->b(,统一修改所有副本。
很好 就用新手友好吧。
全局终,谢谢观看。
总结ai时代 想逆向 小白只需要驾驭ai就能跨越很大的鸿沟,所以善用ai,御剑术,人御剑不是剑御人,所以方向把握的好 就是逆向的关键,而人负责方向,ai负责打工即可。 |
免费评分
-
查看全部评分
|