安卓游戏逆向 -- Frida Hook 绕过碰撞死亡判定
jet58
jet58
逆向有你
2026年6月30日 11:28
河南
在小说阅读器读本章
去阅读
Android安卓游戏Unity Mono 游戏逆向实战:从 APK 到 Hook libmono.so 绕过死亡判定
前言
最近在分析一款 极限摩托基于手机重力控制的 Unity 游戏:
- 通过手机 前后翻转控制角色
- 人物只要 发生碰撞(翻车 / 头部触地)就会立即失败
- 没有明显的数值判定,属于典型的 物理 + 碰撞触发死亡
本文完整记录了我 从 APK 分析 → 判断 Unity 架构 → Hook Mono Runtime → 精准拦截死亡函数 的全过程。
最终效果:
人物发生碰撞也不会死亡,游戏可正常继续运行。
一、实验环境
游戏截图
我使用的设备 & 工具版本
- Android 10 真机(arm64)
- Frida版本
:17.5.2
* Frida Server版本
:frida-server-17.5.1-android-arm64
* Python版本
:3.10.0
* 手机不方便可以使用手机模拟器
#### Frida Server 启动
上传到手机:
复制代码 隐藏代码
adb push frida-server-17.5.1-android-arm64 /data/local/tmp/
复制代码 隐藏代码
adb shell chmod +x /data/local/tmp/frida-server-17.5.1-android-arm64
启动frida-server-17.5.1-android-arm64
复制代码 隐藏代码
adb shell /data/local/tmp/frida-server-17.5.1-android-arm64
二、从 APK 入手:判断游戏架构
1️⃣ 解包 APK
复制代码 隐藏代码
apktool d trial.apk
重点关注:
AndroidManifest.xmllib/armeabi-v7a
/ lib/arm64-v8a
* assets/
2️⃣ 查看 so 文件(关键判断点)
在 lib/arm64-v8a/ 目录下发现:
复制代码 隐藏代码
libmono.so
libu.so
同时:
- ❌ 不存在
libil2cpp.so - ❌ 不存在
libunity.so(部分 Mono 游戏本来就没有)
✅ 结论
这是一个 Unity Mono 架构游戏(非 IL2CPP)
三、确认 C# 脚本存在
在:
复制代码 隐藏代码
assets/bin/Data/Managed/
中可以看到:
复制代码 隐藏代码
Assembly-CSharp.dll
UnityEngine.dll
Assembly-CSharp.dll 可以使用ILSpy工具打开,可以直接看到关键代码Bone::OnCollisionEnter,进行分析
说明:
- 游戏逻辑由 C# 编写
- 运行在 Mono VM
- 实际执行发生在 libmono.so
四、为什么选择 Hook libmono.so
❌ 不直接修改 DLL 的原因
- 需要重打包 APK
- 可能触发签名 / 完整性校验
- 不利于动态调试
✅ Hook Mono Runtime 的优势
- 不修改 APK
- 可实时观察 C# 函数调用
- 能拦截 Unity 生命周期 / 碰撞函数
五、锁定关键函数:mono\_runtime\_invoke
Mono 执行模型简化图
复制代码 隐藏代码
Unity 物理 / 碰撞
↓
C# 脚本 (Update / OnCollisionEnter)
↓
IL Code
↓
mono_runtime_invoke
↓
Native 执行
所有 C# 方法最终都会经过
mono_runtime_invoke
这意味着:
Hook 一个函数,就能观察并控制所有 C# 方法调用。
六、附加进程并 Hook
1️⃣ 查找游戏 PID
复制代码 隐藏代码
adb shell ps -A | grep com.galapagossoft.trial
输出示例:
复制代码 隐藏代码
u0_a236 19480 ... com.galapagossoft.trial
2️⃣ Frida Attach
复制代码 隐藏代码
frida -U -p 19480 -l mono_base.js
七、Hook 脚本(核心代码)
复制代码 隐藏代码
console.log(\" mono_base.js loaded\");
var mono = Process.findModuleByName(\"libmono.so\");
if (!mono) {
console.log(\"libmono.so not found\");
return;
}
var mono_method_get_name_ptr = mono.getExportByName(\"mono_method_get_name\");
var mono_runtime_invoke_ptr = mono.getExportByName(\"mono_runtime_invoke\");
var mono_method_get_class_ptr = mono.getExportByName(\"mono_method_get_class\");
var mono_class_get_name_ptr = mono.getExportByName(\"mono_class_get_name\");
var mono_method_get_name = newNativeFunction(
mono_method_get_name_ptr, \"pointer\", [\"pointer\"]
);
var mono_method_get_class = newNativeFunction(
mono_method_get_class_ptr, \"pointer\", [\"pointer\"]
);
var mono_class_get_name = newNativeFunction(
mono_class_get_name_ptr, \"pointer\", [\"pointer\"]
);
var orig_mono_runtime_invoke = newNativeFunction(
mono_runtime_invoke_ptr,
\"pointer\",
[\"pointer\", \"pointer\", \"pointer\", \"pointer\"]
);
Interceptor.replace(
mono_runtime_invoke_ptr,
newNativeCallback(function (method, obj, params, exc) {
var klass = mono_method_get_class(method);
var className = mono_class_get_name(klass).readCString();
var methodName = mono_method_get_name(method).readCString();
// 关键:拦截碰撞触发
if (className === \"Bone\" && methodName === \"OnCollisionEnter\") {
console.log(\"[BLOCK] \" + className + \"::\" + methodName);
returnptr(0);
}
returnorig_mono_runtime_invoke(method, obj, params, exc);
}, \"pointer\", [\"pointer\", \"pointer\", \"pointer\", \"pointer\"])
);
八、分析过程与关键突破
1️⃣ 先打印观察调用
日志中依次出现:
复制代码 隐藏代码
Fork::Update
Fork::OnCollisionStay
FailController::OnGUI
Bone::OnCollisionEnter
2️⃣ 排除错误目标
FailController::OnGUI
👉 只是 UI 显示失败画面,不是死亡原因FailController::Start
👉 失败后的初始化逻辑
3️⃣ 真正的死亡触发点
复制代码 隐藏代码
Bone::OnCollisionEnter
这正好符合游戏机制:
人物因重力翻转发生碰撞 → 立即失败
九、最终效果
成功拦截后:
- 人物发生碰撞 不再死亡
- 物理系统正常
- 游戏流程可继续
✅ 无需修改 APK
✅ 无需重打包
✅ 精准绕过失败判定
十、总结
本文完整展示了一条 Unity Mono 游戏逆向的通用思路:
- 从 APK 判断 Unity 架构
- 确认 Mono 而非 IL2CPP
- 锁定 libmono.so
- Hook
mono_runtime_invoke - 通过 Runtime 级分析定位关键 C# 方法
- 精准拦截
OnCollisionEnter实现逻辑绕过
理解引擎执行模型,比盲目改代码更重要。
后记
这套方法同样适用于:
- Unity Mono 手游
- 碰撞 / 判定 / 失败逻辑分析
- 无源码、无符号环境下的动态逆向
后续我会继续分享更多 Unity / Mono / Frida 实战分析。
·今 日 推 荐·
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论