# 前言

之前在研究手游的 il2cpp 修改,选取了 Mine Survival 作为研究对象,由于手上没有 root 的机子,于是安装在了 MuMu 模拟器上

但是很快发现了问题,游戏只有 arm 的 lib,由于一系列原因,导致我无法获取到 libil2cpp.so 的基址

在尝试了很多方法后都无法完美的解决这个问题,最终只能考虑安装在真机上了

但是目前并没有对机子 root 的打算,于是选取了注入 frida-gadget 的方案,这样没有 root 也可以对游戏进行修改了 hhh

# 准备工作

基础工作不做过多介绍,学这个的应该都懂一点,除非你想一步登天 (笑)

我的设备

  • 安卓真机 - Redmi Note 8
  • 电脑 - Win10 专业版 22H2

推荐使用 scrcpy ,可以将手机画面投屏到电脑

# 开始操作

# 注入 frida-gadget

# 介绍

可以手动操作去理解原理,参考这篇文章 Using Frida on Android without root

当然我这种懒汉肯定是选用自动化方案啦,使用 objection 来自动化 patch apk

# 安装 objection

  • python 版本 3.4+
  • pip3 版本 9.0+
  • (可选) virtualenv 版本 15+

# 全局安装

$ pip3 install -U objection

# 虚拟环境安装

为了防止冲突,推荐安装在虚拟环境里

# 创建虚拟环境
$ virtualenv myenv
# 激活虚拟环境
$ .\myenv\Scripts\activate
# 安装 objection
$ pip3 install -U objection

# patch apk

确定以下命令安装并且可用,将其添加到环境变量中

adb 连接上安卓设备,执行下面的命令,就可以自动化的帮你 patch 好 apk 了

$ objection patchapk --source '.\Mine Survival_v2.5.3.apk'

img.png

# 安装测试

Mine Survival_v2.5.3.objection.apk 安装到手机

$ adb install '.\Mine Survival_v2.5.3.objection.apk'

然后执行一下 frida-ps -U ,有如下回显就是成功了

$ frida-ps -U
  PID  Name
-----  ------
21709  Gadget

测试一下,写个获取 libil2cpp.so 的脚本

Java.perform(function() {
    var module = Process.getModuleByName("libil2cpp.so");
    console.log(module.base);
})

注入 js

$ frida -U Gadget -l .\hook.js

可以看到成功获取到了 libil2cpp.so 的基址
img.png

# frida-il2cpp-bridge

很好用,不多解释了

# 安装测试

执行下面的命令来安装 frida-il2cpp-bridge

$ npm install --save-dev frida-il2cpp-bridge

修改 package.json

{
  "main": "index.ts",
  "scripts": {
    "prepare": "npm run build",
    "watch": "frida-compile index.ts -w -o hook.js"
  },
  "dependencies": {
    "frida-il2cpp-bridge": "^0.9.0"
  }
}

新建一个 index.ts ,测试一下输出 unity 版本

import "frida-il2cpp-bridge";
Il2Cpp.perform(() => {
    console.log("Unity version: " + Il2Cpp.unityVersion);
});

执行 npm run watch 编译一下,然后再开个 console 执行 frida -U Gadget -l .\hook.js

可以看到成功输出了 unity 的版本
img.png

# 开始修改

通过分析 il2cppdumper dump 后得到的 Assembly-CSharp.dll ,发现了 Inventory 这个类,可以看到他有一个 AddItems 的方法,那我们就可以想办法调用他来添加物品
img.png

现在来跟踪一下这个类

import "frida-il2cpp-bridge";
Il2Cpp.perform(() => {
    console.log("Unity version: " + Il2Cpp.unityVersion);
    const AssemblyCSharp = Il2Cpp.domain.assembly("Assembly-CSharp").image
    const Inventory = AssemblyCSharp.class("Inventory");
    Il2Cpp.trace(true).classes(Inventory).and().attach();
});

拾取一个物品,可以看到他调用了 Inventory::AddDropItem 这个方法
img.png

那么就可以 hook 他来调用 Inventory::AddItems

import "frida-il2cpp-bridge";
Il2Cpp.perform(() => {
    console.log("Unity version: " + Il2Cpp.unityVersion);
    const AssemblyCSharp = Il2Cpp.domain.assembly("Assembly-CSharp").image
    const Inventory = AssemblyCSharp.class("Inventory");
    const AddDropItem = Inventory.method("AddDropItem");
    // Il2Cpp.trace(true).classes(Inventory).and().attach();
    AddDropItem.implementation = function (item): boolean {
        // bool AddItems(int id, int amount)
        this.method("AddItems").invoke(115, 999);
        const result = this.method<boolean>("AddDropItem").invoke(item);
        return result; 
    };
});

拾取物品,可以看到我们拥有了许多核导弹 (喜)
img.png

# 完结撒花

frida-il2cpp-bridge 还是很强大的,可以去学习一下,不过更新变动比较大

写的可能有点乱,有问题还请指出 hh