Skip to content

关于obj直接invoke的建议 #52

@axhlzy

Description

@axhlzy

ps:本来想直接提交pr的,但是看到你的项目好像转移到另一个github账号了,就直接这样给你反馈吧

很多时候我想使用unity obj直接去调用obj下的方法,然后看了一下你的源码,发现有几处可以优化一下

这里举例说明一下我想实现的效果:

    // [-]Assembly-CSharp @ 0x78eebf5220
    //  [-]Assembly-CSharp.dll @ 0x79806bed60 | C:433
    //    [-]IronSourceManager @ 0x77a03b2900 | M:90 | F:13
    //      [-]public Boolean ShowReward(UnityEvent onCompleted, UnityEvent onFailed) @ MI: 0x77a03d30a0 & MP: 0x788db69e28 & RP: 0xbe5e28
    //        [-]onCompleted         | type: 0x788ea15c28 | @ class:0x78eedf6540 | UnityEngine.Events.UnityEvent
    //        [-]onFailed            | type: 0x788ea15c28 | @ class:0x78eedf6540 | UnityEngine.Events.UnityEvent
    //        [-]_RET_               | type: 0x788e9f97b8 | @ class:0x78eede4300 | System.Boolean
    static auto Class_IronSourceManager = UnityResolve::Get("Assembly-CSharp.dll")
            ->Get("IronSourceManager");
    for (auto *method : Class_IronSourceManager->methods) {
        logd("IronSourceManager %s", method->name.c_str());
        if (method->name == "ShowReward") {
            HookManager::registerHook(method->function, *[](void *instance, UnityResolve::UnityType::Object *onCompleted, UnityResolve::UnityType::Object *onFailed) {
                logd("called IronSourceManager ShowReward");

                // ------------------------------------------------------
                //| Found 6 Methods  in class: UnityEvent @ 0x78f02ec2c0 |
                // ------------------------------------------------------
                //[*] 0x789e322ef0 ---> 0x7890926bd8 ---> 0xa53bd8        |  public Void .ctor()
                //[*] 0x789e322f40 ---> 0x7890926cb4 ---> 0xa53cb4        |  public Void AddListener(UnityAction call)
                //[*] 0x789e323080 ---> 0x7890926ff4 ---> 0xa53ff4        |  public Void Invoke()
                //[*] 0x789e322f90 ---> 0x7890926d6c ---> 0xa53d6c        |  protected override MethodInfo FindMethod_Impl(String name, Type targetObjType)
                //[*] 0x789e323030 ---> 0x7890926cf0 ---> 0xa53cf0        |  private static BaseInvokableCall GetDelegate(UnityAction action)
                //[*] 0x789e322fe0 ---> 0x7890926f84 ---> 0xa53f84        |  internal override BaseInvokableCall GetDelegate(Object target, MethodInfo theFunction)
                onCompleted->invokeMethod<void>("Invoke");
            });
        }
    });

我希望通过obj直接去调用obj(所属类"UnityEngine.Events.UnityEvent")下面的invoke方法,按照你现在的代码逻辑还得去获取一遍,就不太方便,我这里为obj多封装了两个函数

struct Object {
            union {
                void *klass{nullptr};
                void *vtable;
            } Il2CppClass;

            struct MonitorData *monitor{nullptr};

            auto GetType() -> CsType * {
                static Method *method;
                if (!method)
                    method = Get("mscorlib.dll")->Get("Object", "System")->Get<Method>("GetType");
                if (method)
                    return method->Invoke<CsType *>(this);
                return nullptr;
            }

            auto ToString() -> String * {
                static Method *method;
                if (!method)
                    method = Get("mscorlib.dll")->Get("Object", "System")->Get<Method>("ToString");
                if (method)
                    return method->Invoke<String *>(this);
                return {};
            }

            int GetHashCode() {
                static Method *method;
                if (!method)
                    method = Get("mscorlib.dll")->Get("Object", "System")->Get<Method>("GetHashCode");
                if (method)
                    return method->Invoke<int>(this);
                return 0;
            }

            [[nodiscard]] auto tryMethod(const std::string &name, const std::vector<std::string> &args = {}) const {
                UnityResolve::Class clazz(this->Il2CppClass.klass);
                return clazz.Get<UnityResolve::Method>(name, args);
            }

            template<typename T>
            T invokeMethod(const std::string &name, const std::vector<std::string> &args = {}, const std::vector<void *> &params = {}) {
                auto method = tryMethod(name, args);
                if (!method) {
                    if constexpr (!std::is_void_v<T>)
                        return T{};
                    else
                        return;
                }
                if constexpr (std::is_void_v<T>) {
                    method->Invoke<void>(this, params);
                } else {
                    return method->Invoke<T>(this, params);
                }
            }

        };

以及修改了一下UnityResolve::Class的构造函数

    struct Class final {
        void *address{};
        std::string name;
        std::string parent;
        std::string namespaze;
        std::vector<Field *> fields;
        std::vector<Method *> methods;
        void *objType{};

        Class()= default;

        explicit Class(void* pClass){
            this->address = pClass;
            this->name = Invoke<const char *>("il2cpp_class_get_name", pClass);
            if (const auto pPClass = Invoke<void *>("il2cpp_class_get_parent", pClass))
                this->parent = Invoke<const char *>("il2cpp_class_get_name", pPClass);
            this->namespaze = Invoke<const char *>("il2cpp_class_get_namespace", pClass);

            ForeachFields(this, pClass);
            ForeachMethod(this, pClass);

            void *i_class;
            void *iter{};
            do {
                if ((i_class = Invoke<void *>("il2cpp_class_get_interfaces", pClass, &iter))) {
                    ForeachFields(this, i_class);
                    ForeachMethod(this, i_class);
                }
            } while (i_class);
        }
       
        ......

    }

这样一来我们就可以直接方便的去访问类实例下面的函数

总的来说,我是觉得他不应该一开始就遍历完了,然后就写"死了",这样的操作方法多了性能表现很差不说而且也不够灵活
而是需要的时候去构造Class(ptr)得到一个解析好的class,需要什么构造什么 ...
其实就是内存地址和类型的随时任意的转换,这样才更像是一个灵活的工具

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions