博客 / 詳情

返回

Unity Mono 安卓遊戲逆向實戰:APK 分析 + Frida Hook 繞過死亡判定

Android安卓遊戲Unity Mono 遊戲逆向實戰:從 APK 到 Hook libmono.so 繞過死亡判定

前言

最近在分析一款 極限摩托基於手機重力控制的 Unity 遊戲

game

  • 通過手機 前後翻轉控制角色
  • 人物只要 發生碰撞(翻車 / 頭部觸地)就會立即失敗
  • 沒有明顯的數值判定,屬於典型的 物理 + 碰撞觸發死亡

本文完整記錄了我 從 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.xml
  • lib/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 = 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"])
);

八、分析過程與關鍵突破

1️⃣ 先打印觀察調用

日誌中依次出現:

Fork::Update
Fork::OnCollisionStay
FailController::OnGUI
Bone::OnCollisionEnter

2️⃣ 排除錯誤目標

  • FailController::OnGUI
    👉 只是 UI 顯示失敗畫面,不是死亡原因

  • FailController::Start
    👉 失敗後的初始化邏輯


3️⃣ 真正的死亡觸發點

Bone::OnCollisionEnter

這正好符合遊戲機制:

人物因重力翻轉發生碰撞 → 立即失敗


九、最終效果

成功攔截後:

  • 人物發生碰撞 不再死亡
  • 物理系統正常
  • 遊戲流程可繼續

無需修改 APK
無需重打包
精準繞過失敗判定


十、總結

本文完整展示了一條 Unity Mono 遊戲逆向的通用思路

  1. 從 APK 判斷 Unity 架構
  2. 確認 Mono 而非 IL2CPP
  3. 鎖定 libmono.so
  4. Hook mono_runtime_invoke
  5. 通過 Runtime 級分析定位關鍵 C# 方法
  6. 精準攔截 OnCollisionEnter 實現邏輯繞過

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


後記

這套方法同樣適用於:

  • Unity Mono 手遊
  • 碰撞 / 判定 / 失敗邏輯分析
  • 無源碼、無符號環境下的動態逆向

後續我會繼續分享更多 Unity / Mono / Frida 實戰分析。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.