# 前言
之前在研究手游的 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
确定以下命令安装并且可用,将其添加到环境变量中
- aapt - http://elinux.org/Android_aapt
- adb - https://developer.android.com/studio/command-line/adb.html
- jarsigner - http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jarsigner.html
- apktool - https://ibotpeaches.github.io/Apktool/
adb 连接上安卓设备,执行下面的命令,就可以自动化的帮你 patch 好 apk 了
$ objection patchapk --source '.\Mine Survival_v2.5.3.apk' |
# 安装测试
将 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
的基址
# 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 的版本
# 开始修改
通过分析 il2cppdumper
dump 后得到的 Assembly-CSharp.dll
,发现了 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"); | |
Il2Cpp.trace(true).classes(Inventory).and().attach(); | |
}); |
拾取一个物品,可以看到他调用了 Inventory::AddDropItem
这个方法
那么就可以 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; | |
}; | |
}); |
拾取物品,可以看到我们拥有了许多核导弹 (喜)
# 完结撒花
frida-il2cpp-bridge
还是很强大的,可以去学习一下,不过更新变动比较大
写的可能有点乱,有问题还请指出 hh