Dump unity SO And Class

1.查看一共有那些dll.
2.dump

import frida
import sys
import json
import os
from pathlib import Path

ROOT_OUTPUT_DIR = Path(r"E:\work\JigsawChaiBao\classInfo")
ROOT_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

ASSEMBLIES = [
    "Assembly-CSharp",
    "Coffee.UIEffect",
    "Coffee.UIParticle",
    "DOTween",
    "Facebook.Unity.Android",
    "Facebook.Unity.Settings",
    "Facebook.Unity",
    "Firebase.App",
    "Firebase.Crashlytics",
    "Firebase.Platform",
    "Gilzoide.SqliteNet",
    "Google.FlatBuffers",
    "Google.Play.Common",
    "Newtonsoft.Json",
    "System.Core",
    "System.Data",
    "System.Numerics",
    "System.Runtime.Serialization",
    "System",
    "Unity.TextMeshPro",
    "Unity.Timeline",
    "UnityEngine.AndroidJNIModule",
    "UnityEngine.AnimationModule",
    "UnityEngine.AssetBundleModule",
    "UnityEngine.AudioModule",
    "UnityEngine.CoreModule",
    "UnityEngine.DirectorModule",
    "UnityEngine.IMGUIModule",
    "UnityEngine.InputLegacyModule",
    "UnityEngine.ParticleSystemModule",
    "UnityEngine.Physics2DModule",
    "UnityEngine.PhysicsModule",
    "UnityEngine.PropertiesModule",
    "UnityEngine.SpriteShapeModule",
    "UnityEngine.TextCoreFontEngineModule",
    "UnityEngine.TextRenderingModule",
    "UnityEngine.UI",
    "UnityEngine.UIElementsModule",
    "UnityEngine.UIModule",
    "UnityEngine.UnityWebRequestModule",
    "UnityEngine.VideoModule",
    "com.beatles.unity.ui",
    "com.learnings.download-unity",
    "com.learnings.unity.assetbundle",
    "com.learnings.unity.log",
    "com.learnings.unity.nativeutil-unity",
    "com.learnings.unity.storage.flatbuffers",
    "com.learnings.unity.unikit.runtime",
    "i2",
    "mscorlib",
    "spine-csharp",
    "spine-timeline",
    "spine-unity"
]

PACKAGE_NAME = "jigsawcard"
JS_FILE = "dump_class_il2cpp.js"


TYPE_MAP = {
    "System.Void": "void",
    "System.Boolean": "bool",
    "System.Byte": "uint8",
    "System.SByte": "int8",
    "System.Int16": "int16",
    "System.UInt16": "uint16",
    "System.Int32": "int32",
    "System.UInt32": "uint32",
    "System.Int64": "int64",
    "System.UInt64": "uint64",
    "System.Single": "float",
    "System.Double": "double",
    "System.IntPtr": "void *",
    "System.UIntPtr": "void *",
    "System.String": "void *",
    "System.Object": "void *",
}

def to_c_type(il2cpp_type: str) -> str:
    if not il2cpp_type:
        return "void *"

    t = il2cpp_type.strip()

    if "<" in t or ">" in t:
        return "void *"
    if t.endswith("[]"):
        return "void *"
    if t.endswith("&"):
        base = t[:-1]
        return to_c_type(base) + " *"

    return TYPE_MAP.get(t, "void *")

def escape_name(name: str) -> str:
    if not name:
        return ""
    return (
        name.replace("<", "_")
            .replace(">", "_")
            .replace(" ", "_")
            .replace(":", "_")
            .replace(",", "_")
    )

def safe_dir_name(name: str) -> str:
    bad = '<>:"/\\|?*'
    for ch in bad:
        name = name.replace(ch, "_")
    return name

def build_ida_prototype(item: dict) -> str:
    func_name = escape_name(item.get("name", "")) or "sub_unknown"
    ret = to_c_type(item.get("returnType", ""))

    params = item.get("params", []) or []
    is_static = bool(item.get("isStatic", False))

    c_params = []

    if not is_static:
        c_params.append("void *this")

    for i, p in enumerate(params):
        if isinstance(p, dict):
            p_name = p.get("name", f"arg{i}")
            p_type = p.get("type", "")
        else:
            p_name = f"arg{i}"
            p_type = ""

        ctype = to_c_type(p_type)
        p_name = escape_name(p_name) or f"arg{i}"
        c_params.append(f"{ctype} {p_name}")

    if not c_params:
        c_params = ["void"]

    return f"{ret} {func_name}({', '.join(c_params)});"

def write_ida_script(dump_data, ida_path: Path):
    with open(ida_path, "w", encoding="utf-8") as f:
        f.write("import idaapi\n")
        f.write("import idc\n")
        f.write("import ida_funcs\n")
        f.write("import ida_typeinf\n\n")

        f.write("base = idaapi.get_imagebase()\n")
        f.write("renamed = 0\n")
        f.write("typed = 0\n")
        f.write("fields_applied = 0\n\n")

        for item in dump_data:
            rva = item.get("rva")
            name = item.get("name")

            if rva is None or not name:
                continue

            safe_name = escape_name(name)

            f.write(f"ea = base + 0x{int(rva):x}\n")

            f.write("fn = ida_funcs.get_func(ea)\n")
            f.write("if fn:\n")

            # =========================
            # 1. rename function
            # =========================
            f.write(f"    if idc.set_name(ea, \"{safe_name}\", idc.SN_NOWARN):\n")
            f.write("        renamed += 1\n")

            # =========================
            # 2. set prototype
            # =========================
            proto = build_ida_prototype(item).replace("\\", "\\\\").replace("\"", "\\\"")

            f.write("    try:\n")
            f.write(f"        proto = \"{proto}\"\n")
            f.write("        if idc.SetType(ea, proto):\n")
            f.write("            typed += 1\n")
            f.write("    except:\n")
            f.write("        pass\n")

            # =========================
            # 3. fields comment attach
            # =========================
            fields = item.get("fields", [])

            if fields:
                f.write("    # ===== Fields =====\n")
                for fd in fields:
                    fname = escape_name(fd.get("name", ""))
                    ftype = fd.get("type", "")
                    offset = fd.get("offset", 0)

                    f.write(
                        f"    # {fname} : {ftype} @0x{int(offset):x}\n"
                    )

                f.write("    # ==================\n")

            f.write("\n")

        f.write("print('[+] renamed =', renamed)\n")
        f.write("print('[+] typed =', typed)\n")


def save_dump_result(assembly_name: str, payload: dict):
    out_dir = ROOT_OUTPUT_DIR / safe_dir_name(assembly_name)
    out_dir.mkdir(parents=True, exist_ok=True)

    json_path = out_dir / "il2cpp_dump_v2.json"
    with open(json_path, "w", encoding="utf-8") as f:
        json.dump(payload["data"], f, indent=2, ensure_ascii=False)

    ida_path = out_dir / "ida_apply_il2cpp_dump_v2.py"
    write_ida_script(payload["data"], ida_path)

    print(f"[+] Saved JSON: {json_path}")
    print(f"[+] Saved IDA : {ida_path}")

def main():
    device = frida.get_usb_device()
    session = device.attach(PACKAGE_NAME)

    with open(JS_FILE, "r", encoding="utf-8") as f:
        script_code = f.read()

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

    print("[*] Attached and script loaded.")

    for asm in ASSEMBLIES:
        print(f"\n[*] Dumping assembly: {asm}")
        try:
            payload = script.exports_sync.dumpassembly(asm)
        except Exception as e:
            print(f"[!] RPC failed for {asm}: {e}")
            continue

        if not payload.get("ok"):
            print(f"[!] Dump failed: {asm}")
            print(f"    error = {payload.get('error')}")
            continue

        print(f"[+] OK: input={payload.get('input')} used={payload.get('usedName')} count={payload.get('count')}")
        save_dump_result(asm, payload)

    print("\n[+] All done.")
    session.detach()

if __name__ == "__main__":
    main()

脚本写法

import "frida-il2cpp-bridge";

type DumpParam = {
    name: string;
    type: string;
};

type DumpField = {
    name: string;
    type: string;
    isStatic: boolean;
    offset: number;
};

type DumpItem = {
    module: string;
    namespace: string;
    class: string;

    method: string;
    name: string;
    rva: number;

    returnType: string;
    params: DumpParam[];
    isStatic: boolean;

    fields: DumpField[];

    assembly: string;
    image: string;
};

type DumpOkResult = {
    ok: true;
    input: string;
    usedName: string;
    imageName: string;
    count: number;
    data: DumpItem[];
};

type DumpFailResult = {
    ok: false;
    input: string;
    error: string;
    stack: string;
};

type DumpResult = DumpOkResult | DumpFailResult;

function sanitizeAssemblyName(name: string): string {
    if (!name) return "";
    return name.endsWith(".dll") ? name.slice(0, -4) : name;
}

function errorToString(e: unknown): { error: string; stack: string } {
    if (e instanceof Error) {
        return {
            error: e.message || String(e),
            stack: e.stack || ""
        };
    }
    return {
        error: String(e),
        stack: ""
    };
}

rpc.exports = {
    dumpassembly(name: string): Promise<DumpResult> {
        return new Promise((resolve) => {
            try {
                Il2Cpp.perform(() => {
                    try {
                        const result: DumpItem[] = [];
                        const exported = new Set<string>();

                        const rawName = String(name || "").trim();

                        const candidates = [...new Set([
                            rawName,
                            sanitizeAssemblyName(rawName),
                            rawName + ".dll"
                        ].filter(Boolean))];

                        let assembly: Il2Cpp.Assembly | null = null;
                        let usedName: string | null = null;

                        for (const n of candidates) {
                            try {
                                const a = Il2Cpp.domain.assembly(n);
                                if (a) {
                                    assembly = a;
                                    usedName = n;
                                    break;
                                }
                            } catch (_) {}
                        }

                        if (!assembly || !usedName) {
                            resolve({
                                ok: false,
                                input: rawName,
                                error: "assembly not found",
                                stack: ""
                            });
                            return;
                        }

                        const image = assembly.image;

                        image.classes.forEach((c: Il2Cpp.Class) => {

                            // =========================
                            // 1. Fields dump
                            // =========================
                            const fields: DumpField[] = [];

                            try {
                                c.fields.forEach((f: Il2Cpp.Field) => {
                                    let typeName = "";
                                    try {
                                        typeName = String(f.type?.name ?? "");
                                    } catch (_) {}

                                    let offset = 0;
                                    try {
                                        offset = Number(f.offset ?? 0);
                                    } catch (_) {}

                                    let isStatic = false;
                                    try {
                                        isStatic = !!f.isStatic;
                                    } catch (_) {}

                                    fields.push({
                                        name: String(f.name ?? ""),
                                        type: typeName,
                                        isStatic,
                                        offset
                                    });
                                });
                            } catch (_) {}

                            // =========================
                            // 2. Methods dump
                            // =========================
                            c.methods.forEach((m: Il2Cpp.Method) => {
                                try {
                                    if (!m.virtualAddress) return;

                                    const va = m.virtualAddress;

                                    const module = Process.findModuleByAddress(va);
                                    if (!module) return;

                                    const key = va.toString();
                                    if (exported.has(key)) return;
                                    exported.add(key);

                                    const rva = va.sub(module.base);

                                    const cleanClass = String(c.name ?? "").replace(/[^a-zA-Z0-9_]/g, "_");
                                    const cleanMethod = String(m.name ?? "").replace(/[^a-zA-Z0-9_]/g, "_");
                                    const newName = `${cleanClass}__${cleanMethod}`;

                                    const params: DumpParam[] = [];
                                    try {
                                        for (const p of m.parameters) {
                                            params.push({
                                                name: String(p.name ?? ""),
                                                type: String(p.type?.name ?? "")
                                            });
                                        }
                                    } catch (_) {}

                                    let returnType = "";
                                    try {
                                        returnType = String(m.returnType?.name ?? "");
                                    } catch (_) {}

                                    let isStatic = false;
                                    try {
                                        isStatic = !!m.isStatic;
                                    } catch (_) {}

                                    result.push({
                                        module: String(module.name ?? ""),
                                        namespace: String(c.namespace ?? ""),
                                        class: String(c.name ?? ""),

                                        method: String(m.name ?? ""),
                                        name: newName,
                                        rva: Number(rva),

                                        returnType,
                                        params,
                                        isStatic,

                                        fields,   // ✅ 加在 class 级别

                                        assembly: String(image.name ?? ""),
                                        image: String(image.name ?? "")
                                    });

                                } catch (_) {}
                            });
                        });

                        resolve({
                            ok: true,
                            input: rawName,
                            usedName: String(usedName),
                            imageName: String(image.name ?? ""),
                            count: result.length,
                            data: result
                        });

                    } catch (e: unknown) {
                        const err = errorToString(e);
                        resolve({
                            ok: false,
                            input: String(name || ""),
                            error: err.error,
                            stack: err.stack
                        });
                    }
                });
            } catch (e: unknown) {
                const err = errorToString(e);
                resolve({
                    ok: false,
                    input: String(name || ""),
                    error: err.error,
                    stack: err.stack
                });
            }
        });
    }
};

dump so

import frida

PACKAGE = "jigsawcard"
JS_FILE = "dump_so_memory.js"

OUT_FILE = "libil2cpp_dump.so"


def main():
    device = frida.get_usb_device()
    session = device.attach(PACKAGE)

    file = open(OUT_FILE, "wb")

    def on_message(message, data):
        if message["type"] == "send":
            payload = message["payload"]

            if payload["type"] == "chunk":
                file.write(data)   # ✅ 真正二进制在 data 里

            elif payload["type"] == "info":
                print("[*] base:", payload["base"])
                print("[*] size:", payload["size"])

            elif payload["type"] == "done":
                print("[+] dump finished")
                file.close()
                session.detach()

    with open(JS_FILE, "r", encoding="utf-8") as f:
        script = session.create_script(f.read())

    script.on("message", on_message)
    script.load()

    print("[*] dumping...")

    script.exports_sync.dumpso()

    import sys
    sys.stdin.read()


if __name__ == "__main__":
    main()

ts

rpc.exports = {
    dumpso() {
        const mod = Process.findModuleByName("libil2cpp.so");
        if (!mod) return { ok: false };

        const base = mod.base;
        const size = mod.size;
        const chunk = 0x10000;

        send({ type: "info", base: base.toString(), size });

        for (let off = 0; off < size; off += chunk) {
            const len = Math.min(chunk, size - off);
            const ptr = base.add(off);

            const buf = Memory.readByteArray(ptr, len);

            // ✅ 正确:第二个参数传 binary
            send({
                type: "chunk",
                offset: off,
                size: len
            }, buf);
        }

        send({ type: "done" });

        return { ok: true };
    }
};
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 拆弹专家,原谷歌游戏downloadUrl:https://ww.lanzous.com/id06yjc(有广告版...
    约你一起偷西瓜阅读 12,064评论 3 6
  • 动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如库)作为加载过...
    小5筒阅读 5,855评论 0 3
  • 常用模块 认识模块 什么是模块 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文...
    go以恒阅读 2,187评论 0 6
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 8,184评论 0 27
  • 先执行IDA动态调试步骤 在JNI_ONLOAD下断点,越往后越好,按ctrl+s查看节点信息,后面的R表示读,W...
    Alanone0x0阅读 1,882评论 0 1

友情链接更多精彩内容