APK逆向-以某赛车小游戏为例
字数 1169 2025-08-22 12:23:00

APK逆向分析教学:某赛车小游戏实战

环境准备

  • 设备环境:Android 12 已Root
  • 工具版本
    • Jadx: 1.4.4
    • Apktool: 2.5.0
    • 算法助手(可选,用于绕过网络检测)

初步分析

权限问题分析

  1. 游戏请求位置和存储权限
    • 存储权限:用于保存游戏资料(合理)
    • 位置权限:单机游戏中用途不明,拒绝后仍可正常运行

实名认证分析

  • 实名认证界面逻辑位于:com.mygamez.common.antiaddiction.IDCheckDialog
  • 视图可见性状态代码:
    • 0:可见
    • 4:不可见但仍占据布局空间
    • 8:不可见且不占据布局空间(示例中用于隐藏按钮)

实名认证绕过技术分析

认证流程

  1. 用户输入信息后调用:
    AntiAddictionManager.INSTANCE.get().doRidCheck(upperCase, obj, new AntiAddictionManager.AntiAddictionManagerInstance.RidCheckCallback()
    
  2. 认证结果处理:
    • 有效认证(ztrue):保存验证信息并设置用户数据
    • 无效认证:设置为游客模式

网络请求分析

  • 请求URL:https://antiaddiction.******.cn/api/v1 + EndPoint.IDENTIFY
  • 请求方法:POST
  • 请求头包含:x-session-id
  • 响应处理:
    • 状态码200:解析返回的玩家数据
    • 状态码422:解析错误信息
    • 其他状态码:通知错误

绕过方法

  1. 修改doRidCheck方法中的z判断逻辑(取反)
  2. 注意需要将之前对界面判断的修改还原,否则不会进入实名阶段

游戏内购破解

数据存储分析

  • 使用SharedPreferences存储游戏数据:
    public static void loadStore(Context context) {
        mProcessedOrders = context.getSharedPreferences(PREFS_PROCESSED, 0).getString("processed_orders", "");
        mCoins = context.getSharedPreferences(PREFS_NAME, 0).getInt("numCoins", 0);
        mGems = context.getSharedPreferences(PREFS_NAME, 0).getInt(NUM_GEMS, 0);
        // 其他数据...
    }
    

修改方法一:直接修改返回值

  1. 定位getCoins方法
  2. 修改smali代码:
    • const/4 v0,0x0改为const v0,66666
    • 或删除sget v0, Lcom/fingersoft/game/InAppPurchaseStore;->mCoins:I直接赋值

修改方法二:修改loadStore函数

修改smali代码:

const-string v1, "numCoins"
invoke-interface {v0, v1, v3}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result v0
const v0, 888888  # 直接赋值
sput v0, Lcom/fingersoft/game/InAppPurchaseStore;->mCoins:I

const-string v1, "numGems"
invoke-interface {v0, v1, v3}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result v0
const v0, 999999  # 直接赋值
sput v0, Lcom/fingersoft/game/InAppPurchaseStore;->mGems:I

反抓包对抗分析

问题现象

开启代理后游戏提示"信息确认中"并无法进入

解决方案

使用算法助手:

  1. 在LSPosed/Xposed中启用算法助手模块
  2. 在算法助手APP中:
    • 对目标应用开启辅助
    • 打开"其他选项"→"网络环境"
    • 启用所有网络环境选项
  3. 重要:从算法助手应用中启动目标APP

技术要点总结

  1. 视图可见性控制:理解Android中0/4/8三种可见性状态的区别
  2. 实名认证流程
    • 本地格式验证
    • 远程API验证(状态码处理)
  3. 数据存储
    • SharedPreferences机制
    • 关键数据字段定位
  4. smali修改
    • 常量赋值
    • 绕过读取直接赋值
  5. 抓包对抗
    • VPN检测绕过
    • 算法助手配置技巧

注意事项

  1. 所有技术分析仅用于学习目的
  2. 实际应用中需遵守相关法律法规
  3. 游戏开发方可能更新防护措施,需持续分析
  4. 修改前建议备份原始APK
APK逆向分析教学:某赛车小游戏实战 环境准备 设备环境 :Android 12 已Root 工具版本 : Jadx: 1.4.4 Apktool: 2.5.0 算法助手(可选,用于绕过网络检测) 初步分析 权限问题分析 游戏请求位置和存储权限 存储权限:用于保存游戏资料(合理) 位置权限:单机游戏中用途不明,拒绝后仍可正常运行 实名认证分析 实名认证界面逻辑位于: com.mygamez.common.antiaddiction.IDCheckDialog 视图可见性状态代码: 0 :可见 4 :不可见但仍占据布局空间 8 :不可见且不占据布局空间(示例中用于隐藏按钮) 实名认证绕过技术分析 认证流程 用户输入信息后调用: 认证结果处理: 有效认证( z 为 true ):保存验证信息并设置用户数据 无效认证:设置为游客模式 网络请求分析 请求URL: https://antiaddiction.******.cn/api/v1 + EndPoint.IDENTIFY 请求方法:POST 请求头包含: x-session-id 响应处理: 状态码200:解析返回的玩家数据 状态码422:解析错误信息 其他状态码:通知错误 绕过方法 修改 doRidCheck 方法中的 z 判断逻辑(取反) 注意需要将之前对界面判断的修改还原,否则不会进入实名阶段 游戏内购破解 数据存储分析 使用 SharedPreferences 存储游戏数据: 修改方法一:直接修改返回值 定位 getCoins 方法 修改smali代码: 将 const/4 v0,0x0 改为 const v0,66666 或删除 sget v0, Lcom/fingersoft/game/InAppPurchaseStore;->mCoins:I 直接赋值 修改方法二:修改loadStore函数 修改smali代码: 反抓包对抗分析 问题现象 开启代理后游戏提示"信息确认中"并无法进入 解决方案 使用算法助手: 在LSPosed/Xposed中启用算法助手模块 在算法助手APP中: 对目标应用开启辅助 打开"其他选项"→"网络环境" 启用所有网络环境选项 重要 :从算法助手应用中启动目标APP 技术要点总结 视图可见性控制 :理解Android中0/4/8三种可见性状态的区别 实名认证流程 : 本地格式验证 远程API验证(状态码处理) 数据存储 : SharedPreferences机制 关键数据字段定位 smali修改 : 常量赋值 绕过读取直接赋值 抓包对抗 : VPN检测绕过 算法助手配置技巧 注意事项 所有技术分析仅用于学习目的 实际应用中需遵守相关法律法规 游戏开发方可能更新防护措施,需持续分析 修改前建议备份原始APK