首页
社区
课程
招聘
[原创]一次完整的 Unity Mono 安卓游戏逆向:Frida Hook 绕过碰撞死亡判定
发表于: 2025-12-28 12:52 5278

[原创]一次完整的 Unity Mono 安卓游戏逆向:Frida Hook 绕过碰撞死亡判定

2025-12-28 12:52
5278

最近在分析一款 极限摩托基于手机重力控制的 Unity 游戏在这里插入图片描述

本文完整记录了我 从 APK 分析 → 判断 Unity 架构 → Hook Mono Runtime → 精准拦截死亡函数 的全过程。

最终效果:

人物发生碰撞也不会死亡,游戏可正常继续运行。

在这里插入图片描述

上传到手机:

启动frida-server-17.5.1-android-arm64

重点关注:

lib/arm64-v8a/ 目录下发现:

同时:

这是一个 Unity Mono 架构游戏(非 IL2CPP)

在:

中可以看到:

在这里插入图片描述

说明:

所有 C# 方法最终都会经过 mono_runtime_invoke

这意味着:

Hook 一个函数,就能观察并控制所有 C# 方法调用。

输出示例:

日志中依次出现:

FailController::OnGUI 只是 UI 显示失败画面,不是死亡原因

FailController::Start 失败后的初始化逻辑

这正好符合游戏机制:

人物因重力翻转发生碰撞 → 立即失败

成功拦截后:

无需修改 APK无需重打包精准绕过失败判定

本文完整展示了一条 Unity Mono 游戏逆向的通用思路

理解引擎执行模型,比盲目改代码更重要。

这套方法同样适用于:

后续我会继续分享更多 Unity / Mono / Frida 实战分析。

adb push frida-server-17.5.1-android-arm64 /data/local/tmp/
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
adb shell chmod +x /data/local/tmp/frida-server-17.5.1-android-arm64
adb shell /data/local/tmp/frida-server-17.5.1-android-arm64
adb shell /data/local/tmp/frida-server-17.5.1-android-arm64
apktool d trial.apk
apktool d trial.apk
libmono.so
libu.so
libmono.so
libu.so
assets/bin/Data/Managed/
assets/bin/Data/Managed/
Assembly-CSharp.dll
UnityEngine.dll
Assembly-CSharp.dll
UnityEngine.dll
Unity 物理 / 碰撞
        
C# 脚本 (Update / OnCollisionEnter)
        
IL Code
        
mono_runtime_invoke
        
Native 执行
Unity 物理 / 碰撞
        
C# 脚本 (Update / OnCollisionEnter)
        
IL Code
        
mono_runtime_invoke
        
Native 执行
adb shell ps -A | grep com.galapagossoft.trial
adb shell ps -A | grep com.galapagossoft.trial
u0_a236   19480   ...   com.galapagossoft.trial
u0_a236   19480   ...   com.galapagossoft.trial
frida -U -p 19480 -l mono_base.js
frida -U -p 19480 -l mono_base.js
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 = new NativeFunction(
    mono_method_get_name_ptr, "pointer", ["pointer"]
);
 
var mono_method_get_class = new NativeFunction(
    mono_method_get_class_ptr, "pointer", ["pointer"]
);
 
var mono_class_get_name = new NativeFunction(
    mono_class_get_name_ptr, "pointer", ["pointer"]
);
 
var orig_mono_runtime_invoke = new NativeFunction(
    mono_runtime_invoke_ptr,
    "pointer",
    ["pointer", "pointer", "pointer", "pointer"]
);
 
Interceptor.replace(
    mono_runtime_invoke_ptr,
    new NativeCallback(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);
            return ptr(0);
        }
 
        return orig_mono_runtime_invoke(method, obj, params, exc);
 
    }, "pointer", ["pointer", "pointer", "pointer", "pointer"])
);
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 = new NativeFunction(
    mono_method_get_name_ptr, "pointer", ["pointer"]
);
 
var mono_method_get_class = new NativeFunction(
    mono_method_get_class_ptr, "pointer", ["pointer"]
);
 
var mono_class_get_name = new NativeFunction(
    mono_class_get_name_ptr, "pointer", ["pointer"]
);
 
var orig_mono_runtime_invoke = new NativeFunction(
    mono_runtime_invoke_ptr,
    "pointer",
    ["pointer", "pointer", "pointer", "pointer"]
);

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-12-28 13:11 被我是jet编辑 ,原因:
收藏
免费 7
支持
分享
最新回复 (4)
雪    币: 3
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
大佬可以来个apk的链接吗,网上找的都是没有arm64,lib的包体
2026-1-9 01:41
0
雪    币: 224
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
加一
2026-1-9 17:08
0
雪    币: 115
活跃值: (115)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
极限摩托(Trial X) apk:613K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2H3j5$3S2G2L8h3g2Q4x3X3g2F1k6i4c8Q4x3V1k6Y4j5h3#2W2M7#2)9J5c8U0f1#2z5o6f1K6y4#2)9J5k6h3S2@1L8h3H3`.
2026-1-11 08:53
0
雪    币: 5712
活跃值: (9732)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
2026-1-11 13:28
0
游客
登录 | 注册 方可回帖
返回