Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


[Mono] Retrieving class instances in C

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
Frouk
Grandmaster Cheater
Reputation: 6

Joined: 22 Jun 2021
Posts: 528

PostPosted: Sat Aug 15, 2026 1:52 am    Post subject: [Mono] Retrieving class instances in C Reply with quote

Code:

...
{$luacode refList=RSI}
local klass = mono_findClass("...")
if (klass) then
    refList = #mono_class_findInstancesOfClassListOnly(nil, klass)
end
{$asm}
...
{$luacode list=RAX}
local klass = mono_findClass("...")
if (klass) then
    local tbl = mono_class_findInstancesOfClassListOnly(nil, klass)
    if (tbl and #tbl > 0) then
        for i, v in pairs(tbl) do
            writePointer(list + 0x4 + 0x8 * (i - 1), v)
        end
    end
end
{$asm}
...


Is there's an easier way to retrieve instances using C code or assembly rather than making a call through lua code? Or it would require writing a header or exports of mono to do that?(it seems to be a "yes" answer)
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 475

Joined: 09 May 2003
Posts: 25989
Location: The netherlands

PostPosted: Sat Aug 15, 2026 2:52 pm    Post subject: Reply with quote

it requires a memoryscan

Unity does have a helper funnction that keeps track of some class instances, but not all

_________________
Tools give you results. Knowledge gives you control.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
Frouk
Grandmaster Cheater
Reputation: 6

Joined: 22 Jun 2021
Posts: 528

PostPosted: Sat Aug 15, 2026 3:07 pm    Post subject: Reply with quote

so, either basic vtable or "klass" memory scan or using the Unity's helper function
though, I should test the Unity's helper function first and report back
Back to top
View user's profile Send private message
Frouk
Grandmaster Cheater
Reputation: 6

Joined: 22 Jun 2021
Posts: 528

PostPosted: Mon Aug 17, 2026 9:37 am    Post subject: Reply with quote

Okay, using Unity's helper function worked
Code:

void *domain = mono_domain_get();

if (!domain)
{
    return;
}

void *coreMod = mono_domain_assembly_open(domain, "UnityEngine.CoreModule");
if (!coreMod)
    coreMod = mono_domain_assembly_open(domain, "UnityEngine");

if (!coreMod)
{
    return;
}

void *modImage = mono_assembly_get_image(coreMod);
void *unityObjClass = mono_class_from_name(modImage, "UnityEngine", "Object");

if (!unityObjClass)
{
    return;
}

void *iter = 0;
void *method = 0;
void *found = 0;
while ((method = mono_class_get_methods(unityObjClass, &iter)) != 0)
{
    const char *methodName = mono_method_get_name(method);
    if (_stricmp(methodName, "FindObjectsOfType") == 0)
    {
        void *sig = mono_method_signature(method);
        if (!sig)
            continue;

        int paramCnt = mono_signature_get_param_count(sig);
        if (paramCnt == 1)
        {
            void *iter = 0;
            void *params = mono_signature_get_params(sig, &iter);
            if (params)
            {
                void *paramKlass = mono_type_get_class(params);
                if (paramKlass)
                {
                    const char* paramName = mono_class_get_name(paramKlass);
                    if (strstr(paramName, "Type"))
                    {
                        void *type = mono_signature_get_return_type(sig);
                        if (!type)
                            continue;

                        if (mono_type_get_type(type) == 0x1D)
                        {
                            found = method;
                            break;
                        }
                    }
                }
            }
        }
    }
}

if (!found)
{
    return;
}


Took some time before I eventually got it working
Back to top
View user's profile Send private message
Csimbi
I post too much
Reputation: 98

Joined: 14 Jul 2007
Posts: 3423

PostPosted: Mon Aug 17, 2026 2:27 pm    Post subject: Reply with quote

Well done!
Any chance you could provide and example with the intended use?
Thanks!
Back to top
View user's profile Send private message
Frouk
Grandmaster Cheater
Reputation: 6

Joined: 22 Jun 2021
Posts: 528

PostPosted: Tue Aug 18, 2026 3:57 am    Post subject: This post has 1 review(s) Reply with quote

Csimbi wrote:
Well done!
Any chance you could provide and example with the intended use?
Thanks!

Yes,
Code:

// defined in {$C}

void *mono_findClass(const char *szAssembly, const char *namespaze, const char *name)
{
    void *domain = mono_domain_get();
    if (!domain)
        return 0;

    void *assembly = mono_domain_assembly_open(domain, szAssembly);
    if (!assembly)
        return 0;

    void *image = mono_assembly_get_image(assembly);
    if (!image)
        return 0;

    return mono_class_from_name(image, namespaze, name);
}

// will return the UnityEngine.Object[] type
// therefore -
// count - 0x18(x64) or 0xC(x86)
// start of array - 0x20(x64) or 0x10(x86)
void *mono_class_findEveryInstance(void *klass)
{
    void *resourcesClass = mono_findClass("UnityEngine.CoreModule", "UnityEngine", "Resources");
    if (!resourcesClass)
        resourcesClass = mono_findClass("UnityEngine", "UnityEngine", "Resources");

    void *objectClass = resourcesClass;
    if (!objectClass)
    {
        objectClass = mono_findClass("UnityEngine.CoreModule", "UnityEngine", "Object");
        if (!objectClass) // If we failed to find one in core module, we would try to find it in the unity's default module
            objectClass = mono_findClass("UnityEngine", "UnityEngine", "Object");
    }

    if (!objectClass)
        return 0;

    void *iter = 0;
    void *foundMethod = 0;

    for (void *method = mono_class_get_methods(objectClass, &iter); method; method = mono_class_get_methods(objectClass, &iter))
    {
        const char *methodName = mono_method_get_name(method);
        if (_stricmp(methodName, resourcesClass ? "FindObjectsOfTypeAll" : "FindObjectsOfType") == 0)
        {
            void *sig = mono_method_signature(method);
            if (!sig)
                continue;

            if (mono_signature_get_param_count(sig) == 1) // one parameter
            {
                void *paramIter = 0;
                void *params = mono_signature_get_params(sig, &paramIter);
                if (!params)
                    continue;

                void *paramClass = mono_type_get_class(params);
                if (!paramClass)
                    continue;

                const char *paramName = mono_class_get_name(paramClass);
                if (strstr(paramName, "Type"))
                {
                    void *type = mono_signature_get_return_type(sig);
                    if (!type)
                        continue;

                    if (mono_type_get_type(type) == 0x1D) // 0x1D - MONO_TYPE_SZARRAY
                    {
                        foundMethod = method;
                        break;
                    }
                }
            }
        }
    }

    if (foundMethod)
    {
        void *domain = mono_domain_get();

        void *klassType = mono_class_get_type(klass);
        void *objectType = mono_type_get_object(domain, klassType);
        if (!objectType)
            return 0;

        void *exc = 0;
        void *args[] = { objectType };
        void *result = mono_runtime_invoke(foundMethod, 0, args, &exc);
        if (!result || exc)
            return 0;

        return result;
    }

    return 0;
}

Simplified and turned into helper functions
Code:

void *klass = mono_findClass("Assembly-CSharp", "ExampleNamespace", "ExampleClass");
if (!klass)
    return;

void *array = mono_class_findEveryInstance(klass);
if (!array)
    return;

int count = mono_array_length(array);
for (int i = 0; i < count; i++)
{
    void *item = *(void**)((uintptr_t)array + 0x20 + 0x8 * i);
    // x86
    // void *item = *(void**)((uintptr_t)array + 0x10 + 0x4 * i);
   
    // item now holds the address of the object

    *(int*)((uintptr_t)item + 0x30) = 100; // let's say 0x30 offset holds our health, from here we set the health to 100, offsets can be seen via .NET info or Mono lookup
}
Back to top
View user's profile Send private message
Csimbi
I post too much
Reputation: 98

Joined: 14 Jul 2007
Posts: 3423

PostPosted: Tue Aug 18, 2026 10:52 am    Post subject: Reply with quote

Much appreciated!
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites