Unity获取动画参数

1.unity获取动画参数

import "frida-il2cpp-bridge";

declare const console: any;

Il2Cpp.perform(() => {

    console.log("🔥 DOTween Full Trace Start");

    // =========================================================
    // 配置
    // =========================================================

    const MAX_PRINT_PER_METHOD = 20;
    const PRINT_EVERY_AFTER_LIMIT = 200;

    const PRINT_ARGS = true;
    const PRINT_RET = false;

    const callCount: any = {};

    // =========================================================
    // 工具函数
    // =========================================================

    function shortClassName(cls: any) {

        try {

            const ns = cls.namespace;
            const name = cls.name;

            if (ns && ns.length > 0) {
                return ns + "." + name;
            }

            return name;

        } catch (e) {

            return "UnknownClass";
        }
    }

    function methodSignature(m: any) {

        try {

            const params = m.parameters
                .map((p: any) => {

                    try {
                        return p.type.name + " " + p.name;
                    } catch (e) {
                        return "?";
                    }

                })
                .join(", ");

            const ret = (() => {

                try {
                    return m.returnType.name;
                } catch (e) {
                    return "void";
                }

            })();

            return `${ret} ${m.name}(${params})`;

        } catch (e) {

            return `${m.name}(?)`;
        }
    }

    function fmtValue(v: any): string {

        try {

            if (v === null) return "null";
            if (v === undefined) return "undefined";

            const t = typeof v;

            if (
                t === "number" ||
                t === "boolean" ||
                t === "bigint"
            ) {
                return String(v);
            }

            if (t === "string") {
                return `"${v}"`;
            }

            // Il2Cpp.Object
            try {

                if (v.class && v.handle) {

                    const clsName =
                        shortClassName(v.class);

                    return `${clsName}@${v.handle}`;
                }

            } catch (e) {}

            // NativePointer
            try {

                if (v.isNull !== undefined) {
                    return `${v}`;
                }

            } catch (e) {}

            return String(v);

        } catch (e) {

            return "<fmt failed>";
        }
    }

    function shouldPrint(key: string): boolean {

        if (callCount[key] === undefined) {
            callCount[key] = 0;
        }

        callCount[key]++;

        const n = callCount[key];

        if (n <= MAX_PRINT_PER_METHOD) {
            return true;
        }

        if (n % PRINT_EVERY_AFTER_LIMIT === 0) {
            return true;
        }

        return false;
    }

    function findClass(className: string): any {

        for (const asm of Il2Cpp.domain.assemblies) {

            try {

                return asm.image.class(className);

            } catch (e) {}
        }

        return null;
    }

    // =========================================================
    // Unity Object Helpers
    // =========================================================

    function unityInvoke(
        obj: any,
        methodName: string
    ): any {

        try {

            return obj
                .method(methodName)
                .invoke();

        } catch (e) {

            return null;
        }
    }

    function unityName(obj: any): string {

        try {

            const n =
                unityInvoke(obj, "get_name");

            if (n) return String(n);

        } catch (e) {}

        try {

            return obj.name;

        } catch (e) {}

        return "Unknown";
    }

    function unityGameObject(obj: any): any {

        try {

            return unityInvoke(
                obj,
                "get_gameObject"
            );

        } catch (e) {

            return null;
        }
    }

    function unityTransform(obj: any): any {

        try {

            return unityInvoke(
                obj,
                "get_transform"
            );

        } catch (e) {

            return null;
        }
    }

    function unityParent(transform: any): any {

        try {

            return unityInvoke(
                transform,
                "get_parent"
            );

        } catch (e) {

            return null;
        }
    }

    function getTransformPath(
        transform: any
    ): string {

        try {

            let path =
                unityName(transform);

            let parent =
                unityParent(transform);

            while (parent) {

                path =
                    unityName(parent) +
                    "/" +
                    path;

                parent =
                    unityParent(parent);
            }

            return path;

        } catch (e) {

            return "UnknownPath";
        }
    }

    function dumpUnityObject(obj: any) {

        try {

            if (!obj) return;

            // =================================================
            // Transform
            // =================================================

            try {

                if (
                    obj.class &&
                    obj.class.name.indexOf(
                        "Transform"
                    ) >= 0
                ) {

                    console.log(
                        "🎯 Transform.name =",
                        unityName(obj)
                    );

//                     console.log(
//                         "🎯 Transform.path =",
//                         getTransformPath(obj)
//                     );

                    return;
                }

            } catch (e) {}

            // =================================================
            // Component
            // =================================================

            try {

                const go =
                    unityGameObject(obj);

                if (go) {

                    console.log(
                        "🎯 GameObject.name =",
                        unityName(go)
                    );

                    const tr =
                        unityTransform(obj);

                    if (tr) {

                        console.log(
                            "🎯 GameObject.path =",
                            getTransformPath(tr)
                        );
                    }

                    return;
                }

            } catch (e) {}

            // =================================================
            // Tween.target
            // =================================================

            try {

                const target =
                    obj.target;

                if (target) {

                    console.log(
                        "🎯 Tween.target =",
                        fmtValue(target)
                    );

                    const go =
                        unityGameObject(target);

                    if (go) {

                        console.log(
                            "🎯 Tween.target.name =",
                            unityName(go)
                        );

                        const tr =
                            unityTransform(target);

                        if (tr) {

                            console.log(
                                "🎯 Tween.target.path =",
                                getTransformPath(tr)
                            );
                        }
                    }
                }

            } catch (e) {}

        } catch (e) {

            console.log(
                "❌ dumpUnityObject failed"
            );
        }
    }

    // =========================================================
    // invoke original
    // =========================================================

    function invokeOriginal(
        method: any,
        self: any,
        args: any[]
    ) {

        // ctor 不 invoke
        if (method.name === ".ctor") {
            return;
        }

        try {

            if (method.isStatic) {
                return method.invoke(...args);
            }

            return method.invoke(
                self,
                ...args
            );

        } catch (e) {

            console.log(
                "❌ invoke original failed:",
                e
            );
        }
    }

    // =========================================================
    // 方法过滤
    // =========================================================

    function shouldHook(
        className: string,
        methodName: string
    ): boolean {

        // getter 太吵
        if (methodName.startsWith("get_")) {
            return false;
        }

        // 高频查询方法
        const noisy = [
            "Elapsed",
            "ElapsedPercentage",
            "Duration",
            "IsPlaying",
            "IsActive",
            "Update",
            "Evaluate"
        ];

        if (
            noisy.indexOf(methodName) >= 0
        ) {
            return false;
        }

        // =====================================================
        // DOTween
        // =====================================================

        if (
            className ===
            "DG.Tweening.DOTween"
        ) {

            const names = [
                "To",
                "Sequence",
                "DelayedCall",
                "Kill",
                "Play",
                "Pause",
                "Restart",
                "Clear",
                "Init"
            ];

            return (
                names.indexOf(methodName) >= 0
            );
        }

        // =====================================================
        // ShortcutExtensions
        // =====================================================

        if (
            className.indexOf(
                "DG.Tweening.ShortcutExtensions"
            ) >= 0
        ) {

            return methodName.startsWith(
                "DO"
            );
        }

        // =====================================================
        // TweenSettingsExtensions
        // =====================================================

        if (
            className ===
            "DG.Tweening.TweenSettingsExtensions"
        ) {

            if (
                methodName.startsWith("Set")
            ) {
                return true;
            }

            if (
                methodName.startsWith("On")
            ) {
                return true;
            }

            const names = [
                "Append",
                "Join",
                "Insert",
                "Prepend",
                "AppendCallback",
                "InsertCallback",
                "From"
            ];

            return (
                names.indexOf(methodName) >= 0
            );
        }

        // =====================================================
        // TweenExtensions
        // =====================================================

        if (
            className ===
            "DG.Tweening.TweenExtensions"
        ) {

            const names = [
                "Play",
                "Pause",
                "Restart",
                "Rewind",
                "Kill",
                "Complete",
                "Goto",
                "Flip",
                "ForceInit"
            ];

            return (
                names.indexOf(methodName) >= 0
            );
        }

        // =====================================================
        // TweenManager
        // =====================================================

        if (
            className ===
            "DG.Tweening.Core.TweenManager"
        ) {

            const names = [
                "AddActiveTween",
                "Despawn",
                "DoGoto",
                "Complete",
                "Kill",
                "ForceInit"
            ];

            return (
                names.indexOf(methodName) >= 0
            );
        }

        return false;
    }

    // =========================================================
    // Hook Class
    // =========================================================

    function hookClass(className: string) {

        const cls =
            findClass(className);

        if (!cls) {

            console.log(
                "⚠️ Class not found:",
                className
            );

            return;
        }

        console.log(
            "✅ Found class:",
            className
        );

        for (const m of cls.methods) {

            const methodName = m.name;

            if (
                !shouldHook(
                    className,
                    methodName
                )
            ) {
                continue;
            }

            const sig =
                methodSignature(m);

            const key =
                `${className}.${sig}`;

            try {

                console.log(
                    "🎯 Hook:",
                    key
                );

                m.implementation = function (
                    ...args: any[]
                ) {

                    const print =
                        shouldPrint(key);

                    const index =
                        callCount[key];

                    if (print) {

                        console.log(
                            "\n=============================="
                        );

                        console.log(
                            `🔥 [${index}] ${className}.${sig}`
                        );

                        // =====================================
                        // this
                        // =====================================

                        try {

//                             if (this) {
//
//                                 console.log(
//                                     "this =",
//                                     fmtValue(this)
//                                 );
//
//                                 dumpUnityObject(
//                                     this
//                                 );
//                             }

                        } catch (e) {}

                        // =====================================
                        // args
                        // =====================================

                        if (PRINT_ARGS) {

                            for (
                                let i = 0;
                                i < args.length;
                                i++
                            ) {

                                const a =
                                    args[i];

                                console.log(
                                    `arg[${i}] = ${fmtValue(a)}`
                                );

                                dumpUnityObject(
                                    a
                                );
                            }
                        }
                    }

                    const ret =
                        invokeOriginal(
                            m,
                            this,
                            args
                        );

                    if (
                        print &&
                        PRINT_RET
                    ) {

                        console.log(
                            "ret =",
                            fmtValue(ret)
                        );

                        dumpUnityObject(ret);
                    }

                    if (print) {

                        console.log(
                            "==============================\n"
                        );
                    }

                    return ret;
                };

            } catch (e) {

                console.log(
                    "❌ Hook failed:",
                    key,
                    e
                );
            }
        }
    }

    // =========================================================
    // 目标类
    // =========================================================

    const targetClasses = [

        "DG.Tweening.DOTween",

        "DG.Tweening.ShortcutExtensions",
        "DG.Tweening.ShortcutExtensions46",
        "DG.Tweening.ShortcutExtensions43",
        "DG.Tweening.ShortcutExtensionsTMPText",
        "DG.Tweening.ShortcutExtensionsTextMeshPro",
        "DG.Tweening.ShortcutExtensionsModuleUI",
        "DG.Tweening.ShortcutExtensionsModulePhysics",
        "DG.Tweening.ShortcutExtensionsModulePhysics2D",
        "DG.Tweening.ShortcutExtensionsModuleSprite",
        "DG.Tweening.ShortcutExtensionsModuleAudio",

        "DG.Tweening.TweenSettingsExtensions",
        "DG.Tweening.TweenExtensions",

        "DG.Tweening.Core.TweenManager"
    ];

    for (const clsName of targetClasses) {
        hookClass(clsName);
    }

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

相关阅读更多精彩内容

友情链接更多精彩内容