Frida brige使用

Unity

  • 測試環(huán)境
import "frida-il2cpp-bridge";

setImmediate(() => {
    Il2Cpp.perform(() => {
        console.log("Unity Version:", Il2Cpp.unityVersion);
        const image = Il2Cpp.domain.assembly("Assembly-CSharp")?.image;
        console.log("Image:", image);
    });
});
  • 查看所有的類
// 第一階段:Dump 所有類
import "frida-il2cpp-bridge";
setImmediate(() => {
    Il2Cpp.perform(() => {
        console.log("Unity:", Il2Cpp.unityVersion);
        const image = Il2Cpp.domain.assembly("Assembly-CSharp").image;
        console.log("Dumping classes...");

        // Dumping classes...
        // Found: AnalyzeData
        // Found: AnalyzeDataFlatBuffersDirect
        // Found: AnalyzeData
        // Found: AnalyzeDataVerify

        //         image.classes
        //             .filter(c => c.name.includes("AnalyzeData"))
        //             .forEach(c => console.log("Found:", c.name));
        image.classes.forEach(c => {
            console.log(c.namespace + "." + c.name);
        });
    });
});
  • 查看方法地址
import "frida-il2cpp-bridge";
Il2Cpp.perform(() => {
    const image = Il2Cpp.domain.assembly("Assembly-CSharp").image;
    image.classes.forEach(c => {
        c.methods.forEach(m => {
            console.log(
                c.name,
                m.name,
                "VA:",
                m.virtualAddress,
                "RVA:",
                m.relativeVirtualAddress
            );
        });
    });
});
  • 查看方法的信息
setImmediate(() => {

    Il2Cpp.perform(() => {
        const assembly = Il2Cpp.domain.assembly("Assembly-CSharp");
        const image = assembly.image;
        let output = "";
        image.classes.forEach(c => {
            output += `\n// Namespace: ${c.namespace}\n`;
            output += `class ${c.name}\n{\n`;
            // 字段
            c.fields.forEach(f => {
                output += `    ${f.type.name} ${f.name};\n`;
            });
            // 方法
            c.methods.forEach(m => {
                output += `    ${m.returnType.name} ${m.name}(...);\n`;
            });
            output += "}\n";
        });
        console.log(output)
    });
});
  • dump信息
'use strict';

const IL2CPP = "libil2cpp.so";
const il2cppMod = Process.getModuleByName(IL2CPP);
const BASE = il2cppMod.base;

function exp(name) {
  const p = Module.findExportByName(IL2CPP, name);
  if (!p) throw new Error("missing export: " + name);
  return p;
}
function cstr(p) { return p.isNull() ? "" : p.readCString(); }
function normalizeThumb(p) {
  if (Process.arch === "arm" && !p.isNull() && p.and(1).toInt32() === 1) return p.and(ptr("0xfffffffe"));
  return p;
}
function isExec(p) {
  if (p.isNull()) return false;
  const r = Process.findRangeByAddress(p);
  return r && r.protection.indexOf("x") !== -1;
}
function getImplFromMethodInfo(mi) {
  const cand = [0x0,0x4,0x8,0xC,0x10,0x14,0x18,0x1C,0x20,0x24,0x28,0x2C,0x30];
  for (const off of cand) {
    let p;
    try { p = mi.add(off).readPointer(); } catch (e) { continue; }
    const real = normalizeThumb(p);
    if (isExec(real)) return real;
  }
  return NULL;
}
function offOf(p) { return normalizeThumb(p).sub(BASE); }

const il2cpp_class_get_name      = new NativeFunction(exp("il2cpp_class_get_name"), "pointer", ["pointer"]);
const il2cpp_class_get_namespace = new NativeFunction(exp("il2cpp_class_get_namespace"), "pointer", ["pointer"]);
const il2cpp_method_get_name     = new NativeFunction(exp("il2cpp_method_get_name"), "pointer", ["pointer"]);
const il2cpp_method_get_class    = new NativeFunction(exp("il2cpp_method_get_class"), "pointer", ["pointer"]);
const il2cpp_class_get_methods   = new NativeFunction(exp("il2cpp_class_get_methods"), "pointer", ["pointer", "pointer"]);

// 你已經(jīng)有任意一個 MethodInfo* 的時候最好用它拿 klass。
// 但如果你沒有 seed,我們就走“找到一個 DTween 方法后用它擴展”。
// 這里先給一個函數(shù):給一個 MethodInfo*,打印它所屬類所有方法。
function dumpClassFromMethodInfo(methodInfo) {
  const klass = il2cpp_method_get_class(methodInfo);
  const ns = cstr(il2cpp_class_get_namespace(klass));
  const cn = cstr(il2cpp_class_get_name(klass));
  console.log(`\n===== ${ns}.${cn} =====`);

  const iter = Memory.alloc(Process.pointerSize);
  iter.writePointer(NULL);

  while (true) {
    const m = il2cpp_class_get_methods(klass, iter);
    if (m.isNull()) break;

    const mn = cstr(il2cpp_method_get_name(m));
    const impl = getImplFromMethodInfo(m);
    if (!impl.isNull()) {
      console.log(`${mn} -> ${impl} (off ${offOf(impl)})`);
    }
  }
}

globalThis.dumpClassFromMethodInfo = dumpClassFromMethodInfo;
console.log("[+] loaded. Call dumpClassFromMethodInfo(ptr('0xMETHODINFO'))");
  • 調(diào)用信息,以及參數(shù)
//最牛逼的一個
Il2Cpp.perform(() => {

    const Game = Il2Cpp.domain
        .assembly("Assembly-CSharp")
        .image
        .class("Game");

    console.log("[+] Tracing all Game methods");

    Il2Cpp.trace(true)
        .classes(Game)
        .and()
        .attach();
});

上面為腳本代碼

一個完整的使用代碼

  • python
import frida
import sys
import time


DEVICE = frida.get_usb_device(timeout=5)

# 1?? attach
session = DEVICE.attach("xxx")

# 2?? 先加載 frida-il2cpp-bridge
with open("../../resources/js/dump_il2cpp.js", "r", encoding="utf-8") as f:
    bridge_code = f.read()

bridge = session.create_script(bridge_code)
bridge.load()

print("? frida-il2cpp-bridge loaded")

# 3?? 再加載你自己的腳本
with open("../../resources/js/unity/il2cpp_dump_safe.js", "r", encoding="utf-8") as f:
    user_code = f.read()

script = session.create_script(user_code)
script.load()

print("?? user script loaded")

# 4?? 防止 Python 退出
sys.stdin.read()
  • 編譯ts
frida-compile .\dump_il2cpp.ts -o .\dump_il2cpp.js
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容