熊大快跑 Unity 游戏简单逆向

  • 示例游戏版本: 小米应用商店熊出没之熊大快跑(com.joym.xiongdakuaipao) v4.3.2

Dump 出 C# 类结构

  • 从目标 APK 中复制 libs/CPU架构/libil2cpp.soassets/bin/Data/Managed/Metadata/global-metadata.dat 到本地
  • 运行 Il2CppDumper 并依次选择 libil2cpp.soglobal-metadata.dat
  • 导出的 dump.cs 包含类结构和函数/属性偏移

寻找目标函数

  • 进入 dump.cs
  • 已知货币是金币和钻石,所以搜索 Coin 或者 Diamond,找到 ItemID,这是物品 ID 表
  • 搜索 class Item,找到 Item 类,这是物品类,我们的目标是 get_Count 函数和 itemId 属性
  • 已知有物品安全帽,所以搜索 Helmet,找到 BearGameInfimpl 类,这是玩家类,里面有相当多的函数可以 hook,我们的目标是 IsHelmet IsDoubleCoinIsMagnet 函数
  • 地址/偏移/物品表
    函数/属性/物品 地址/偏移/ID
    BearGameInfimpl::IsHelmet 0x9A7F7C
    BearGameInfimpl::IsDoubleCoin 0x9A8304
    BearGameInfimpl::IsMagnet 0x9A8554
    Item::get_Count 0x132EE20
    Item::itemId +0x10
     
    物品 ID
    钻石 1
    金币 2
    安全帽(Shield) 3
    双倍金币 4
    磁铁 20

Hook 目标函数

  • 预留保存原函数指针
1
2
3
4
bool (*O_BearGameInfimpl_IsHelmet)(void*) = nullptr;
bool (*O_BearGameInfimpl_IsDoubleCoin)(void*) = nullptr;
bool (*O_BearGameInfimpl_IsMagnet)(void*) = nullptr;
int (*O_Item_get_Count)(void*) = nullptr;
  • 功能表
1
2
3
4
5
bool permanentHelmet = true;
bool permanentDoubleCoin = true;
bool permanentMagnet = true;
bool infiniteCoin = true;
// ...
  • Hook IsHelmet IsDoubleCoinIsMagnet 函数
    这里只演示 IsHelmet 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
uintptr_t base = getBaseAddress();
// 获取 libil2cpp.so 的基址,getBaseAddress() 需要自行实现或者使用库

bool H_BearGameInfimpl_IsHelmet(void* instance) {
if (permanentHelmet) {
return true;
}
if (O_BearGameInfimpl_IsHelmet) {
return reinterpret_cast<bool(*)(void*)>(O_BearGameInfimpl_IsHelmet)(instance);
}
return false;
}

hook((void *)((uintptr_t) base + 0x9A7F7C), (void*) H_BearGameInfimpl_IsHelmet, (void**) &O_BearGameInfimpl_IsHelmet);
// hook() 需要自行实现或者使用库
  • Hook get_Count 函数
    这里以无限金币为例
1
2
3
4
5
6
7
8
9
10
11
12
13
int H_Item_get_Count(void* instance) {
int type = *(int *)((char *)instance + 0x10);
if (infiniteCoin && type == 2) {
return 999999;
}
if (O_Item_get_Count) {
return reinterpret_cast<int(*)(void*)>(O_Item_get_Count)(instance);
}
return 0;
}

hook((void *)((uintptr_t) base + 0x132EE20), (void*) H_Item_get_Count, (void**) &O_Item_get_Count);
// hook() 需要自行实现或者使用库

加载 Hook

  • 把我们编译出来的 libcrack.so 复制到 APK 的 lib/CPU架构/
  • 修改或注入 Dex/Java,使 il2cpp 被加载后加载我们的 libcrack.so
1
System.loadLibrary("crack");
  • 签名安装,大功告成

后记

  • 如果打开后闪退,则需要绕过签名校验并检查代码是否有错误
  • 如果无法登录或提示环境异常,需要把 com.joym.sdk.core.GGameActivity 设为启动 Activity,并拦截登录窗口的弹出
  • Demo: OneDrive