Last active
September 1, 2025 19:35
-
-
Save eprosync/97c0c2f4bf82898e70b2b7d1ca2d5fd6 to your computer and use it in GitHub Desktop.
Something about accessing mono via lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local mono = {} | |
| _G.mono = mono | |
| function mono.initialize(module) | |
| mono.module = module | |
| -- You could use FFI here but for now FFI isn't cross-compatible with memory | |
| local subroutine = {} | |
| mono.subroutine = subroutine | |
| subroutine.get_root_domain = memory.fetch(module, "mono_get_root_domain") | |
| if not subroutine.get_root_domain then return error("mono: unable to locate mono_get_root_domain") end | |
| subroutine.thread_attach = memory.fetch(module, "mono_thread_attach") | |
| if not subroutine.thread_attach then return error("mono: unable to locate mono_thread_attach") end | |
| subroutine.assembly_get_image = memory.fetch(module, "mono_assembly_get_image") | |
| if not subroutine.assembly_get_image then return error("mono: unable to locate mono_assembly_get_image") end | |
| subroutine.image_get_name = memory.fetch(module, "mono_image_get_name") | |
| if not subroutine.image_get_name then return error("mono: unable to locate mono_image_get_name") end | |
| subroutine.runtime_invoke = memory.fetch(module, "mono_runtime_invoke") | |
| if not subroutine.runtime_invoke then return error("mono: unable to locate mono_runtime_invoke") end | |
| subroutine.image_get_table_rows = memory.fetch(module, "mono_image_get_table_rows") | |
| if not subroutine.image_get_table_rows then return error("mono: unable to locate mono_image_get_table_rows") end | |
| subroutine.object_get_class = memory.fetch(module, "mono_object_get_class") | |
| if not subroutine.object_get_class then return error("mono: unable to locate mono_object_get_class") end | |
| subroutine.class_get = memory.fetch(module, "mono_class_get") | |
| if not subroutine.class_get then return error("mono: unable to locate mono_class_get") end | |
| subroutine.class_get_namespace = memory.fetch(module, "mono_class_get_namespace") | |
| if not subroutine.class_get_namespace then return error("mono: unable to locate mono_class_get_namespace") end | |
| subroutine.class_get_name = memory.fetch(module, "mono_class_get_name") | |
| if not subroutine.class_get_name then return error("mono: unable to locate mono_class_get_name") end | |
| subroutine.class_vtable = memory.fetch(module, "mono_class_vtable") | |
| if not subroutine.class_vtable then return error("mono: unable to locate mono_class_vtable") end | |
| subroutine.class_get_fields = memory.fetch(module, "mono_class_get_fields") | |
| if not subroutine.class_get_fields then return error("mono: unable to locate mono_class_get_fields") end | |
| subroutine.field_get_name = memory.fetch(module, "mono_field_get_name") | |
| if not subroutine.field_get_name then return error("mono: unable to locate mono_field_get_name") end | |
| subroutine.field_get_offset = memory.fetch(module, "mono_field_get_offset") | |
| if not subroutine.field_get_offset then return error("mono: unable to locate mono_field_get_offset") end | |
| subroutine.field_get_value = memory.fetch(module, "mono_field_get_value") | |
| if not subroutine.field_get_value then return error("mono: unable to locate mono_field_get_value") end | |
| subroutine.field_set_value = memory.fetch(module, "mono_field_set_value") | |
| if not subroutine.field_set_value then return error("mono: unable to locate mono_field_set_value") end | |
| subroutine.field_static_get_value = memory.fetch(module, "mono_field_static_get_value") | |
| if not subroutine.field_static_get_value then return error("mono: unable to locate mono_field_static_get_value") end | |
| subroutine.field_static_set_value = memory.fetch(module, "mono_field_static_set_value") | |
| if not subroutine.field_static_set_value then return error("mono: unable to locate mono_field_static_set_value") end | |
| subroutine.class_get_methods = memory.fetch(module, "mono_class_get_methods") | |
| if not subroutine.class_get_methods then return error("mono: unable to locate mono_class_get_methods") end | |
| subroutine.method_get_name = memory.fetch(module, "mono_method_get_name") | |
| if not subroutine.method_get_name then return error("mono: unable to locate mono_method_get_name") end | |
| end | |
| function mono.get_domain() | |
| return memory.subroutine.emit(mono.subroutine.get_root_domain) | |
| end | |
| function mono.attach() | |
| return memory.subroutine.emit(mono.subroutine.thread_attach, mono.get_domain()) | |
| end | |
| function mono.invoke(method, instance, ...) | |
| local argc = #({...}) | |
| local arg_block = nil | |
| if argc > 0 then | |
| arg_block = memory.allocate(argc * memory.size.address) | |
| for i, arg in ipairs({...}) do | |
| local slot = arg_block + (i - 1) * memory.size.address | |
| memory.write.pointer(slot, arg) | |
| end | |
| end | |
| local exception_ptr = memory.allocate(memory.size.address) | |
| memory.write.address(exception_ptr, memory.address(0)) | |
| local result = memory.subroutine.emit( | |
| mono.subroutine.runtime_invoke, | |
| method, | |
| instance or memory.address(0), | |
| arg_block or memory.address(0), | |
| exception_ptr | |
| ) | |
| local exc = memory.read.address(exception_ptr) | |
| if exc.raw ~= 0 then | |
| error("managed exception thrown.") | |
| end | |
| return result | |
| end | |
| function mono.get_assemblies_offset() | |
| local domain = mono.get_domain() | |
| for i=0, 0x160, 8 do | |
| local domain_assemblies = memory.offset(domain, i) | |
| local _domain_assemblies = memory.offset(domain_assemblies, 0) | |
| local failure = false | |
| for i=0, 20 do | |
| local ran, assembly = pcall(memory.read.address, _domain_assemblies) | |
| if not ran then failure = true break end | |
| _domain_assemblies = memory.read.address(memory.offset(_domain_assemblies, memory.size.address)) | |
| end | |
| if not failure then | |
| return i | |
| end | |
| end | |
| end | |
| function mono.get_assemblies() | |
| local domain = mono.get_domain() | |
| local domain_assemblies = memory.offset(domain, jit.arch == "x64" and 0x98 or 0x88) | |
| local _domain_assemblies = memory.offset(domain_assemblies, 0) | |
| local assemblies = {} | |
| local skip = true | |
| while true do | |
| local assembly = memory.read.address(_domain_assemblies) | |
| if not skip then assemblies[#assemblies+1] = assembly end | |
| _domain_assemblies = memory.read.address(memory.offset(_domain_assemblies, memory.size.address)) | |
| if _domain_assemblies.raw == 0 then break end | |
| skip = false | |
| end | |
| return assemblies | |
| end | |
| function mono.get_image_name(image) | |
| return memory.read.string(memory.subroutine.emit(mono.subroutine.image_get_name, image)) | |
| end | |
| function mono.get_image(assembly) | |
| return memory.subroutine.emit(mono.subroutine.assembly_get_image, assembly) | |
| end | |
| function mono.find_image(name) | |
| local assemblies = mono.get_assemblies() | |
| for i=1, #assemblies do | |
| local assembly = assemblies[i] | |
| local image = mono.get_image(assembly) | |
| local image_name = mono.get_image_name(image) | |
| if image_name == name then | |
| return image | |
| end | |
| end | |
| end | |
| function mono.get_class_name(class) | |
| return memory.read.string(memory.subroutine.emit(mono.subroutine.class_get_name, class)) | |
| end | |
| function mono.get_class_namespace(class) | |
| return memory.read.string(memory.subroutine.emit(mono.subroutine.class_get_namespace, class)) | |
| end | |
| function mono.get_class_vtable(class) | |
| local domain = mono.get_domain() | |
| return memory.subroutine.emit(mono.subroutine.class_vtable, domain, class) | |
| end | |
| function mono.get_object_class(object) | |
| return memory.subroutine.emit(mono.subroutine.object_get_class, object) | |
| end | |
| function mono.get_classes(image) | |
| local rows = memory.subroutine.emit(mono.subroutine.image_get_table_rows, image, memory.address(0x2)) -- MONO_TABLE_TYPEDEF | |
| local classes = {} | |
| for i=1, rows.int do | |
| local class = memory.subroutine.emit(mono.subroutine.class_get, image, memory.address(bit.bor(0x02000000, i))) -- MONO_TOKEN_TYPE_DEF | |
| classes[i] = class | |
| end | |
| return classes | |
| end | |
| function mono.find_class(image, name) | |
| local rows = memory.subroutine.emit(mono.subroutine.image_get_table_rows, image, memory.address(0x2)) -- MONO_TABLE_TYPEDEF | |
| for i=1, rows.int do | |
| local class = memory.subroutine.emit(mono.subroutine.class_get, image, memory.address(bit.bor(0x02000000, i))) -- MONO_TOKEN_TYPE_DEF | |
| local class_namespace = mono.get_class_namespace(class) | |
| local class_name = mono.get_class_name(class) | |
| if class_namespace == name or class_name == name then | |
| return class | |
| end | |
| end | |
| end | |
| function mono.set_field_value(object, field, value) | |
| return memory.subroutine.emit(mono.subroutine.field_set_value, object, field, value) | |
| end | |
| function mono.get_field_value(object, field) | |
| local ref = memory.allocate(memory.size.address) | |
| memory.subroutine.emit(mono.subroutine.field_get_value, object, field, ref) | |
| return ref | |
| end | |
| function mono.set_field_static_value(vt, field, value) | |
| return memory.subroutine.emit(mono.subroutine.field_static_set_value, vt, field, value) | |
| end | |
| function mono.get_field_static_value(vt, field) | |
| local ref = memory.allocate(memory.size.address) | |
| memory.subroutine.emit(mono.subroutine.field_static_get_value, vt, field, ref) | |
| return ref | |
| end | |
| function mono.get_field_offset(field) | |
| return memory.subroutine.emit(mono.subroutine.field_get_offset, field) | |
| end | |
| function mono.get_field_name(field) | |
| return memory.read.string(memory.subroutine.emit(mono.subroutine.field_get_name, field)) | |
| end | |
| function mono.get_fields(class) | |
| local ref = memory.allocate(memory.size.address) | |
| memory.write.address(ref, memory.address(0)) | |
| local fields = {} | |
| while true do | |
| local field = memory.subroutine.emit(mono.subroutine.class_get_fields, class, ref) | |
| if field.raw == 0 then break end | |
| fields[#fields+1] = field | |
| end | |
| return fields | |
| end | |
| function mono.find_field(class, name) | |
| local ref = memory.allocate(memory.size.address) | |
| memory.write.address(ref, memory.address(0)) | |
| while true do | |
| local field = memory.subroutine.emit(mono.subroutine.class_get_fields, class, ref) | |
| if field.raw == 0 then break end | |
| if mono.get_field_name(field) == name then return field end | |
| end | |
| end | |
| function mono.get_method_name(method) | |
| return memory.read.string(memory.subroutine.emit(mono.subroutine.method_get_name, method)) | |
| end | |
| function mono.get_methods(class) | |
| local ref = memory.allocate(memory.size.address) | |
| memory.write.address(ref, memory.address(0)) | |
| local methods = {} | |
| while true do | |
| local method = memory.subroutine.emit(mono.subroutine.class_get_methods, class, ref) | |
| if method.raw == 0 then break end | |
| methods[#methods+1] = method | |
| end | |
| return methods | |
| end | |
| function mono.find_method(class, name) | |
| local ref = memory.allocate(memory.size.address) | |
| memory.write.address(ref, memory.address(0)) | |
| while true do | |
| local method = memory.subroutine.emit(mono.subroutine.class_get_methods, class, ref) | |
| if method.raw == 0 then break end | |
| if mono.get_method_name(method) == name then return method end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment