{"id":24003298,"url":"https://github.com/jadis0x/il2cpp-reverse-engineering-guide","last_synced_at":"2025-04-14T23:42:55.003Z","repository":{"id":183465357,"uuid":"670167159","full_name":"jadis0x/il2cpp-reverse-engineering-guide","owner":"jadis0x","description":"This guide provides illustrative examples demonstrating the usage of Il2cppInspector C++ scaffold.","archived":false,"fork":false,"pushed_at":"2025-02-03T16:12:41.000Z","size":10160,"stargazers_count":154,"open_issues_count":0,"forks_count":17,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-14T23:42:46.500Z","etag":null,"topics":["il2cpp","il2cpp-guide","il2cpp-hacking","il2cpp-modding","il2cpp-tutorial","il2cppinspector","unity"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jadis0x.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"buy_me_a_coffee":"jadis0x"}},"created_at":"2023-07-24T12:46:24.000Z","updated_at":"2025-04-14T12:49:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"e06c0105-d03f-488f-999b-5b16e67c4a51","html_url":"https://github.com/jadis0x/il2cpp-reverse-engineering-guide","commit_stats":null,"previous_names":["jadis0x/il2cpp-reverse-engineering-guide","vaeloria/il2cpp-reverse-engineering-guide"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jadis0x%2Fil2cpp-reverse-engineering-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jadis0x%2Fil2cpp-reverse-engineering-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jadis0x%2Fil2cpp-reverse-engineering-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jadis0x%2Fil2cpp-reverse-engineering-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jadis0x","download_url":"https://codeload.github.com/jadis0x/il2cpp-reverse-engineering-guide/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248981259,"owners_count":21193143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["il2cpp","il2cpp-guide","il2cpp-hacking","il2cpp-modding","il2cpp-tutorial","il2cppinspector","unity"],"created_at":"2025-01-08T01:09:54.044Z","updated_at":"2025-04-14T23:42:54.992Z","avatar_url":"https://github.com/jadis0x.png","language":"C","funding_links":["https://buymeacoffee.com/jadis0x"],"categories":[],"sub_categories":[],"readme":"\n[![GitHub stars](https://img.shields.io/github/stars/jadis0x/il2cpp-reverse-engineering-guide.svg?style=flat\u0026label=Stars\u0026color=ffcc66)](https://github.com/jadis0x/il2cpp-reverse-engineering-guide/stargazers)\n[![GitHub contributors](https://img.shields.io/github/contributors/jadis0x/il2cpp-reverse-engineering-guide.svg)](https://github.com/jadis0x/il2cpp-reverse-engineering-guide/graphs/contributors)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\n\u003ch3 align=\"center\"\u003eIl2cppInspector: C++ Scaffold Guide\u003c/h3\u003e\n\n\u003cp\u003eHello! I have decided to share some useful examples regarding the usage of Il2cppInspector C++ scaffold. In this guide, I will provide examples of how to interact with defined Il2cpp API functions.\u003c/p\u003e\n\n### Installation\nYou can get the latest version of Il2CppInspectorPro 2025.2 [here](https://github.com/jadis0x/Il2CppInspectorPro/releases/tag/2025.2).\n\n### Requirements\nHaving knowledge of C++ and C# is essential. You should also be familiar with the basics of the Unity game engine.\n\n\u003e [!NOTE]  \n\u003e I wrote my own helper class. You can access it under the lib folder. Throughout the guide, I will be using the helper functions I created.\n  \n## Video\n[![Video](https://img.youtube.com/vi/L7s2ttcNEh0/0.jpg)](https://www.youtube.com/watch?v=L7s2ttcNEh0)\n\n## Contact\nIf you have any questions, feel free to reach out to me.\u003c/br\u003e\n\nDiscord: Jadis0x \u003c/br\u003e\nSteam: Jadis0x\n\n## Examples\n\u003e [!TIP]\n\u003e You can find more detailed examples by taking a look at [HERE](https://github.com/ALittlePatate/DevourClient) using the Il2cppInspector analysis tool I used to create the cheat.\n\n## Contents\n\n\u003cnav\u003e\n  \u003cul\u003e\n    \u003cli\u003e\u003ca href=\"#get_assemblies\"\u003eGet the assemblies\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#type_usage\"\u003eConverting an Il2CppObject* to Type* and Understanding Its Usage\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#get_class_names_types\"\u003eGetting class names and types from a specific assembly\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#get_info_method\"\u003eGetting information about any method\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#call_function\"\u003eExecuting a Method Using \"il2cpp_runtime_invoke\"\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#list_all_functions\"\u003eGetting a List of All Functions in the Target Class\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#get_field_info\"\u003eGetting Information about Class Fields (FieldInfo)\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#modify_field\"\u003eChanging the Value of a Class Field\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#write_FindObjectOfType_function\"\u003eCreating a Helper Function to Find Objects of a Specific Type (\"FindObjectOfType\")\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#readingProperty\"\u003eReading and Managing Static and Instance Properties\u003c/a\u003e\u003c/li\u003e\n  \u003c/ul\u003e\n\u003c/nav\u003e\n\n\u003ch2 id=\"get_assemblies\"\u003eGet the assemblies\u003c/h2\u003e\n\n\u003cspan\u003eThis code snippet demonstrates how to retrieve a list of all assemblies within the active domain using il2cpp API functions.\u003c/span\u003e\n\n```cpp\n// Get the active domain\nconst Il2CppDomain* domain = il2cpp_domain_get();\n\n// Define variables to hold the assembly list\nconst Il2CppAssembly** assemblies;\nsize_t size;\n\n// Use the il2cpp_domain_get_assemblies function to retrieve all assemblies\nassemblies = il2cpp_domain_get_assemblies(domain, \u0026size);\n\n// Iterate through each assembly in the list\nfor (size_t i = 0; i \u003c size; ++i) {\n    const Il2CppAssembly* assembly = assemblies[i];\n\n    if (assembly) {\n        // Get the assembly name using il2cpp_image_get_name function\n        const char* assemblyName = il2cpp_image_get_name(assembly-\u003eimage);\n        \n        // Print the name of the assembly to the console\n        std::cout \u003c\u003c assemblyName \u003c\u003c \"\\n\";\n    }\n}\n```\n\n\u003ch2\u003eSummary of Get the assemblies\u003c/h2\u003e\n\n\u003col\u003e\n    \u003cli\u003e\n        \u003cstrong\u003eGet the Active Domain:\u003c/strong\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003cstrong\u003eFunction:\u003c/strong\u003e \u003ccode\u003eil2cpp_domain_get\u003c/code\u003e\u003c/li\u003e\n            \u003cli\u003e\u003cstrong\u003eDescription:\u003c/strong\u003e Retrieves the active domain (\u003ccode\u003eIl2CppDomain\u003c/code\u003e) where the program is currently running.\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n        \u003cstrong\u003eRetrieve Assemblies:\u003c/strong\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003cstrong\u003eFunction:\u003c/strong\u003e \u003ccode\u003eil2cpp_domain_get_assemblies\u003c/code\u003e\u003c/li\u003e\n            \u003cli\u003e\u003cstrong\u003eDescription:\u003c/strong\u003e Retrieves a list of all assemblies (\u003ccode\u003eIl2CppAssembly\u003c/code\u003e) within the specified domain (\u003ccode\u003eIl2CppDomain\u003c/code\u003e). The function returns an array of \u003ccode\u003eIl2CppAssembly\u003c/code\u003e pointers (\u003ccode\u003eassemblies\u003c/code\u003e) and updates the \u003ccode\u003esize\u003c/code\u003e variable with the number of assemblies found.\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n        \u003cstrong\u003eIterate Through Assemblies:\u003c/strong\u003e\n        \u003cul\u003e\n            \u003cli\u003eUsing a \u003ccode\u003efor\u003c/code\u003e loop, iterate through each assembly in the \u003ccode\u003eassemblies\u003c/code\u003e array.\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n        \u003cstrong\u003eGet Assembly Name:\u003c/strong\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003cstrong\u003eFunction:\u003c/strong\u003e \u003ccode\u003eil2cpp_image_get_name\u003c/code\u003e\u003c/li\u003e\n            \u003cli\u003e\u003cstrong\u003eDescription:\u003c/strong\u003e Retrieves the name of the assembly associated with the given image (\u003ccode\u003eIl2CppImage\u003c/code\u003e) within the assembly structure (\u003ccode\u003eIl2CppAssembly\u003c/code\u003e). It returns a \u003ccode\u003econst char*\u003c/code\u003e containing the assembly name.\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n        \u003cstrong\u003ePrint Assembly Names:\u003c/strong\u003e\n        \u003cul\u003e\n            \u003cli\u003ePrint each assembly name retrieved from \u003ccode\u003eil2cpp_image_get_name\u003c/code\u003e to the console (\u003ccode\u003estd::cout\u003c/code\u003e).\u003c/li\u003e\n        \u003c/ul\u003e\n    \u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eOutput: \u003c/p\u003e\n\u003cimg src=\"img/1.png\" width=\"650\"\u003e\n\n\u003cbr\u003e\n\n\u003ch2 id=\"type_usage\"\u003eConverting an Il2CppObject* to Type* and Understanding Its Usage\u003c/h2\u003e\n\nTo obtain the type information here, we will use the GetTypeFromClass function inside my Il2cppHelper class.\n\n```cpp\nIl2CppObject* Il2CppHelper::GetTypeFromClass(const Il2CppImage* image, const char* namespaze, const char* className)\n{\n    if (!image) {\n        return nullptr;\n    }\n\n    // Retrieve the Il2CppClass pointer\n    Il2CppClass* targetClass = il2cpp_class_from_name(image, namespaze, className);\n    if (!targetClass) {\n        return nullptr;\n    }\n\n    // Retrieve the Il2CppType pointer\n    const Il2CppType* targetType = il2cpp_class_get_type(targetClass);\n    if (!targetType) {\n        return nullptr;\n    }\n\n    // Retrieve the Il2CppObject pointer\n    return il2cpp_type_get_object(targetType); // If it fails, nullptr will be returned.\n}\n```\n\n\u003cspan\u003eFirst, load the CoreModule from Unity, which contains many fundamental classes such as GameObject.\u003c/span\u003e\n\n```cpp\nconst Il2CppImage* _CoreModule = _helper-\u003eGetImage(\"UnityEngine.CoreModule.dll\");\n```\n\n\u003cspan\u003eIf the module is successfully loaded, use the GetTypeFromClass function to get the type information for the GameObject class.\u003c/span\u003e\n\n```cpp\nif (_CoreModule) {\n    // Get the type information for the GameObject class in the UnityEngine namespace\n    Il2CppObject* objectType = _helper-\u003eGetTypeFromClass(_CoreModule, \"UnityEngine\", \"GameObject\");\n\n    // Ensure the type information is retrieved successfully\n    if (!objectType) {\n        std::cout \u003c\u003c \"Failed to retrieve GameObject type.\\n\";\n        return;\n    }\n\n    // Cast Il2CppObject to Type\n    Type* gameObjectType = reinterpret_cast\u003cType*\u003e(objectType);\n    if (!gameObjectType) {\n        std::cout \u003c\u003c \"Failed to cast to Type.\\n\";\n        return;\n    }\n\n    // Find all GameObject instances\n    Object_1__Array* allGameObjects = Object_1_FindObjectsOfType(gameObjectType, nullptr);\n    if (!allGameObjects) {\n        std::cout \u003c\u003c \"No GameObjects found.\\n\";\n        return;\n    }\n\n    // Print the count of GameObject instances\n    std::cout \u003c\u003c \"GameObject count: \" \u003c\u003c allGameObjects-\u003emax_length \u003c\u003c \"\\n\";\n\n    // Iterate through each GameObject instance\n    for (int i = 0; i \u003c allGameObjects-\u003emax_length; i++) {\n        Object_1* currentGameObject = allGameObjects-\u003evector[i];\n        if (!currentGameObject) {\n            continue; // Skip null objects\n        }\n\n        // Check if the GameObject is active in the hierarchy\n        GameObject* gameObject = reinterpret_cast\u003cGameObject*\u003e(currentGameObject);\n        if (gameObject \u0026\u0026 GameObject_get_activeInHierarchy(gameObject, nullptr)) {\n            // Print the name of the active GameObject\n            std::cout \u003c\u003c \"GameObject Name: \" \n                      \u003c\u003c il2cppi_to_string(Object_1_GetName(currentGameObject, nullptr)) \n                      \u003c\u003c \"\\n\";\n        }\n    }\n}\n```\n\n\u003cspan\u003eIn this example, we are passing the type of the object to be found (GameObject) as a parameter to the Object_1_FindObjectsOfType function. This actually allows us to achieve the following:\u003c/span\u003e\n\n```cpp\nGameObject[] allGameObjects = FindObjectsOfType\u003cGameObject\u003e();\n```\n\n\u003e This function is quite slow. Using this function every frame is not recommended.\n\n\u003ch2\u003eSummary of the Steps and il2cpp API Functions Used\u003c/h2\u003e\n\n\u003col\u003e\n  \u003cli\u003eLoading the Image:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eGetImage\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Loads the \u003ccode\u003eCoreModule\u003c/code\u003e image from Unity, which contains fundamental classes like \u003ccode\u003eGameObject\u003c/code\u003e.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eRetrieving Class Information:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eil2cpp_class_from_name\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Retrieves class information using the image, namespace, and class name.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eGetting Type Information from Class:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eil2cpp_class_get_type\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Obtains the type information from the class.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eGetting Il2CppObject from Type:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eil2cpp_type_get_object\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Converts type information into an \u003ccode\u003eIl2CppObject\u003c/code\u003e.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eCasting Il2CppObject to Type:\n    \u003cul\u003e\n      \u003cli\u003eOperation: \u003ccode\u003ereinterpret_cast\u0026lt;Type*\u0026gt;\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Casts the retrieved \u003ccode\u003eIl2CppObject\u003c/code\u003e to \u003ccode\u003eType\u003c/code\u003e.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eFinding Objects of a Specific Type:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eObject_1_FindObjectsOfType\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Finds all objects of the specified type (\u003ccode\u003eGameObject\u003c/code\u003e in this case).\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eChecking if GameObject is Active:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eGameObject_get_activeInHierarchy\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Checks if the \u003ccode\u003eGameObject\u003c/code\u003e is active in the hierarchy.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003eGetting GameObject Name:\n    \u003cul\u003e\n      \u003cli\u003eFunction: \u003ccode\u003eObject_1_GetName\u003c/code\u003e\u003c/li\u003e\n      \u003cli\u003eDescription: Retrieves the name of the \u003ccode\u003eGameObject\u003c/code\u003e.\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eOutput: \u003c/p\u003e\n\u003cimg src=\"img/2.png\" alt=\"Gameobjects\" width=\"650\"\u003e\n\n\u003cbr\u003e\n\n\u003ch2 id=\"get_class_names_types\"\u003eGetting class names and types from a specific assembly\u003c/h2\u003e\n\n\u003cp\u003eThis code snippet demonstrates how to retrieve and print the names and namespaces of classes within a specified assembly using il2cpp API functions.\u003c/p\u003e\n\n```cpp\nvoid Il2CppHelper::GetClassesAndNamesFromAssembly(const Il2CppImage* _image)\n{\n\tif (_image) {\n\t\tsize_t classCount = il2cpp_image_get_class_count(_image);\n\n\t\tstd::cout \u003c\u003c \"{\\n\";\n\n\t\tfor (size_t i = 0; i \u003c classCount; ++i) {\n\t\t\tconst Il2CppClass* _klass = il2cpp_image_get_class(_image, i);\n\n\t\t\tif (_klass) {\n\t\t\t\tchar* _name = const_cast\u003cchar*\u003e(il2cpp_class_get_name(const_cast\u003cIl2CppClass*\u003e(_klass)));\n\t\t\t\tchar* _namespace = const_cast\u003cchar*\u003e(il2cpp_class_get_namespace(const_cast\u003cIl2CppClass*\u003e(_klass)));\n\n\t\t\t\tstd::cout \u003c\u003c \" [\\n\";\n\t\t\t\tstd::cout \u003c\u003c \"\\tName: \" \u003c\u003c _name \u003c\u003c \"\\n\";\n\t\t\t\tstd::cout \u003c\u003c \"\\tNamespace: \" \u003c\u003c _namespace \u003c\u003c \"\\n\";\n\n\t\t\t\tstd::cout \u003c\u003c \" ],\\n\";\n\t\t\t}\n\t\t}\n\n\t\tstd::cout \u003c\u003c \"\\n}\\n\";\n\t}\n}\n```\n\n\n```cpp\nconst Il2CppImage* _BoltDll = _helper-\u003eGetImage(\"bolt.dll\");\n\nif (_BoltDll) {\n    _helper-\u003eGetClassesAndNamesFromAssembly(_BoltDll);\n}\n```\n\nor\n\n```cpp\nconst Il2CppImage* _assemblyCSHARP = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n\nif (_assemblyCSHARP) {\n   _helper-\u003eGetClassesAndNamesFromAssembly(_assemblyCSHARP);\n}\n```\n\n\u003cp\u003eOutputs: \u003c/p\u003e\n\u003cimg src=\"img/3.png\" width=\"650\"\u003e\n\u003cimg src=\"img/4.png\" width=\"650\"\u003e\n\n\u003cbr\u003e\n\n\u003ch2 id=\"get_info_method\"\u003eGetting information about any method \u003c/h2\u003e\n\n* It allows you to print the name, return type, and parameter information of the target method.\n\n```cpp\nvoid Il2CppHelper::GetMethodInfo(const Il2CppImage* _image, const char* _funcName, int argLength, const char* _class_name, const char* _class_namespace)\n{\n\tIl2CppClass* _class = il2cpp_class_from_name(_image, _class_namespace, _class_name);\n\n\tif (_class == nullptr) return;\n\n\tconst MethodInfo* methodInfo = il2cpp_class_get_method_from_name(_class, _funcName, argLength);\n\n\tif (methodInfo == nullptr) return;\n\n\tIl2CppReflectionMethod* reflectionMethod = il2cpp_method_get_object(methodInfo, _class);\n\n\t// Check if the reflectionMethod is not null\n\tif (reflectionMethod == nullptr) return;\n\n\tstd::cout \u003c\u003c \"{\\n\";\n\n\t// Get the method's name from the reflectionMethod object\n\tconst char* methodName = il2cpp_method_get_name(methodInfo);\n\tstd::cout \u003c\u003c \"\\tMethod Name: \" \u003c\u003c methodName \u003c\u003c std::endl;\n\n\tconst Il2CppType* returnType = il2cpp_method_get_return_type(methodInfo);\n\tstd::cout \u003c\u003c \"\\tReturn Type: \" \u003c\u003c il2cpp_type_get_name(returnType) \u003c\u003c std::endl;\n\n\t// Get the parameter count of the method using il2cpp_method_get_param_count\n\tint parameterCount = il2cpp_method_get_param_count(methodInfo);\n\tstd::cout \u003c\u003c \"\\tParameter Count: \" \u003c\u003c parameterCount \u003c\u003c std::endl;\n\n\tstd::cout \u003c\u003c \"\\t[\\n\";\n\t// Get the parameter types of the method\n\tfor (int i = 0; i \u003c parameterCount; i++) {\n\t\t// Get the parameter type at index i using il2cpp_method_get_param\n\t\tconst Il2CppType* parameterType = il2cpp_method_get_param(methodInfo, i);\n\n\t\t// Get the type name of the parameter type using il2cpp_type_get_name\n\t\tconst char* parameterTypeName = il2cpp_type_get_name(parameterType);\n\n\t\t// Print the parameter type name to the console\n\t\tstd::cout \u003c\u003c \"\\t\\tParameter \" \u003c\u003c i \u003c\u003c \" Type: \" \u003c\u003c parameterTypeName \u003c\u003c std::endl;\n\t}\n\tstd::cout \u003c\u003c \"\\t]\\n\";\n\n\tstd::cout \u003c\u003c \"}\\n\";\n}\n```\n\n\n```cpp\nconst Il2CppImage* _AssemblyCSharp = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n\t\t\t\n_helper-\u003eGetMethodInfo(_AssemblyCSharp, \"SetFOV\", 1, \"NolanBehaviour\", \"\");\n```\n\n\u003cp\u003eOutput: \u003c/p\u003e\n\u003cimg src=\"img/5.png\" width=\"650\"\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ch2 id=\"call_function\"\u003eCalling a function with \"il2cpp_runtime_invoke\"\u003c/h2\u003e \n\n```cpp\nif (GetAsyncKeyState(VK_F1) \u0026 0x8000) {\n    const Il2CppImage* assemblyCSharp = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n    if (!assemblyCSharp) {\n        std::cout \u003c\u003c \"Failed to get Assembly-CSharp.dll image.\\n\";\n        return;\n    }\n\n    _helper-\u003eGetMethodInfo(assemblyCSharp, \"SetRank\", 1, \"NolanRankController\", \"\");\n}\n\nif (GetAsyncKeyState(VK_F2) \u0026 0x8000) {\n    const Il2CppImage* csharpImage = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n    if (!csharpImage) {\n        std::cout \u003c\u003c \"Failed to get Assembly-CSharp.dll image.\\n\";\n        return;\n    }\n\n    // Get the NolanRankController type\n    Il2CppObject* nolanObj = _helper-\u003eGetTypeFromClass(csharpImage, \"\", \"NolanRankController\");\n    if (!nolanObj) {\n        std::cout \u003c\u003c \"Failed to get NolanRankController type.\\n\";\n        return;\n    }\n\n    Type* TNolan = reinterpret_cast\u003cType*\u003e(nolanObj);\n    auto isTypeValid = Object_1_FindObjectOfType(TNolan, nullptr);\n    if (!isTypeValid) {\n        std::cout \u003c\u003c \"NolanRankController instance not found.\\n\";\n        return;\n    }\n\n    // Cast to NolanBehaviour\n    NolanBehaviour* nolanBehaviour = reinterpret_cast\u003cNolanBehaviour*\u003e(isTypeValid);\n    if (!nolanBehaviour) {\n        std::cout \u003c\u003c \"Failed to cast to NolanBehaviour.\\n\";\n        return;\n    }\n\n    // Get class information\n    Il2CppClass* nolanClass = il2cpp_class_from_name(csharpImage, \"\", \"NolanRankController\");\n    if (!nolanClass) {\n        std::cout \u003c\u003c \"Failed to retrieve NolanRankController class.\\n\";\n        return;\n    }\n\n    // Get method information\n    const MethodInfo* methodInfo = il2cpp_class_get_method_from_name(nolanClass, \"SetRank\", 1);\n    if (!methodInfo) {\n        std::cout \u003c\u003c \"Failed to get SetRank method.\\n\";\n        return;\n    }\n\n    int newRankValue = 666;\n    void* params[] = { \u0026newRankValue };\n\n    std::cout \u003c\u003c \"Calling SetRank function...\\n\";\n    il2cpp_runtime_invoke(methodInfo, nolanBehaviour, params, nullptr);\n}\n```\n\n\u003cp\u003eOutput: \u003c/p\u003e\n\u003cimg src=\"img/6.png\" width=\"650\"\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ch2 id=\"list_all_functions\"\u003eGetting a List of All Functions in the Target Class\u003c/h2\u003e\n\n* This function, serves the purpose of obtaining and displaying a list of all methods within a given class (specified by the klass parameter). It iterates through each method in the class using a loop, retrieving information such as the method name and its return type. Subsequently, it prints out the method name along with its return type, providing a clear representation of the methods contained within the class\n\n```cpp\nvoid Il2CppHelper::PrintMethods(Il2CppClass* klass) {\n\tconst MethodInfo* methodIter = nullptr;\n\tvoid* iter = nullptr;\n\n\t// Retrieve all methods of the class\n\twhile ((methodIter = il2cpp_class_get_methods(klass, \u0026iter)) != nullptr) {\n\t\t// Get the name of the method\n\t\tconst char* methodName = il2cpp_method_get_name(methodIter);\n\n\t\t// Get the return type of the method\n\t\tconst Il2CppType* methodReturnType = il2cpp_method_get_return_type(methodIter);\n\t\tchar* returnTypeName = il2cpp_type_get_name(methodReturnType);\n\n\t\t// Print the method name and its return type\n\t\tstd::cout \u003c\u003c \"Method Name: \" \u003c\u003c methodName;\n\t\tstd::cout \u003c\u003c \" (\" \u003c\u003c returnTypeName \u003c\u003c \")\\n------------------------------------\\n\";\n\n\t\t// Perform necessary memory operations\n\t\til2cpp_free(returnTypeName);\n\t}\n}\n```\n\n## Example:\n\n```cpp\nconst Il2CppImage* _image = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n\nif (_image) {\n\tIl2CppClass* nolanRankControllerClass = il2cpp_class_from_name(_timage, \"\", \"NolanRankController\");\n\n\tif (nolanRankControllerClass != nullptr) {\n\t\t_helper-\u003ePrintMethods(nolanRankControllerClass);\n\t}\n}\n```\n\n\u003cp\u003eOutput: \u003c/p\u003e\n\u003cimg src=\"img/8.png\" width=\"650\"\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ch2 id=\"get_field_info\"\u003eGetting Information about Class Fields (FieldInfo)\u003c/h2\u003e\n\n* It allows us to get information about the fields of a class\n\n```cpp\nvoid Il2CppHelper::GetFieldsInformation(Il2CppClass* klass)\n{\n\tvoid* iter = nullptr;\n\tFieldInfo* field = nullptr;\n\n\t// Iterate through the fields of the class\n\twhile ((field = il2cpp_class_get_fields(klass, \u0026iter)) != nullptr)\n\t{\n\t\t// Get the name of the field\n\t\tconst char* fieldName = il2cpp_field_get_name(field);\n\n\t\t// Get the type of the field\n\t\tconst Il2CppType* fieldType = il2cpp_field_get_type(field);\n\t\tchar* fieldTypeStr = il2cpp_type_get_name(fieldType);\n\n\t\t// Print the information about the field\n\t\tstd::cout \u003c\u003c \"Field Name: \" \u003c\u003c fieldName \u003c\u003c std::endl;\n\t\tstd::cout \u003c\u003c \"Type: \" \u003c\u003c fieldTypeStr \u003c\u003c std::endl;\n\t\tstd::cout \u003c\u003c \"-----------\\n\";\n\t}\n}\n```\n\n\n```cpp\nconst Il2CppImage* _assemblyCSHARP = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n\t\t\t\nif (_assemblyCSHARP) {\n\tIl2CppClass* _nolanBehaviourClass = il2cpp_class_from_name(_assemblyCSHARP, \"\", \"NolanBehaviour\");\n\n\t_helper-\u003eGetFieldsInformation(_nolanBehaviourClass);\n}\n```\n\n\u003cp\u003eOutput: \u003c/p\u003e\n\u003cimg src=\"img/7.png\" width=\"650\"\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ch2 id=\"modify_field\"\u003eModifiying the Value of a Field\u003c/h2\u003e\n\n```cpp\nif (GetAsyncKeyState(VK_F1) \u0026 0x8000) {\n    // Get the Il2CppImage for \"Assembly-CSharp.dll\"\n    const Il2CppImage* assemblyCSharp = _helper-\u003eGetImage(\"Assembly-CSharp.dll\");\n    if (!assemblyCSharp) {\n        std::cout \u003c\u003c \"Failed to get Assembly-CSharp.dll image.\\n\";\n        return;\n    }\n\n    // Get the object for the \"Menu\" class within the \"Horror\" namespace\n    Il2CppObject* horrorMenuClassObject = _helper-\u003eGetTypeFromClass(assemblyCSharp, \"Horror\", \"Menu\");\n    if (!horrorMenuClassObject) {\n        std::cout \u003c\u003c \"Failed to get Horror::Menu class.\\n\";\n        return;\n    }\n\n    // Find the object instance of the \"Menu\" class\n    auto menuType = app::Object_1_FindObjectOfType_1(reinterpret_cast\u003cType*\u003e(horrorMenuClassObject), true, nullptr);\n    if (!menuType) {\n        std::cout \u003c\u003c \"Failed to find an instance of Horror::Menu.\\n\";\n        return;\n    }\n\n    // Get the Il2CppClass for the \"Menu\" class\n    Il2CppClass* menuClass = il2cpp_class_from_name(assemblyCSharp, \"Horror\", \"Menu\");\n    if (!menuClass) {\n        std::cout \u003c\u003c \"Failed to get Il2CppClass for Horror::Menu.\\n\";\n        return;\n    }\n\n    // Get the FieldInfo for the \"steamName\" field\n    FieldInfo* steamNameField = il2cpp_class_get_field_from_name(menuClass, \"steamName\");\n    if (!steamNameField) {\n        std::cout \u003c\u003c \"Field 'steamName' does not exist in Horror::Menu.\\n\";\n        return;\n    }\n\n    std::cout \u003c\u003c \"Field 'steamName' exists!\\n\";\n\n    // Define a new value for the field\n    const char* newSteamNameValue = \"il2cpp-field\";\n\n    // Create a new Il2CppString from the new value\n    Il2CppString* newSteamNameString = il2cpp_string_new(newSteamNameValue);\n    if (!newSteamNameString) {\n        std::cout \u003c\u003c \"Failed to create Il2CppString for new steam name.\\n\";\n        return;\n    }\n\n    // Set the field's value to the new value\n    il2cpp_field_set_value(menuType, steamNameField, newSteamNameString);\n\n    std::cout \u003c\u003c \"Successfully updated 'steamName' field!\\n\";\n}\n```\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ch2 id=\"write_FindObjectOfType_function\"\u003eCreating a Helper Function to Find Objects of a Specific Type (\"FindObjectOfType\")\u003c/h2\u003e\n\n**FindObjectOfType** function is used to search for an object of a specific class (type). Our goal is to write our own function that will simplify this process in the IL2CPP environment. This way, we can obtain a more flexible and customized solution for direct access to Unity's objects.\n\n**Basic Logic of the Function:**\n\n- **Load the Assembly:** We open the specified assembly file to access its classes.\n- **Find the Class:** We locate the class in the assembly using the className parameter.\n- **Get the Type of the Class:** We access the type (Type) of the class we found.\n- **Search for the Unity Object:** We perform an object search using Unity's internal functions (e.g., app::Object_1_FindObjectOfType) -\u003e defined in the *il2cpp-functions.h* header file.\n- **Result**: Once the object is found, we return it by casting to the appropriate type (T).\"\n\n\u003cbr\u003e\n\n**Here is the function we will write according to the logic explained above:**\n\n```cpp\ntemplate\u003ctypename T\u003e\nT* FindObjectOfType(const char* className, const char* classNamespace = \"\", const char* assemblyName = \"Assembly-CSharp.dll\") {\n    // Getting the IL2CPP domain - the domain represents the runtime environment where all objects are loaded\n    Il2CppDomain* domain = il2cpp_domain_get();\n    if (!domain) {\n        std::cout \u003c\u003c \"Error: Failed to get IL2CPP domain!\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Loading the assembly - loading the specific assembly (like Assembly-CSharp.dll) in which the class is defined\n    const Il2CppAssembly* assembly = il2cpp_domain_assembly_open(domain, assemblyName);\n    if (!assembly) {\n        std::cout \u003c\u003c \"Error: Failed to load assembly (\" \u003c\u003c assemblyName \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Loading the class by name - locating the class inside the assembly using classNamespace and className\n    Il2CppClass* klass = il2cpp_class_from_name(assembly-\u003eimage, classNamespace, className);\n    if (!klass) {\n        std::cout \u003c\u003c \"Error: Class not found (\" \u003c\u003c classNamespace \u003c\u003c \"::\" \u003c\u003c className \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Getting the class type - retrieving the type information of the class (Il2CppType)\n    const Il2CppType* type = il2cpp_class_get_type(klass);\n    if (!type) {\n        std::cout \u003c\u003c \"Error: Failed to get class type (\" \u003c\u003c className \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Getting the type object - using the class type to get the corresponding type object in Unity\n    Il2CppObject* typeObject = il2cpp_type_get_object(type);\n    if (!typeObject) {\n        std::cout \u003c\u003c \"Error: Failed to get type object!\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Calling Unity's FindObjectOfType method - this function finds the first object of the given type in the scene\n    app::Object_1* foundObject = app::Object_1_FindObjectOfType(reinterpret_cast\u003capp::Type*\u003e(typeObject), nullptr);\n    if (!foundObject) {\n        std::cout \u003c\u003c \"Warning: Object not found (\" \u003c\u003c className \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Returning the found object cast to the specified type\n    return reinterpret_cast\u003cT*\u003e(foundObject);\n}\n```\n\n\u003cbr\u003e\n\nNow, let me show an example from the macro below using our FindObjectOfType function. The following function simulates the click of the 'Start' button in the lobby menu.\n```cpp\nDO_APP_FUNC(0x006AC8A0, void, Menu_OnLobbyStartButtonClick, (Menu * __this, MethodInfo * method));\n```\n\n\u003cbr\u003e\n\n```cpp\n#include \"pch-il2cpp.h\"\n\n#define WIN32_LEAN_AND_MEAN\n#include \u003cWindows.h\u003e\n#include \u003ciostream\u003e\n#include \"il2cpp-appdata.h\"\n#include \"helpers.h\"\n\n#include \u003cchrono\u003e\n#include \u003cthread\u003e\n\nextern const LPCWSTR LOG_FILE = L\"il2cpp-log.txt\";\n\n// Template function to find an object of a specified class type in the Unity scene\n// This function is used to search for the first instance of a class in the scene by class name\ntemplate\u003ctypename T\u003e\nT* FindObjectOfType(const char* className, const char* classNamespace = \"\", const char* assemblyName = \"Assembly-CSharp.dll\") {\n    // Getting the IL2CPP domain - the domain represents the runtime environment where all objects are loaded\n    Il2CppDomain* domain = il2cpp_domain_get();\n    if (!domain) {\n        std::cout \u003c\u003c \"Error: Failed to get IL2CPP domain!\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Loading the assembly - loading the specific assembly (like Assembly-CSharp.dll) in which the class is defined\n    const Il2CppAssembly* assembly = il2cpp_domain_assembly_open(domain, assemblyName);\n    if (!assembly) {\n        std::cout \u003c\u003c \"Error: Failed to load assembly (\" \u003c\u003c assemblyName \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Loading the class by name - locating the class inside the assembly using classNamespace and className\n    Il2CppClass* klass = il2cpp_class_from_name(assembly-\u003eimage, classNamespace, className);\n    if (!klass) {\n        std::cerr \u003c\u003c \"Error: Class not found (\" \u003c\u003c classNamespace \u003c\u003c \"::\" \u003c\u003c className \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Getting the class type - retrieving the type information of the class (Il2CppType)\n    const Il2CppType* type = il2cpp_class_get_type(klass);\n    if (!type) {\n        std::cerr \u003c\u003c \"Error: Failed to get class type (\" \u003c\u003c className \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Getting the type object - using the class type to get the corresponding type object in Unity\n    Il2CppObject* typeObject = il2cpp_type_get_object(type);\n    if (!typeObject) {\n        std::cout \u003c\u003c \"Error: Failed to get type object!\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Calling Unity's FindObjectOfType method - this function finds the first object of the given type in the scene\n    app::Object_1* foundObject = app::Object_1_FindObjectOfType(reinterpret_cast\u003capp::Type*\u003e(typeObject), nullptr);\n    if (!foundObject) {\n        std::cerr \u003c\u003c \"Warning: Object not found (\" \u003c\u003c className \u003c\u003c \")\" \u003c\u003c std::endl;\n        return nullptr;\n    }\n\n    // Returning the found object cast to the specified type\n    return reinterpret_cast\u003cT*\u003e(foundObject);\n}\n\nvoid Run()\n{\n\t// Initialize thread data - DO NOT REMOVE\n\tIl2CppDomain* domain = il2cpp_domain_get();\n\til2cpp_thread_attach(domain);\n\n\n\til2cppi_new_console();\n\n    while (true) {\n        // Check if the F1 key is pressed - GetAsyncKeyState returns the state of a specific key\n        if (GetAsyncKeyState(VK_F1) \u0026 0x8000) {\n\n            // Try to find the \"Menu\" object in the \"Horror\" namespace\n            app::Menu* _menu = FindObjectOfType\u003capp::Menu\u003e(\"Menu\", \"Horror\");\n\n            // If the menu is found, attempt to invoke the 'OnLobbyStartButtonClick' function\n            if (_menu) {\n                // Ensure that the function pointer is valid before calling it\n                if (app::Menu_OnLobbyStartButtonClick != nullptr) {\n                    app::Menu_OnLobbyStartButtonClick(_menu, nullptr); // Simulates the click of the \"Start\" button in the lobby menu\n                }\n            }\n\n        }\n\n        std::this_thread::sleep_for(std::chrono::seconds(1));\n    }\n}\n```\n\n\u003cbr\u003e\u003cbr\u003e\n\n\u003ch2 id=\"readingProperty\"\u003eReading and Managing Static and Instance Properties\u003c/h2\u003e\n\nA guide to accessing and managing static and instance properties. Explains how to create a custom PropertyAccessor class\n\n```cpp\n// The `PropertyAccessor` class provides an interface to interact with Il2Cpp objects,\n// enabling access to classes, static properties, and instance properties in a given assembly.\nclass PropertyAccessor {\nprivate:\n    /**\n     * @brief Finds an Il2Cpp class by its namespace and class name within the current image.\n     *\n     * This method is used to locate and retrieve a class definition from the Il2Cpp image.\n     * It performs checks to ensure the image, assembly, and class exist.\n     *\n     * @param namespaceName The namespace where the target class resides.\n     * @param className The name of the class to find.\n     * @return A pointer to the `Il2CppClass` if found; otherwise, nullptr.\n     */\n    Il2CppClass* FindClass(const std::string\u0026 namespaceName, const std::string\u0026 className) {\n        if (!currentImage) {\n            std::cout \u003c\u003c \"[Error] Current image is null.\" \u003c\u003c std::endl;\n            return nullptr;\n        }\n\n        const Il2CppAssembly* assembly = currentImage-\u003eassembly;\n        if (!assembly) {\n            std::cout \u003c\u003c \"[Error] Assembly is null.\" \u003c\u003c std::endl;\n            return nullptr;\n        }\n\n        const Il2CppImage* image = il2cpp_assembly_get_image(assembly);\n        if (!image) {\n            std::cout \u003c\u003c \"[Error] Image is null.\" \u003c\u003c std::endl;\n            return nullptr;\n        }\n\n        Il2CppClass* klass = il2cpp_class_from_name(image, namespaceName.c_str(), className.c_str());\n        if (!klass) {\n            std::cout \u003c\u003c \"[Error] Class not found: \" \u003c\u003c namespaceName \u003c\u003c \".\" \u003c\u003c className \u003c\u003c std::endl;\n            return nullptr;\n        }\n\n        return klass;\n    }\n\npublic:\n    /**\n     * @brief Constructs the `PropertyAccessor` object, initializing the image for the specified assembly.\n     *\n     * This constructor initializes the current Il2Cpp image by opening the specified assembly\n     * in the current domain. The image is required for accessing classes and properties.\n     *\n     * @param assemblyName The name of the assembly to load (e.g., \"UnityEngine.CoreModule.dll\").\n     */\n    PropertyAccessor(const char* assemblyName) {\n        // Retrieve the Il2Cpp domain\n        Il2CppDomain* domain = il2cpp_domain_get();\n        if (!domain) {\n            std::cout \u003c\u003c \"[ERROR] Il2Cpp domain not available.\";\n        }\n\n        // Open the specified assembly and retrieve its image\n        if (assemblyName \u0026\u0026 *assemblyName) {\n            currentImage = il2cpp_domain_assembly_open(domain, assemblyName)-\u003eimage;\n            if (!currentImage) {\n                std::cout \u003c\u003c \"[ERROR] Assembly not found: \" + std::string(assemblyName);\n            }\n        }\n    }\n\n    /**\n     * @brief Retrieves the value of a static property from a given class.\n     *\n     * This method finds the class by its namespace and name, locates the getter method\n     * for the specified property, and invokes the method to retrieve the property value.\n     *\n     * @tparam T The expected type of the property value.\n     * @param classNamespace The namespace of the target class.\n     * @param className The name of the class containing the static property.\n     * @param propertyName The name of the property to retrieve.\n     * @return The value of the property as type `T`.\n     */\n    template \u003ctypename T\u003e\n    T getStaticProperty(const std::string\u0026 classNamespace, const std::string\u0026 className, const std::string\u0026 propertyName) {\n        Il2CppClass* klass = FindClass(classNamespace, className);\n        if (!klass) {\n            std::cout \u003c\u003c \"[Error] Class not found: \" + classNamespace + \".\" + className;\n        }\n\n        std::string getterName = \"get_\" + propertyName;\n        const MethodInfo* getterMethod = il2cpp_class_get_method_from_name(klass, getterName.c_str(), 0);\n        if (!getterMethod) {\n            std::cout \u003c\u003c \"[Error] Getter method not found: \" + propertyName;\n        }\n\n        // Invoke the getter method to retrieve the property value\n        Il2CppObject* result = il2cpp_runtime_invoke(getterMethod, nullptr, nullptr, nullptr);\n        return convertResult\u003cT\u003e(result);\n    }\n\n    /**\n     * @brief Retrieves the value of an instance property from a given object.\n     *\n     * This method checks the validity of the provided instance, locates the getter\n     * method for the specified property, and invokes it to retrieve the property value.\n     *\n     * @tparam T The expected type of the property value.\n     * @param instance A pointer to the Il2CppObject instance.\n     * @param propertyName The name of the property to retrieve.\n     * @return The value of the property as type `T`.\n     */\n    template \u003ctypename T\u003e\n    T getInstanceProperty(Il2CppObject* instance, const std::string\u0026 propertyName) {\n        if (!instance) {\n            std::cout \u003c\u003c \"[Error] Instance is null.\";\n        }\n\n        Il2CppClass* klass = il2cpp_object_get_class(instance);\n        if (!klass) {\n            std::cout \u003c\u003c \"[Error] Class not found.\";\n        }\n\n        std::string getterName = \"get_\" + propertyName;\n        const MethodInfo* getterMethod = il2cpp_class_get_method_from_name(klass, getterName.c_str(), 0);\n        if (!getterMethod) {\n            std::cout \u003c\u003c \"[Error] Getter method not found: \" + propertyName;\n        }\n\n        // Invoke the getter method to retrieve the property value\n        Il2CppObject* result = il2cpp_runtime_invoke(getterMethod, instance, nullptr, nullptr);\n        return convertResult\u003cT\u003e(result);\n    }\n\n    /**\n     * @brief Converts the Il2CppObject result to the desired type `T`.\n     *\n     * This method supports basic data types (e.g., strings, numerics, enums) and\n     * directly returns pointers for complex object types.\n     *\n     * @tparam T The expected type of the result.\n     * @param result The `Il2CppObject` to be converted.\n     * @return The converted result as type `T`.\n     */\n    template \u003ctypename T\u003e\n    T convertResult(Il2CppObject* result) {\n        if (!result) {\n            std::cout \u003c\u003c \"[Error] Null result.\";\n        }\n\n        if constexpr (std::is_same_v\u003cT, std::string\u003e) {\n            // Convert Il2CppString to std::string\n            Il2CppString* il2cppString = reinterpret_cast\u003cIl2CppString*\u003e(result);\n            return il2cppi_to_string(il2cppString);\n        }\n        else if constexpr (std::is_arithmetic_v\u003cT\u003e || std::is_enum_v\u003cT\u003e) {\n            // Unbox primitive types or enums\n            return *(T*)il2cpp_object_unbox(result);\n        }\n        else {\n            // Return the result as a raw pointer for other types\n            return reinterpret_cast\u003cT\u003e(result);\n        }\n    }\n\nprivate:\n    const Il2CppImage* currentImage; // The Il2CppImage associated with the target assembly.\n};\n```\n\nNow that we have written our PropertyAccessor class, let's create some examples and test it. We will use the PropertyAccessor class to read static properties like Application.version and Application.dataPath, and to retrieve the main camera instance\n\n```cpp\nvoid Run()\n{\n\t// Initialize thread data - DO NOT REMOVE\n\til2cpp_thread_attach(il2cpp_domain_get());\n\n\n\til2cppi_new_console();\n\n\tPropertyAccessor appProperty(\"UnityEngine.CoreModule.dll\");\n\n\t//UnityEngine.Application.version\n\tstd::cout \u003c\u003c appProperty.getStaticProperty\u003cstd::string\u003e(\"UnityEngine\", \"Application\", \"version\") \u003c\u003c \"\\n\";\n\n\t//UnityEngine.Application.dataPath\n\tstd::cout \u003c\u003c appProperty.getStaticProperty\u003cstd::string\u003e(\"UnityEngine\", \"Application\", \"dataPath\") \u003c\u003c \"\\n\";\n\n\t//UnityEngine.Application.productName\n\tstd::cout \u003c\u003c appProperty.getStaticProperty\u003cstd::string\u003e(\"UnityEngine\", \"Application\", \"productName\") \u003c\u003c \"\\n\";\n\n\t//UnityEngine.Application.unityVersion\n\tstd::cout \u003c\u003c appProperty.getStaticProperty\u003cstd::string\u003e(\"UnityEngine\", \"Application\", \"unityVersion\") \u003c\u003c \"\\n\";\n\n\tPropertyAccessor cameraProperty(\"UnityEngine.CoreModule.dll\");\n\n\t//UnityEngine.Camera.main\n\tapp::Camera* mainCamera = cameraProperty.getStaticProperty\u003capp::Camera*\u003e(\"UnityEngine\", \"Camera\", \"main\");\n\t\n\tif (mainCamera) {\n\t\tstd::cout \u003c\u003c \"main camera retrieved!!\\n\";\n\t}\n\telse {\n\t\tstd::cout \u003c\u003c \"main camera is nullptr.\\n\";\n\t}\n}\n```\n\nOutput:\u003cbr\u003e\n\n\u003cimg src=\"img/9.png\" width=\"650\"\u003e\n\nNow, let's move on to further enhancing our class. I will create a UGameObject class that will inherit from PropertyAccessor. This class will serve as a dedicated helper for operations related to GameObject. It will encapsulate all the functionality required for interacting with GameObject instances, such as retrieving objects by tag, accessing their properties, and performing related tasks in a structured manner.\n\n```cpp\nclass UGameObject : public PropertyAccessor {\npublic:\n    UGameObject() : PropertyAccessor(\"UnityEngine.CoreModule.dll\") {}\n\n    // Finds a GameObject by tag\n    app::GameObject* FindWithTag(const char* tag) {\n        // Find GameObject class\n        Il2CppClass* klass = FindClass(\"UnityEngine\", \"GameObject\");\n        if (!klass) {\n            std::cout \u003c\u003c \"[Error] GameObject class not found.\\n\";\n            return nullptr;\n        }\n\n        // Find the FindWithTag method\n        const MethodInfo* method = il2cpp_class_get_method_from_name(klass, \"FindWithTag\", 1);\n        if (!method) {\n            std::cout \u003c\u003c \"[Error] GameObject.FindWithTag method not found.\\n\";\n            return nullptr;\n        }\n\n        // Create Il2CppString for the tag\n        Il2CppString* il2cppTag = il2cpp_string_new(tag);\n\n        // Invoke the method\n        Il2CppException* exception = nullptr;\n        Il2CppObject* result = il2cpp_runtime_invoke(method, nullptr, reinterpret_cast\u003cvoid**\u003e(\u0026il2cppTag), \u0026exception);\n\n        if (exception) {\n            char exceptionMessage[1024];\n            il2cpp_format_exception(exception, exceptionMessage, sizeof(exceptionMessage));\n            std::cout \u003c\u003c \"[Error] Exception occurred during FindWithTag call: \" \u003c\u003c exceptionMessage \u003c\u003c \"\\n\";\n            return nullptr;\n        }\n\n        if (result) {\n            return reinterpret_cast\u003capp::GameObject*\u003e(result);\n        }\n\n        return nullptr;\n    }\n\n    // Retrieves the activeInHierarchy property\n    bool GetActiveInHierarchy(app::GameObject* gameObject) {\n        return getInstanceProperty\u003cbool\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(gameObject), \"activeInHierarchy\");\n    }\n\n    // Retrieves the activeSelf property\n    bool GetActiveSelf(app::GameObject* gameObject) {\n        return getInstanceProperty\u003cbool\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(gameObject), \"activeSelf\");\n    }\n\n    // Retrieves the layer property\n    int GetLayer(app::GameObject* gameObject) {\n        return getInstanceProperty\u003cint\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(gameObject), \"layer\");\n    }\n\n    // Retrieves the tag property\n    std::string GetTag(app::GameObject* gameObject) {\n        return getInstanceProperty\u003cstd::string\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(gameObject), \"tag\");\n    }\n\n    // Retrieves the transform property\n    app::Transform* GetTransform(app::GameObject* gameObject) {\n        return getInstanceProperty\u003capp::Transform*\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(gameObject), \"transform\");\n    }\n};\n```\n\nNow, let's move on to creating an example\n\n```cpp\nvoid Run()\n{\n\t// Initialize thread data - DO NOT REMOVE\n\til2cpp_thread_attach(il2cpp_domain_get());\n\n\n\til2cppi_new_console();\n\n    // Create an instance of UGameObject\n    UGameObject gameObjectHelper;\n\n    while (true) {\n        // Check if the F1 key is pressed - GetAsyncKeyState returns the state of a specific key\n        if (GetAsyncKeyState(VK_F1) \u0026 0x8000) {\n            // Example usage: Find a GameObject by tag\n            app::GameObject* myObject = gameObjectHelper.FindWithTag(\"Player\");\n            if (myObject) {\n                std::cout \u003c\u003c \"GameObject found with tag 'Player'.\\n\";\n                std::cout \u003c\u003c \"Active in Hierarchy: \" \u003c\u003c gameObjectHelper.GetActiveInHierarchy(myObject) \u003c\u003c \"\\n\";\n                std::cout \u003c\u003c \"Active Self: \" \u003c\u003c gameObjectHelper.GetActiveSelf(myObject) \u003c\u003c \"\\n\";\n                std::cout \u003c\u003c \"Layer: \" \u003c\u003c gameObjectHelper.GetLayer(myObject) \u003c\u003c \"\\n\";\n                std::cout \u003c\u003c \"Tag: \" \u003c\u003c gameObjectHelper.GetTag(myObject) \u003c\u003c \"\\n\";\n\n                app::Transform* transform = gameObjectHelper.GetTransform(myObject);\n                if (transform) {\n                    std::cout \u003c\u003c \"Transform component retrieved.\\n\";\n                }\n                else {\n                    std::cout \u003c\u003c \"[Error] Transform component not found.\\n\";\n                }\n            }\n            else {\n                std::cout \u003c\u003c \"[Error] GameObject with tag 'Player' not found. -\u003e you're probably on the menu, so it's normal\\n\";\n            }\n        }\n\n        Sleep(1000);\n    }\n}\n```\nOutput:\n\n\u003cimg src=\"img/10.png\" width=\"650\"\u003e\n\nFinally, just like with the GameObject logic, let's create a UTransform class and demonstrate it with an example\n\n```cpp\nclass UTransform : public PropertyAccessor {\npublic:\n    UTransform(app::Transform* transform) : PropertyAccessor(\"UnityEngine.CoreModule.dll\")\n    {\n        this-\u003etransform = transform;\n    }\nprivate:\n    app::Transform* transform;\npublic:\n    app::Vector3 GetPosition() {\n        auto obj = getInstanceProperty\u003cIl2CppObject*\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(transform), \"position\");\n        return *(reinterpret_cast\u003capp::Vector3*\u003e(il2cpp_object_unbox(obj)));\n    }\n    app::Vector3 GetRotation() {\n        auto obj = getInstanceProperty\u003cIl2CppObject*\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(transform), \"rotation\");\n        return *(reinterpret_cast\u003capp::Vector3*\u003e(il2cpp_object_unbox(obj)));\n    }\n    app::Vector3 GetScale() {\n        auto obj = getInstanceProperty\u003cIl2CppObject*\u003e(reinterpret_cast\u003cIl2CppObject*\u003e(transform), \"localScale\");\n        return *(reinterpret_cast\u003capp::Vector3*\u003e(il2cpp_object_unbox(obj)));\n    }\n};\n```\n\n```cpp\nvoid Run()\n{\n\t// Initialize thread data - DO NOT REMOVE\n\til2cpp_thread_attach(il2cpp_domain_get());\n\n\n\til2cppi_new_console();\n\n    // Create an instance of UGameObject\n    UGameObject gameObjectHelper;\n\n    while (true) {\n        // Check if the F1 key is pressed - GetAsyncKeyState returns the state of a specific key\n        if (GetAsyncKeyState(VK_F1) \u0026 0x8000) {\n            // Example usage: Find a GameObject by tag\n            app::GameObject* myObject = gameObjectHelper.FindWithTag(\"Player\");\n            if (myObject) {\n                std::cout \u003c\u003c \"GameObject found with tag 'Player'.\\n\";\n\n                app::Transform* playerTransform = gameObjectHelper.GetTransform(myObject);\n                if (playerTransform) {\n                    std::cout \u003c\u003c \"Transform component retrieved.\\n\";\n\n                    UTransform transformHelper(playerTransform);\n\n                    std::cout \u003c\u003c \"Position: [x,y,z]\" \u003c\u003c transformHelper.GetPosition().x \u003c\u003c \",\" \u003c\u003c transformHelper.GetPosition().y \u003c\u003c \",\" \u003c\u003c transformHelper.GetPosition().z \u003c\u003c \"\\n\";\n                    std::cout \u003c\u003c \"Rotation: [x,y,z]\" \u003c\u003c transformHelper.GetRotation().x \u003c\u003c \",\" \u003c\u003c transformHelper.GetRotation().y \u003c\u003c \",\" \u003c\u003c transformHelper.GetRotation().z \u003c\u003c \"\\n\";\n                    std::cout \u003c\u003c \"Scale: [x,y,z]\" \u003c\u003c transformHelper.GetScale().x \u003c\u003c \",\" \u003c\u003c transformHelper.GetScale().y \u003c\u003c \",\" \u003c\u003c transformHelper.GetScale().z \u003c\u003c \"\\n\";\n                }\n                else {\n                    std::cout \u003c\u003c \"[Error] Transform component not found.\\n\";\n                }\n            }\n            else {\n                std::cout \u003c\u003c \"[Error] GameObject with tag 'Player' not found. -\u003e you're probably on the menu, so it's normal\\n\";\n            }\n        }\n\n        Sleep(1000);\n    }\n}\n```\n\nOutput:\n\n\u003cimg src=\"img/11.png\" width=\"650\"\u003e\n\nI will continue to contribute as much as I can. For now, bye!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjadis0x%2Fil2cpp-reverse-engineering-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjadis0x%2Fil2cpp-reverse-engineering-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjadis0x%2Fil2cpp-reverse-engineering-guide/lists"}