From 84bde77928ba344b06c346418961b40d77aefad8 Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Sat, 26 Aug 2023 13:38:34 +0500 Subject: [PATCH 01/10] Complete DLL Ejection HOLD Control [CTRL] key and press "Activate Mono Features" to eject the dll --- .../MonoDataCollector/MonoDataCollector.cpp | 2 ++ .../MonoDataCollector/MonoDataCollector/PipeServer.cpp | 5 +++++ Cheat Engine/bin/autorun/monoscript.lua | 10 +++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp index b144c321..219dc727 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp @@ -90,6 +90,7 @@ DWORD WINAPI DataCollectorEntry(LPVOID lpThreadParameter) OutputDebugString("starting CPipeServer instance\n"); pw->Start(); + OutputDebugString("Destroying PipeServer\n"); DataCollectorThread=0; delete pw; @@ -99,6 +100,7 @@ DWORD WINAPI DataCollectorEntry(LPVOID lpThreadParameter) Sleep(1000); #ifdef _WINDOWS + OutputDebugString("Freeing Memory\n"); FreeLibraryAndExitThread(g_hInstance, 0); #endif return 0; diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp index f5bc7a7c..25314836 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp @@ -2946,6 +2946,11 @@ void CPipeServer::Start(void) break; case MONOCMD_TERMINATE: + if (pipehandle != INVALID_HANDLE_VALUE) + { + DisconnectNamedPipe(pipehandle); + CloseHandle(pipehandle); + } return; case MONOCMD_DISASSEMBLE: diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index 852b51b0..cd9660d8 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -3993,7 +3993,15 @@ end function miMonoActivateClick(sender) if monopipe then - monopipe.OnTimeout() + if isKeyPressed(VK_CONTROL) then + monopipe.lock() + monopipe.writeByte(MONOCMD_TERMINATE) + monopipe.unlock() + monopipe.OnTimeout() + print('dll ejected') + else + monopipe.OnTimeout() + end else if LaunchMonoDataCollector()==0 then showMessage(translate("Failure to launch ")) From a5880ebaf9e69f2b8fd4f8670f6e4b4ea6a92e85 Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Mon, 4 Sep 2023 07:12:00 +0500 Subject: [PATCH 02/10] Several debug inprovements Added a way to check if a class is a struct Fixed data structure dissect for Enum Class when in an array Added a way to enable console in dll to ease in debugging on windows. --- .../MonoDataCollector/MonoDataCollector.cpp | 28 +++++++++++++++-- .../MonoDataCollector/PipeServer.cpp | 31 ++++++++++++------- .../MonoDataCollector/PipeServer.h | 7 ++++- Cheat Engine/bin/autorun/monoscript.lua | 18 ++++++++--- 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp index 219dc727..213b986c 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp @@ -9,7 +9,6 @@ #include "PipeServer.h" - HANDLE DataCollectorThread; HANDLE SuicideThread; HINSTANCE g_hInstance; @@ -61,7 +60,17 @@ typedef int (NTAPI *ZWSETINFORMATIONTHREAD)( ); #endif - +#ifdef CUSTOM_DEBUG +FILE* CreateAndTestDebugConsole() +{ + FILE* f = nullptr; +#if DEBUG_CONSOLE + AllocConsole(); + freopen_s(&f, "CONOUT$", "w", stdout); +#endif + return f; +} +#endif DWORD WINAPI DataCollectorEntry(LPVOID lpThreadParameter) { @@ -85,7 +94,12 @@ DWORD WINAPI DataCollectorEntry(LPVOID lpThreadParameter) OutputDebugString("creating new CPipeServer instance\n"); pw=new CPipeServer(); - + +#ifdef CUSTOM_DEBUG + FILE* console = CreateAndTestDebugConsole(); + if (console) + printf("Console created!\n"); +#endif OutputDebugString("starting CPipeServer instance\n"); pw->Start(); @@ -94,6 +108,14 @@ DWORD WINAPI DataCollectorEntry(LPVOID lpThreadParameter) DataCollectorThread=0; delete pw; +#ifdef CUSTOM_DEBUG + if (console) + fclose(console); +#if DEBUG_CONSOLE + FreeConsole(); +#endif +#endif + if (SuicideThread) TerminateThread(SuicideThread, 0); diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp index 25314836..026ce375 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp @@ -21,7 +21,6 @@ #endif //linux - #include #include @@ -31,6 +30,15 @@ //todo: Make this multithreaded. So: Make a list of threads that can AV +void Log(_In_z_ _Printf_format_string_ char const* const _Format, ...) +{ +#ifdef DEBUG_CONSOLE + va_list args; + va_start(args, _Format); + vprintf(_Format, args); +#endif +} + BOOL ExpectingAccessViolations = FALSE; #ifdef _WINDOWS @@ -448,6 +456,7 @@ void CPipeServer::InitMono() mono_free = (MONO_FREE)GetProcAddress(hMono, "il2cpp_free"); mono_get_root_domain = (MONO_GET_ROOT_DOMAIN)GetProcAddress(hMono, "il2cpp_get_root_domain"); + mono_get_root_domain = mono_get_root_domain ? mono_get_root_domain : (MONO_GET_ROOT_DOMAIN)GetProcAddress(hMono, "mono_get_root_domain"); //some modern games have the same name as mono mono_thread_attach = (MONO_THREAD_ATTACH)GetProcAddress(hMono, "il2cpp_thread_attach"); mono_thread_detach = (MONO_THREAD_DETACH)GetProcAddress(hMono, "il2cpp_thread_detach"); @@ -542,7 +551,8 @@ void CPipeServer::InitMono() mono_method_desc_from_method = (MONO_METHOD_DESC_FROM_METHOD)GetProcAddress(hMono, "il2cpp_method_desc_from_method");; mono_method_desc_free = (MONO_METHOD_DESC_FREE)GetProcAddress(hMono, "il2cpp_method_desc_free");; - mono_string_new = (MONO_STRING_NEW)GetProcAddress(hMono, "il2cpp_string_new"); + mono_string_new = (MONO_STRING_NEW)GetProcAddress(hMono, "mono_string_new"); // il2cpp also has "mono_string_new". Th il2cpp_string_new is a different function + mono_string_new = mono_string_new ? mono_string_new : (MONO_STRING_NEW)GetProcAddress(hMono, "il2cpp_string_new"); mono_string_to_utf8 = (MONO_STRING_TO_UTF8)GetProcAddress(hMono, "il2cpp_string_to_utf8"); il2cpp_array_new = (IL2CPP_ARRAY_NEW)GetProcAddress(hMono, "il2cpp_array_new"); mono_array_element_size = (MONO_ARRAY_ELEMENT_SIZE)GetProcAddress(hMono, "il2cpp_array_element_size"); @@ -772,7 +782,7 @@ void CPipeServer::Object_New() domain = (void*)mono_domain_get(); void* klass = (void*)ReadQword(); - void* object = mono_object_new(domain, klass); + void* object = il2cpp ? mono_object_new(klass, klass) : mono_object_new(domain, klass); //No domain in il2cpp; And since it is __stdcall, the prms should be fine in x86 il2pp processes WriteQword((UINT64)object); } @@ -1588,16 +1598,17 @@ void CPipeServer::GetMonoDataCollectorVersion() WriteDword(MONO_DATACOLLECTORVERSION); } -void CPipeServer::NewString() +DECLSPEC_NOINLINE void CPipeServer::NewString() { + //Log("Creating new string\n"); void* domain = (void*)ReadQword(); - if (domain == NULL) + if (domain == NULL && !il2cpp) //No domain required in il2cpp domain = (void*)mono_get_root_domain(); char* s = ReadString(); + void* string = mono_string_new ? mono_string_new(domain, s) : nullptr; free(s); - void* string = mono_string_new(domain, s); WriteQword((UINT_PTR)string); } @@ -1647,6 +1658,7 @@ void CPipeServer::GetMethodParameters() { void* returntype = il2cpp_method_get_return_type(method); + WriteQword((UINT64)returntype); if (returntype) WriteDword(mono_type_get_type(returntype)); else @@ -1695,17 +1707,12 @@ void CPipeServer::GetMethodParameters() { MonoType* returntype = mono_signature_get_return_type(methodsignature); + WriteQword((UINT64)returntype); if (returntype) WriteDword(mono_type_get_type(returntype)); else WriteDword(0); } - - - - - - } else WriteByte(0); diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h index 2c98158a..d8da47d7 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h @@ -6,8 +6,13 @@ #endif +//#define CUSTOM_DEBUG +#ifdef CUSTOM_DEBUG +#define DEBUG_CONSOLE 1 +#endif // CUSTOM_DEBUG + //yyyymmdd -#define MONO_DATACOLLECTORVERSION 20230512 +#define MONO_DATACOLLECTORVERSION 20230830 #define MONO_TYPE_NAME_FORMAT_IL 0 #define MONO_TYPE_NAME_FORMAT_REFLECTION 1 diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index cd9660d8..0ee05b92 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -21,7 +21,7 @@ local dpiscale=getScreenDPI()/96 mono_timeout=3000 --change to 0 to never timeout (meaning: 0 will freeze your face off if it breaks on a breakpoint, just saying ...) -MONO_DATACOLLECTORVERSION=20230512 +MONO_DATACOLLECTORVERSION=20230830 MONOCMD_INITMONO=0 MONOCMD_OBJECT_GETCLASS=1 @@ -144,6 +144,9 @@ monoTypeToVartypeLookup[MONO_TYPE_R4]=vtSingle monoTypeToVartypeLookup[MONO_TYPE_R8]=vtDouble monoTypeToVartypeLookup[MONO_TYPE_STRING]=vtPointer --pointer to a string object monoTypeToVartypeLookup[MONO_TYPE_PTR]=vtPointer +monoTypeToVartypeLookup[MONO_TYPE_I]=vtPointer --IntPtr +monoTypeToVartypeLookup[MONO_TYPE_U]=vtPointer +monoTypeToVartypeLookup[MONO_TYPE_OBJECT]=vtPointer --object monoTypeToVartypeLookup[MONO_TYPE_BYREF]=vtPointer monoTypeToVartypeLookup[MONO_TYPE_CLASS]=vtPointer monoTypeToVartypeLookup[MONO_TYPE_FNPTR]=vtPointer @@ -166,7 +169,7 @@ monoTypeToCStringLookup[MONO_TYPE_I8]='int64' monoTypeToCStringLookup[MONO_TYPE_U8]='unsigned int 64' monoTypeToCStringLookup[MONO_TYPE_R4]='single' monoTypeToCStringLookup[MONO_TYPE_R8]='double' -monoTypeToCStringLookup[MONO_TYPE_STRING]='String' --pointer to a string object +monoTypeToCStringLookup[MONO_TYPE_STRING]='String' monoTypeToCStringLookup[MONO_TYPE_PTR]='Pointer' monoTypeToCStringLookup[MONO_TYPE_BYREF]='Object' monoTypeToCStringLookup[MONO_TYPE_CLASS]='Object' @@ -1415,6 +1418,10 @@ function mono_class_isValueType(klass) return retv==1 end +function mono_class_isStruct(klass) + return mono_class_isValueType(klass) and not(mono_class_isEnum(klass)) and not(mono_class_IsPrimitive(klass)) +end + function mono_class_isSubClassOf(klass,parentklass,checkInterfaces) checkInterfaces = checkInterfaces and 1 or 0 if not klass or klass==0 then return false end @@ -2112,7 +2119,7 @@ function mono_class_enumFields(class, includeParents, expandedStructs) if expandedStructs then for k,v in pairs(mainFields) do local lockls = mono_field_getClass(v.field) - if ((v.monotype==MONO_TYPE_VALUETYPE) and not(mono_class_isEnum(lockls)) and not(mono_class_isSubClassOf(mono_field_getClass(v.field),class))) and not(v.isStatic or v.isConst) then --does not want to infinitely loop if the struct has some static member of the same class + if not(v.isStatic or v.isConst) and mono_class_isStruct(lockls) and not(mono_class_isSubClassOf(lockls,class)) then --does not want to infinitely loop if the struct has some static member of the same class local subFields = GetFields(lockls, includeParents, expandedStructs, true) --print(v.name, v.typename, fu(v.monotype)) if #subFields >0 then @@ -2626,6 +2633,7 @@ function mono_method_get_parameters(method) end --result + result.returnmonotype = monopipe.readQword() result.returntype=monopipe.readDword() monopipe.unlock() @@ -4644,7 +4652,7 @@ function monoform_exportArrayStructInternal(acs, arraytype, elemtype, recursive, end local elementkls = mono_class_getArrayElementClass(arraytype) local elementmonotype = mono_type_get_type(mono_class_get_type(elementkls)) - local isStruct = mono_class_isValueType(elementkls) and not(mono_class_IsPrimitive(elementkls)) and not(mono_class_isEnum(elementkls)) + local isStruct = mono_class_isStruct(elementkls)--mono_class_isValueType(elementkls) and not(mono_class_IsPrimitive(elementkls)) and not(mono_class_isEnum(elementkls)) --print(fu(elementkls),mono_class_getFullName(elementkls),fu(elementmonotype)) if isStruct then --print("yep, a struct") @@ -4657,7 +4665,7 @@ function monoform_exportArrayStructInternal(acs, arraytype, elemtype, recursive, ce=acs.addElement() ce.Name=string.format("[%d]%s",j,nm) ce.Offset=j*psize+start+v.offset-suboffset - ce.Vartype= monoTypeToVarType( v.monotype ) --vtPointer + ce.Vartype= mono_class_isEnum(mono_field_getClass( v.field )) and vtDword or monoTypeToVarType( v.monotype ) --vtPointer if ce.Vartype == vtDword then ce.DisplayMethod = 'dtSignedInteger' end From 8aed58b7df0c5a1baea2cd0ea88b815fb75509a0 Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Sun, 29 Oct 2023 21:27:26 +0500 Subject: [PATCH 03/10] Added a function to get full name of MonoMethod. --- .gitignore | 15 +++++++++++++ .../MonoDataCollector/PipeServer.cpp | 21 +++++++++++++++++++ .../MonoDataCollector/PipeServer.h | 4 ++++ Cheat Engine/bin/autorun/monoscript.lua | 12 +++++++++++ 4 files changed, 52 insertions(+) diff --git a/.gitignore b/.gitignore index e0bc7086..6fdc89b2 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,18 @@ Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/stdafx.obj Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/vc143.pdb Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj +Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj +*.vcxproj +Cheat Engine/MonoDataCollector/.vs/MonoDataCollector/v17/ipch/AutoPCH/f68d19c2fab066ca/DLLMAIN.ipch +Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj +Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoDataCollector.vcxproj.FileListAbsolute.txt +Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoDataCollector64.Build.CppClean.log +Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj +Cheat Engine/MonoDataCollector/.vs/MonoDataCollector/v17/ipch/AutoPCH/3d2a0f62d32e0fb5/CMEMSTREAM.ipch +Cheat Engine/MonoDataCollector/.vs/MonoDataCollector/FileContentIndex/62bb0928-9760-4e2d-9c74-b56a96c8718a.vsidx +Cheat Engine/cheatengine.lpi +Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoData.941726A9.tlog/Cl.items.tlog +*.tlog +*.lpi +*.vcxproj +Cheat Engine/cheatengine.lpi diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp index 026ce375..4378ab06 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp @@ -519,6 +519,8 @@ void CPipeServer::InitMono() mono_type_get_name_full = (MONO_TYPE_GET_NAME_FULL)GetProcAddress(hMono, "il2cpp_type_get_name_full"); mono_method_get_name = (MONO_METHOD_GET_NAME)GetProcAddress(hMono, "il2cpp_method_get_name"); + mono_method_get_full_name = (MONO_METHOD_GET_FULL_NAME)GetProcAddress(hMono, "il2cpp_method_get_full_name"); + mono_method_get_full_name = mono_method_get_full_name ? mono_method_get_full_name : (MONO_METHOD_GET_FULL_NAME)GetProcAddress(hMono, "mono_method_get_full_name"); mono_method_get_class = (MONO_METHOD_GET_CLASS)GetProcAddress(hMono, "il2cpp_method_get_class"); mono_method_get_header = (MONO_METHOD_GET_HEADER)GetProcAddress(hMono, "il2cpp_method_get_header"); mono_method_get_flags = (MONO_METHOD_GET_FLAGS)GetProcAddress(hMono, "il2cpp_method_get_flags"); @@ -680,6 +682,7 @@ void CPipeServer::InitMono() mono_type_get_name_full = (MONO_TYPE_GET_NAME_FULL)GetProcAddress(hMono, "mono_type_get_name_full"); mono_method_get_name = (MONO_METHOD_GET_NAME)GetProcAddress(hMono, "mono_method_get_name"); + mono_method_get_full_name = (MONO_METHOD_GET_FULL_NAME)GetProcAddress(hMono, "mono_method_get_full_name"); mono_method_get_class = (MONO_METHOD_GET_CLASS)GetProcAddress(hMono, "mono_method_get_class"); mono_method_get_header = (MONO_METHOD_GET_HEADER)GetProcAddress(hMono, "mono_method_get_header"); mono_method_get_flags = (MONO_METHOD_GET_FLAGS)GetProcAddress(hMono, "mono_method_get_flags"); @@ -1532,6 +1535,20 @@ void CPipeServer::GetMethodName() Write(methodname, (WORD)strlen(methodname)); } +void CPipeServer::GetMethodFullName() +{ + void* method = (void*)ReadQword(); + if (method && mono_method_get_full_name) + { + char* methodname = mono_method_get_full_name(method); + + WriteWord((WORD)strlen(methodname)); + Write(methodname, (WORD)strlen(methodname)); + } + else + WriteWord(0); +} + void CPipeServer::GetMethodClass() { void* method = (void*)ReadQword(); @@ -2935,6 +2952,10 @@ void CPipeServer::Start(void) case MONOCMD_GETMETHODNAME: GetMethodName(); break; + + case MONOCMD_GETMETHODFULLNAME: + GetMethodFullName(); + break; case MONOCMD_GETMETHODCLASS: GetMethodClass(); diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h index d8da47d7..edba3a92 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h @@ -83,6 +83,7 @@ #define MONOCMD_MONOOBJECTUNBOX 60 #define MONOCMD_MONOARRAYNEW 61 #define MONOCMD_ENUMINTERFACESOFCLASS 62 +#define MONOCMD_GETMETHODFULLNAME 63 typedef struct {} MonoType; @@ -171,6 +172,7 @@ typedef void* (__cdecl * MONO_FIELD_GET_VALUE_OBJECT)(void *domain, void* field, typedef char* (__cdecl *MONO_METHOD_GET_NAME)(void *method); +typedef char* (__cdecl *MONO_METHOD_GET_FULL_NAME)(void *method); typedef void* (__cdecl *MONO_COMPILE_METHOD)(void *method); typedef void (__cdecl *MONO_FREE_METHOD)(void *method); @@ -345,6 +347,7 @@ private: MONO_METHOD_GET_FLAGS mono_method_get_flags; MONO_METHOD_GET_NAME mono_method_get_name; + MONO_METHOD_GET_FULL_NAME mono_method_get_full_name; MONO_METHOD_GET_HEADER mono_method_get_header; MONO_METHOD_GET_CLASS mono_method_get_class; MONO_METHOD_SIG mono_method_signature; @@ -456,6 +459,7 @@ private: void FindClass(); void FindMethod(); void GetMethodName(); + void GetMethodFullName(); void GetMethodClass(); void GetKlassName(); void GetClassNamespace(); diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index 0ee05b92..bdd78dd0 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -89,6 +89,7 @@ MONOCMD_GETREFLECTIONMETHODOFMONOMETHOD = 59 MONOCMD_MONOOBJECTUNBOX = 60 MONOCMD_MONOARRAYNEW = 61 MONOCMD_ENUMINTERFACESOFCLASS = 62 +MONOCMD_GETMETHODFULLNAME = 63 MONO_TYPE_END = 0x00 -- End of List MONO_TYPE_VOID = 0x01 @@ -2580,6 +2581,17 @@ function mono_method_getName(method) return result; end +function mono_method_getFullName(monomethod) + monopipe.lock() + monopipe.writeByte(MONOCMD_GETMETHODFULLNAME) + monopipe.writeQword(monomethod) + local namelength=monopipe.readWord() + local result=monopipe.readString(namelength) + monopipe.unlock() + return result or '' +end + + function mono_method_getHeader(method) --if debug_canBreak() then return nil end if method==nil then return nil end From dc51fa522d012bfb993dbb98d5e341384177d760 Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Wed, 1 Nov 2023 09:10:10 +0500 Subject: [PATCH 04/10] Mono invoke now will return exception as string when occurred --- .gitignore | 3 + .../MonoDataCollector/PipeServer.cpp | 182 ++++++++++-------- Cheat Engine/bin/autorun/monoscript.lua | 11 +- 3 files changed, 113 insertions(+), 83 deletions(-) diff --git a/.gitignore b/.gitignore index 6fdc89b2..8cefd6de 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoData.941726A9.t *.lpi *.vcxproj Cheat Engine/cheatengine.lpi +Cheat Engine/cheatengine.lpi +*.vsidx +*.lpi diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp index 4378ab06..5041eca6 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp @@ -561,6 +561,7 @@ void CPipeServer::InitMono() mono_value_box = (MONO_VALUE_BOX)GetProcAddress(hMono, "il2cpp_value_box"); mono_object_unbox = (MONO_OBJECT_UNBOX)GetProcAddress(hMono, "il2cpp_object_unbox"); mono_object_new = (MONO_OBJECT_NEW)GetProcAddress(hMono, "il2cpp_object_new"); + mono_object_to_string = (MONO_OBJECT_TO_STRING)GetProcAddress(hMono, "il2cpp_object_to_string"); mono_class_get_type = (MONO_CLASS_GET_TYPE)GetProcAddress(hMono, "il2cpp_class_get_type"); mono_type_get_class = (MONO_TYPE_GET_CLASS)GetProcAddress(hMono, "il2cpp_type_get_class"); @@ -722,6 +723,7 @@ void CPipeServer::InitMono() mono_value_box = (MONO_VALUE_BOX)GetProcAddress(hMono, "mono_value_box"); mono_object_unbox = (MONO_OBJECT_UNBOX)GetProcAddress(hMono, "mono_object_unbox"); mono_object_new = (MONO_OBJECT_NEW)GetProcAddress(hMono, "mono_object_new"); + mono_object_to_string = (MONO_OBJECT_TO_STRING)GetProcAddress(hMono, "mono_object_to_string"); mono_object_isinst = (MONO_OBJECT_ISINST)GetProcAddress(hMono, "mono_object_isinst"); mono_get_enum_class = (MONO_GET_ENUM_CLASS)GetProcAddress(hMono, "mono_get_enum_class"); @@ -2409,102 +2411,120 @@ void CPipeServer::InvokeMethod(void) } try { - MonoObject* exception = {}; + MonoObject* exception = nullptr; result = mono_runtime_invoke(method, pThis, arry, &exception); if (!result) { WriteByte(MONO_TYPE_VOID); WriteQword((UINT64)result); - return; } - void* klass = mono_object_get_class(result); - void* type = klass ? mono_class_get_type(klass) : NULL; - int returntype = type ? mono_type_get_type(type) : MONO_TYPE_VOID; - WriteByte(returntype); - switch (returntype) + else { - case MONO_TYPE_STRING: - { - if (il2cpp) + void* klass = mono_object_get_class(result); + void* type = klass ? mono_class_get_type(klass) : NULL; + int returntype = type ? mono_type_get_type(type) : MONO_TYPE_VOID; + WriteByte(returntype); + switch (returntype) { - wchar_t* ptr = il2cpp_string_chars(result); + case MONO_TYPE_STRING: + { + if (il2cpp) + { + wchar_t* ptr = il2cpp_string_chars(result); #ifdef _WINDOWS - int l = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, NULL, 0, NULL, NULL); - char* c = (char*)malloc(l + 1); - l = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, c, l, NULL, NULL); - c[l] = 0; - WriteString(c); - free(c); + int l = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, NULL, 0, NULL, NULL); + char* c = (char*)malloc(l + 1); + l = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, c, l, NULL, NULL); + c[l] = 0; + WriteString(c); + free(c); #else - //todo: unsure about this - std::wstring_convert, char16_t> convert; - std::string dest = convert.to_bytes((char16_t*)ptr); - WriteString(dest.c_str()); + //todo: unsure about this + std::wstring_convert, char16_t> convert; + std::string dest = convert.to_bytes((char16_t*)ptr); + WriteString(dest.c_str()); #endif - /*_bstr_t b((wchar_t*)il2cpp_string_chars(result)); - WriteString((char*)b);*/ + /*_bstr_t b((wchar_t*)il2cpp_string_chars(result)); + WriteString((char*)b);*/ + } + else + { + char* ptr = mono_string_to_utf8(result); + WriteString(ptr); + g_free(ptr); + } + } + break; + case MONO_TYPE_CHAR: + WriteString((char*)mono_object_unbox(result)); + break; + case MONO_TYPE_R4: + { + float f = *(float*)mono_object_unbox(result); + Write(&f, 4); + }break; + case MONO_TYPE_R8: + { + double d = *(double*)mono_object_unbox(result); + Write(&d, 8); + }break; + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_BOOLEAN: + WriteByte(*(BYTE*)mono_object_unbox(result)); + break; + case MONO_TYPE_I2: + case MONO_TYPE_U2: + WriteWord(*(WORD*)mono_object_unbox(result)); + break; + case MONO_TYPE_I4: + case MONO_TYPE_U4: + WriteDword(*(DWORD*)mono_object_unbox(result)); + break; + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + WriteQword(*(UINT64*)mono_object_unbox(result)); + break; + case MONO_TYPE_VALUETYPE: + WriteQword((UINT64)mono_object_unbox(result)); + break; + /*case MONO_TYPE_PTR: + case MONO_TYPE_BYREF: + case MONO_TYPE_CLASS: + case MONO_TYPE_FNPTR: + case MONO_TYPE_GENERICINST: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_VALUETYPE: + { + WriteQword((INT64)result); + } + break;*/ + + default: + WriteQword((INT64)result); + break; + } + } + + // Push exception is caused + if (exception && mono_object_to_string && mono_string_to_utf8) + { + WriteByte(1); + void* MonoString = mono_object_to_string(exception, (void**) & exception); + if (MonoString) + { + WriteByte(1); + WriteString( mono_string_to_utf8(MonoString) ); } else - { - char* ptr = mono_string_to_utf8(result); - WriteString(ptr); - g_free(ptr); - } - } - break; - case MONO_TYPE_CHAR: - WriteString((char*)mono_object_unbox(result)); - break; - case MONO_TYPE_R4: - { - float f = *(float*)mono_object_unbox(result); - Write(&f, 4); - }break; - case MONO_TYPE_R8: - { - double d = *(double*)mono_object_unbox(result); - Write(&d, 8); - }break; - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_BOOLEAN: - WriteByte(*(BYTE*)mono_object_unbox(result)); - break; - case MONO_TYPE_I2: - case MONO_TYPE_U2: - WriteWord(*(WORD*)mono_object_unbox(result)); - break; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - WriteDword(*(DWORD*)mono_object_unbox(result)); - break; - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - WriteQword(*(UINT64*)mono_object_unbox(result)); - break; - case MONO_TYPE_VALUETYPE: - WriteQword((UINT64)mono_object_unbox(result)); - break; - /*case MONO_TYPE_PTR: - case MONO_TYPE_BYREF: - case MONO_TYPE_CLASS: - case MONO_TYPE_FNPTR: - case MONO_TYPE_GENERICINST: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_VALUETYPE: - { - WriteQword((INT64)result); - } - break;*/ - - default: - WriteQword((INT64)result); - break; + WriteByte(0); } + else + WriteByte(0); } catch (...) { diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index bdd78dd0..1ba0504b 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -3115,11 +3115,18 @@ function mono_invoke_method(domain, method, object, args) mono_writeObject(args[i].type, args[i].value) end - local result=mono_readObject() + local result =mono_readObject() --print(type(result),result) if monopipe then + local exception = nil + if monopipe.readByte() == 1 then + if monopipe.readByte() == 1 then + local excplen = monopipe.readWord() + exception = monopipe.readString(excplen) + end + end monopipe.unlock() - return result + return result, exception else --something bad happened LaunchMonoDataCollector() From a24d07aab1196f803a3ca96b023e597250883f9a Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Wed, 1 Nov 2023 15:51:40 +0500 Subject: [PATCH 05/10] Added a few functions for C Pointer lookup and field type >mono_ptr_class_get >mono_field_get_type >mono_type_get_ptr_type >mono_type_is_byref --- .gitignore | 1 + .../MonoDataCollector/PipeServer.cpp | 113 ++++++++++++++---- .../MonoDataCollector/PipeServer.h | 19 ++- Cheat Engine/bin/autorun/monoscript.lua | 48 ++++++-- 4 files changed, 146 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 8cefd6de..b7365d5f 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ Cheat Engine/cheatengine.lpi Cheat Engine/cheatengine.lpi *.vsidx *.lpi +Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp index 5041eca6..04a8e7c0 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.cpp @@ -514,9 +514,10 @@ void CPipeServer::InitMono() mono_type_get_name = (MONO_TYPE_GET_NAME)GetProcAddress(hMono, "il2cpp_type_get_name"); mono_type_get_type = (MONO_TYPE_GET_TYPE)GetProcAddress(hMono, "il2cpp_type_get_type"); + mono_type_get_name_full = (MONO_TYPE_GET_NAME_FULL)GetProcAddress(hMono, "il2cpp_type_get_name_full"); + mono_type_is_byref = (MONO_TYPE_IS_BYREF)GetProcAddress(hMono, "il2cpp_type_is_byref"); il2cpp_type_get_object = (IL2CPP_TYPE_GET_OBJECT)GetProcAddress(hMono, "il2cpp_type_get_object"); il2cpp_method_get_object = (IL2CPP_METHOD_GET_OBJECT)GetProcAddress(hMono, "il2cpp_method_get_object"); - mono_type_get_name_full = (MONO_TYPE_GET_NAME_FULL)GetProcAddress(hMono, "il2cpp_type_get_name_full"); mono_method_get_name = (MONO_METHOD_GET_NAME)GetProcAddress(hMono, "il2cpp_method_get_name"); mono_method_get_full_name = (MONO_METHOD_GET_FULL_NAME)GetProcAddress(hMono, "il2cpp_method_get_full_name"); @@ -571,6 +572,10 @@ void CPipeServer::InitMono() mono_runtime_invoke = (MONO_RUNTIME_INVOKE)GetProcAddress(hMono, "il2cpp_runtime_invoke"); mono_runtime_object_init = (MONO_RUNTIME_OBJECT_INIT)GetProcAddress(hMono, "il2cpp_runtime_object_init"); + mono_ptr_class_get = (MONO_PTR_GET_CLASS)GetProcAddress(hMono, "il2cpp_ptr_class_get"); + mono_ptr_class_get = mono_ptr_class_get ? mono_ptr_class_get : (MONO_PTR_GET_CLASS)GetProcAddress(hMono, "mono_ptr_class_get"); + mono_type_get_ptr_type = (MONO_PTR_GET_CLASS)GetProcAddress(hMono, "il2cpp_type_get_ptr_type"); + mono_type_get_ptr_type = mono_type_get_ptr_type ? mono_type_get_ptr_type : (MONO_PTR_GET_CLASS)GetProcAddress(hMono, "mono_type_get_ptr_type"); mono_assembly_name_new = (MONO_ASSEMBLY_NAME_NEW)GetProcAddress(hMono, "il2cpp_assembly_name_new"); mono_assembly_loaded = (MONO_ASSEMBLY_LOADED)GetProcAddress(hMono, "il2cpp_assembly_loaded"); @@ -679,8 +684,9 @@ void CPipeServer::InitMono() mono_type_get_name = (MONO_TYPE_GET_NAME)GetProcAddress(hMono, "mono_type_get_name"); mono_type_get_type = (MONO_TYPE_GET_TYPE)GetProcAddress(hMono, "mono_type_get_type"); mono_type_get_object = (MONO_TYPE_GET_OBJECT)GetProcAddress(hMono, "mono_type_get_object"); - mono_method_get_object = (MONO_METHOD_GET_OBJECT)GetProcAddress(hMono, "mono_method_get_object"); mono_type_get_name_full = (MONO_TYPE_GET_NAME_FULL)GetProcAddress(hMono, "mono_type_get_name_full"); + mono_type_is_byref = (MONO_TYPE_IS_BYREF)GetProcAddress(hMono, "mono_type_is_byref"); + mono_method_get_object = (MONO_METHOD_GET_OBJECT)GetProcAddress(hMono, "mono_method_get_object"); mono_method_get_name = (MONO_METHOD_GET_NAME)GetProcAddress(hMono, "mono_method_get_name"); mono_method_get_full_name = (MONO_METHOD_GET_FULL_NAME)GetProcAddress(hMono, "mono_method_get_full_name"); @@ -735,6 +741,8 @@ void CPipeServer::InitMono() mono_runtime_invoke = (MONO_RUNTIME_INVOKE)GetProcAddress(hMono, "mono_runtime_invoke"); mono_runtime_object_init = (MONO_RUNTIME_OBJECT_INIT)GetProcAddress(hMono, "mono_runtime_object_init"); + mono_ptr_class_get = (MONO_PTR_GET_CLASS)GetProcAddress(hMono, "mono_ptr_class_get"); + mono_type_get_ptr_type = (MONO_PTR_GET_CLASS)GetProcAddress(hMono, "mono_type_get_ptr_type"); mono_assembly_name_new = (MONO_ASSEMBLY_NAME_NEW)GetProcAddress(hMono, "mono_assembly_name_new"); mono_assembly_loaded = (MONO_ASSEMBLY_LOADED)GetProcAddress(hMono, "mono_assembly_loaded"); @@ -1631,6 +1639,28 @@ DECLSPEC_NOINLINE void CPipeServer::NewString() WriteQword((UINT_PTR)string); } +void CPipeServer::GetClassFromPointer() +{ + void* ptr = (void*)ReadQword(); + if (ptr && mono_ptr_class_get) + { + WriteQword((UINT64)mono_ptr_class_get(ptr)); + } + else + WriteQword(0); +} + +void CPipeServer::GetTypeFromPointerType() +{ + void* type = (void*)ReadQword(); + if (type && mono_type_get_ptr_type) + { + WriteQword((UINT64)mono_type_get_ptr_type(type)); + } + else + WriteQword(0); +} + void CPipeServer::DisassembleMethod() { void* method = (void*)ReadQword(); @@ -1708,30 +1738,24 @@ void CPipeServer::GetMethodParameters() WriteByte(0); } - if (paramcount) + gpointer iter = NULL; + MonoType* paramtype; + + for (i = 0; i < paramcount; i++) { - gpointer iter = NULL; - MonoType* paramtype; - - for (i = 0; i < paramcount; i++) - { - paramtype = mono_signature_get_params((MonoMethodSignature*)methodsignature, &iter); - - if (paramtype) - WriteDword(mono_type_get_type(paramtype)); - else - WriteDword(0); - }; - } - - { - MonoType* returntype = mono_signature_get_return_type(methodsignature); - WriteQword((UINT64)returntype); - if (returntype) - WriteDword(mono_type_get_type(returntype)); + paramtype = mono_signature_get_params((MonoMethodSignature*)methodsignature, &iter); + WriteQword((UINT64)paramtype); + if (paramtype) + WriteDword(mono_type_get_type(paramtype)); else WriteDword(0); - } + }; + MonoType* returntype = mono_signature_get_return_type(methodsignature); + WriteQword((UINT64)returntype); + if (returntype) + WriteDword(mono_type_get_type(returntype)); + else + WriteDword(0); } else WriteByte(0); @@ -1969,7 +1993,7 @@ void CPipeServer::GetStaticFieldAddressFromClass(void) } } -void CPipeServer::GetTypeClass(void) +void CPipeServer::GetFieldClass(void) { void* field = (void*)ReadQword(); // TODO: this should be monotype but EnumFieldsInClass effectively returns fieldtype ptr void* type = field ? mono_field_get_type(field) : NULL; @@ -1983,6 +2007,15 @@ void CPipeServer::GetTypeClass(void) WriteQword((UINT_PTR)klass); } +void CPipeServer::GetFieldType() +{ + void* field = (void*)ReadQword(); + if (field && mono_field_get_type) + WriteQword((UINT_PTR)mono_field_get_type(field)); + else + WriteQword(0); +} + void CPipeServer::GetArrayElementClass(void) { void* klass = (void*)ReadQword(); @@ -2708,6 +2741,18 @@ void CPipeServer::IsSubClassOf() WriteByte(0); //not supported } +void CPipeServer::IsTypeByReference() +{ + void* monotype = (void*)ReadQword(); + if (monotype && mono_type_is_byref) + { + bool bIsByRef = mono_type_is_byref(monotype); + WriteByte(bIsByRef); + } + else + WriteByte(0); +} + void CPipeServer::GetArrayElementSize() { void* klass = (void*)ReadQword(); @@ -3025,8 +3070,12 @@ void CPipeServer::Start(void) GetStaticFieldAddressFromClass(); break; - case MONOCMD_GETTYPECLASS: - GetTypeClass(); + case MONOCMD_GETFIELDCLASS: + GetFieldClass(); + break; + + case MONOCMD_GETFIELDTYPE: + GetFieldType(); break; case MONOCMD_GETARRAYELEMENTCLASS: @@ -3065,6 +3114,10 @@ void CPipeServer::Start(void) IsSubClassOf(); break; + case MONOCMD_TYPEISBYREF: + IsTypeByReference(); + break; + case MONOCMD_ISIL2CPP: IsIL2CPP(); break; @@ -3137,6 +3190,14 @@ void CPipeServer::Start(void) NewCSArray(); break; + case MONOCMD_GETPTRTYPECLASS: + GetClassFromPointer(); + break; + + case MONOCMD_GETTYPEPTRTYPE: + GetTypeFromPointerType(); + break; + } ExpectingAccessViolations = FALSE; diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h index edba3a92..fd171fe1 100755 --- a/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h +++ b/Cheat Engine/MonoDataCollector/MonoDataCollector/PipeServer.h @@ -47,7 +47,7 @@ #define MONOCMD_GETMETHODSIGNATURE 24 #define MONOCMD_GETPARENTCLASS 25 #define MONOCMD_GETSTATICFIELDADDRESSFROMCLASS 26 -#define MONOCMD_GETTYPECLASS 27 +#define MONOCMD_GETFIELDCLASS 27 #define MONOCMD_GETARRAYELEMENTCLASS 28 #define MONOCMD_FINDMETHODBYDESC 29 #define MONOCMD_INVOKEMETHOD 30 @@ -84,6 +84,10 @@ #define MONOCMD_MONOARRAYNEW 61 #define MONOCMD_ENUMINTERFACESOFCLASS 62 #define MONOCMD_GETMETHODFULLNAME 63 +#define MONOCMD_TYPEISBYREF 64 +#define MONOCMD_GETPTRTYPECLASS 65 +#define MONOCMD_GETFIELDTYPE 66 +#define MONOCMD_GETTYPEPTRTYPE 67 typedef struct {} MonoType; @@ -155,10 +159,13 @@ typedef int (__cdecl *MONO_FIELD_GET_OFFSET)(void *field); typedef char* (__cdecl *MONO_TYPE_GET_NAME)(void *type); typedef void* (__cdecl* MONO_TYPE_GET_CLASS)(void* type); typedef int (__cdecl *MONO_TYPE_GET_TYPE)(void *type); +typedef int (__cdecl *MONO_TYPE_IS_BYREF)(void *monotype); typedef void* (__cdecl *MONO_TYPE_GET_OBJECT)(void *domain, void *type); typedef void* (__cdecl *IL2CPP_TYPE_GET_OBJECT)(void *type); typedef void* (__cdecl *MONO_METHOD_GET_OBJECT)(void *domain, void *method, void* klass); typedef void* (__cdecl *IL2CPP_METHOD_GET_OBJECT)(void* method, void* klass); +typedef void* (__cdecl* MONO_PTR_GET_CLASS)(void* monotype); +typedef void* (__cdecl* MONO_TYPE_GET_PTR_TYPE)(void* ptrmonotype); typedef char* (__cdecl *MONO_TYPE_GET_NAME_FULL)(void *type, int format); @@ -335,6 +342,7 @@ private: MONO_TYPE_GET_NAME mono_type_get_name; MONO_TYPE_GET_TYPE mono_type_get_type; + MONO_TYPE_IS_BYREF mono_type_is_byref; MONO_TYPE_GET_OBJECT mono_type_get_object; //return a ReflectionType* object IL2CPP_TYPE_GET_OBJECT il2cpp_type_get_object; MONO_METHOD_GET_OBJECT mono_method_get_object; @@ -344,6 +352,8 @@ private: MONO_TYPE_GET_NAME_FULL mono_type_get_name_full; MONO_FIELD_GET_FLAGS mono_field_get_flags; MONO_FIELD_GET_VALUE_OBJECT mono_field_get_value_object; + MONO_PTR_GET_CLASS mono_ptr_class_get; + MONO_TYPE_GET_PTR_TYPE mono_type_get_ptr_type; MONO_METHOD_GET_FLAGS mono_method_get_flags; MONO_METHOD_GET_NAME mono_method_get_name; @@ -479,7 +489,8 @@ private: void UnBoxMonoObject(); void GetVTableFromClass(); void GetStaticFieldAddressFromClass(); - void GetTypeClass(); + void GetFieldClass(); + void GetFieldType(); void GetArrayElementClass(); void FindMethodByDesc(); void InvokeMethod(); @@ -492,6 +503,7 @@ private: void IsEnumClass(); void IsValueTypeClass(); void IsSubClassOf(); + void IsTypeByReference(); void GetArrayElementSize(); void NewCSArray(); void IsIL2CPP(); @@ -501,6 +513,9 @@ private: void GetMonoDataCollectorVersion(); void NewString(); + void GetClassFromPointer(); + void GetTypeFromPointerType(); + public: CPipeServer(void); ~CPipeServer(void); diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index 1ba0504b..ce5cc55b 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -90,6 +90,10 @@ MONOCMD_MONOOBJECTUNBOX = 60 MONOCMD_MONOARRAYNEW = 61 MONOCMD_ENUMINTERFACESOFCLASS = 62 MONOCMD_GETMETHODFULLNAME = 63 +MONOCMD_TYPEISBYREF = 64 +MONOCMD_GETPTRTYPECLASS = 65 +MONOCMD_GETFIELDTYPE = 66 +MONOCMD_GETTYPEPTRTYPE = 67 MONO_TYPE_END = 0x00 -- End of List MONO_TYPE_VOID = 0x01 @@ -1556,6 +1560,33 @@ function mono_class_getImage(class) return result; end +function mono_ptr_class_get(fieldtype_or_ptrtype) +--returns the MonoType* object which is a pointer to the given type. Use "mono_class_getFullName" on the returned value to see the difference. + monopipe.lock() + monopipe.writeByte(MONOCMD_GETPTRTYPECLASS) + monopipe.writeQword(fieldtype_or_ptrtype) + local val = monopipe.readQword() + monopipe.unlock() + return val +end + +function mono_field_get_type(monofield) + monopipe.lock() + monopipe.writeByte(MONOCMD_GETFIELDTYPE) + monopipe.writeQword(monofield) + local val = monopipe.readQword() + monopipe.unlock() + return val +end + +function mono_type_get_ptr_type(ptrtype) + monopipe.lock() + monopipe.writeByte(MONOCMD_GETTYPEPTRTYPE) + monopipe.writeQword(ptrtype) + local val = monopipe.readQword() + monopipe.unlock() + return val +end function mono_field_getClass(field) --if debug_canBreak() then return nil end @@ -1601,6 +1632,15 @@ function mono_type_get_type(monotype) return retv end +function mono_type_is_byref(monotype) + monopipe.lock() + monopipe.writeByte(MONOCMD_TYPEISBYREF) + monopipe.writeQword(monotype) + local val = monopipe.readByte() + monopipe.unlock() + return val == 1 +end + function mono_classtype_get_reflectiontype(monotype) if not monotype or monotype==0 then return end monopipe.lock() @@ -2641,6 +2681,7 @@ function mono_method_get_parameters(method) --types for i=1, paramcount do + result.parameters[i].monotype=monopipe.readQword(); result.parameters[i].type=monopipe.readDword(); end @@ -4528,22 +4569,15 @@ mono_StringStruct=nil function monoform_exportStructInternal(s, caddr, recursive, static, structmap, makeglobal) --print("monoform_exportStructInternal") - if (monopipe==nil) or (caddr==0) or (caddr==nil) then return nil end - - -- print("b") - local className = mono_class_getFullName(caddr) --print('Populating '..className) -- handle Array as separate case - if string.sub(className,-2)=='[]' then local elemtype = mono_class_getArrayElementClass(caddr) return monoform_exportArrayStructInternal(s, caddr, elemtype, recursive, structmap, makeglobal, true) end - - local hasStatic = false structure_beginUpdate(s) From 2907948d8f8d253068e99b9342ee029cf0eb4eb9 Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Fri, 3 Nov 2023 06:53:44 +0500 Subject: [PATCH 06/10] Structure dissection for c-pointers Structure dissection for values stored as c-pointer in a class can not be achieved. The max level (number of child structures) for this is set to 2. You can change it by changing the value of "monoSettings.Value["MaxPointerChildStructs"]" or set it to "0" to completely remove it. --- Cheat Engine/bin/autorun/monoscript.lua | 50 +++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index ce5cc55b..9eb70bdb 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -4567,17 +4567,57 @@ end mono_StringStruct=nil -function monoform_exportStructInternal(s, caddr, recursive, static, structmap, makeglobal) +function monofrom_addPointerStructure(parentstructure, thiselement, field, recursive, static, structmap, loopnumber) + --This function will add sub-strutures to the fields that are c Pointers + --to disable, set " monoSettings.Value["MaxPointerChildStructs"] = "" " + assert(field.monotype==MONO_TYPE_PTR, 'Error: WAIT! How did I end up here!?') + local kls = mono_field_getClass(field.field) + if not kls or not readPointer(kls) then return end + kls = mono_class_get_type(kls) + kls = mono_type_get_ptr_type(kls) + if not kls or not readPointer(kls) then return end + local pat = mono_type_get_type(kls) + kls = mono_type_get_class(kls) + kls = pat==MONO_TYPE_GENERICINST and mono_class_getParent(kls) or kls + if not kls or not readPointer(kls) then return end + local subflds = mono_class_enumFields(kls,1) + if #subflds==0 then return end + local subofst; -- the offset of very first non-static, non-const field needs to be subtracted from similar fields + for k,v in ipairs(subflds) do + if not v.isStatic and not v.isConst then + subofst = subofst or v.offset + break + end + end + local structure = createStructure("") + monoform_exportStructInternal(structure, kls, recursive, static, structmap, nil, subofst, loopnumber-1) + print(structure.Count, field.name) + if structure.Count > 0 then + thiselement.ChildStruct = structure + thiselement.ChildStructStart = 0 + else + structure.destroy() + end + --print(#subflds, subflds[1].offset,mono_class_getFullName(kls), mono_class_getFullName(mono_field_getClass(field.field))) +end + +function monoform_exportStructInternal(s, caddr, recursive, static, structmap, makeglobal, minusoffset, loopnumber) --print("monoform_exportStructInternal") + if not(tonumber(monoSettings.Value["MaxPointerChildStructs"])) then + monoSettings.Value["MaxPointerChildStructs"] = "2" + end + if (monopipe==nil) or (caddr==0) or (caddr==nil) then return nil end + local className = mono_class_getFullName(caddr) --print('Populating '..className) - -- handle Array as separate case if string.sub(className,-2)=='[]' then local elemtype = mono_class_getArrayElementClass(caddr) return monoform_exportArrayStructInternal(s, caddr, elemtype, recursive, structmap, makeglobal, true) end + minusoffset = minusoffset or 0 + local hasStatic = false structure_beginUpdate(s) @@ -4596,14 +4636,16 @@ function monoform_exportStructInternal(s, caddr, recursive, static, structmap, m if fieldname~=nil then e.Name=fieldname end - e.Offset=fields[i].offset + e.Offset=fields[i].offset - minusoffset e.Vartype=mono_class_isEnum(mono_field_getClass( fields[i].field )) and vtDword or monoTypeToVarType(ft) --print(string.format(" Field: %d: %d: %d: %s", e.Offset, e.Vartype, ft, fieldname)) + loopnumber = loopnumber or tonumber(monoSettings.Value["MaxPointerChildStructs"]) if ft==MONO_TYPE_STRING or ft==MONO_TYPE_CHAR then --e.Vartype=vtUnicodeString e.Bytesize = 999 - + elseif ft == MONO_TYPE_PTR and loopnumber > 0 then + monofrom_addPointerStructure(s, e, fields[i], recursive, static, structmap, loopnumber) --[[ e.Vartype=vtPointer --print(string.format(" Field: %d: %d: %d: %s", e.Offset, e.Vartype, ft, fieldname)) From da291646cc73d220d4f99474e119f0f4f2b6506e Mon Sep 17 00:00:00 2001 From: PeaceBeUponYou Date: Fri, 17 Nov 2023 08:00:10 +0500 Subject: [PATCH 07/10] Expanded structs in arrays for structure dissection --- Cheat Engine/bin/autorun/monoscript.lua | 78 +++++++++++++++++-------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/Cheat Engine/bin/autorun/monoscript.lua b/Cheat Engine/bin/autorun/monoscript.lua index 9eb70bdb..d13fb1b0 100755 --- a/Cheat Engine/bin/autorun/monoscript.lua +++ b/Cheat Engine/bin/autorun/monoscript.lua @@ -3453,9 +3453,6 @@ function monoform_createInstanceOfClass(sender) end end - - - --[[ function monoform_miCreateObject(sender) if (monoForm.TV.Selected~=nil) then @@ -4718,6 +4715,50 @@ function monoform_exportArrayStruct(arraytype, elemtype, typename, recursive, st return monoform_exportArrayStructInternal(acs, arraytype, elemtype, recursive, structmap, makeglobal, reload) end +function mono_structfields_getStartOffset(fields) + --this function get the first non-static, non-const field and gets its offset to subtract from all the offsets of fields + --this is done since structs as a memeber element in a class are not pointers, rather simple values! + for k,v in pairs(fields) do + if not(v.isConst) and not(v.isStatic) then + return v.offset + end + end +end + +function monoform_addCSStructElements(structure, klass, parentstructname, offsetInStructure, prename, postname, preklassName, postClassName) + parentstructname = type(parentstructname)=='string' and #parentstructname>0 and parentstructname..'.' or '' + offsetInStructure = tonumber(offsetInStructure) or 0 --for arrays of the same struct + prename = prename or "" --the text to add before the name of the element + postname = postname or "" --text to add after the name of the element + preklassName = preklassName or "" --the text to add before the klassname (in paranthesis) of the element + postklassName = postklassName or "" --text to add after the klassname (in paranthesis) of the element + + local subfield = mono_class_enumFields(klass) + local suboffset = mono_structfields_getStartOffset(subfield) + if not suboffset then + suboffset = targetIs64Bit() and 0x10 or 0x8 + end + for k,v in pairs(subfield) do + if not(v.isConst) and not(v.isStatic) then + local fieldClass = mono_field_getClass( v.field ) + local klsname = mono_class_getName(fieldClass) + local eloffset = offsetInStructure+v.offset-suboffset + if mono_class_isStruct(fieldClass) then + monoform_addCSStructElements(structure, fieldClass, v.name, eloffset, prename, postname, klsname..'.') + else + local nm = v.name..'('..preklassName..klsname..postklassName..')' + local ce=structure.addElement() + ce.Name=string.format("%s%s%s",prename,parentstructname..nm,postname) + ce.Offset=eloffset + ce.Vartype= mono_class_isEnum(fieldClass) and vtDword or monoTypeToVarType( v.monotype ) --vtPointer + if ce.Vartype == vtDword then + ce.DisplayMethod = 'dtSignedInteger' + end + end + end + end +end + function monoform_exportArrayStructInternal(acs, arraytype, elemtype, recursive, structmap, makeglobal, reload) --print("monoform_exportArrayStructInternal") --print(fu(arraytype),mono_class_getFullName(arraytype)) @@ -4737,35 +4778,22 @@ function monoform_exportArrayStructInternal(acs, arraytype, elemtype, recursive, local j local psize = arraytype and mono_array_element_size(arraytype) or nil - psize = psize and psize or (targetIs64Bit() and 8 or 4) + psize = psize and psize or (targetIs64Bit() and 8 or 4) - local start - if targetIs64Bit() then - start=0x20 - else - start=0x10 - end + local start + if targetIs64Bit() then + start=0x20 + else + start=0x10 + end local elementkls = mono_class_getArrayElementClass(arraytype) local elementmonotype = mono_type_get_type(mono_class_get_type(elementkls)) local isStruct = mono_class_isStruct(elementkls)--mono_class_isValueType(elementkls) and not(mono_class_IsPrimitive(elementkls)) and not(mono_class_isEnum(elementkls)) --print(fu(elementkls),mono_class_getFullName(elementkls),fu(elementmonotype)) if isStruct then --print("yep, a struct") - local subfield = mono_class_enumFields(elementkls) - local suboffset = subfield[1].offset == 0x10 and 0x10 or 0 - for k,v in pairs(subfield) do - if not(v.isConst) and not(v.isStatic) then - local nm = v.name..'('..mono_class_getName(mono_field_getClass(v.field))..')' - for j=0, 9 do -- Arbitrarily add 10 elements - ce=acs.addElement() - ce.Name=string.format("[%d]%s",j,nm) - ce.Offset=j*psize+start+v.offset-suboffset - ce.Vartype= mono_class_isEnum(mono_field_getClass( v.field )) and vtDword or monoTypeToVarType( v.monotype ) --vtPointer - if ce.Vartype == vtDword then - ce.DisplayMethod = 'dtSignedInteger' - end - end - end + for j=0, 9 do -- Arbitrarily add 10 elements + monoform_addCSStructElements(acs, elementkls, "", j*psize+start, '['..j..']', "") end else for j=0, 9 do -- Arbitrarily add 10 elements From ea32e4363d83a829db69911d7cd53ea7fdf23415 Mon Sep 17 00:00:00 2001 From: Dark Byte Date: Thu, 14 Dec 2023 12:53:34 +0100 Subject: [PATCH 08/10] Update .gitignore the cheat engine lpi contains compile parameter changes which sometimes do need to be commited --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index b7365d5f..67efa300 100644 --- a/.gitignore +++ b/.gitignore @@ -52,8 +52,6 @@ Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoData.941726A9.t *.tlog *.lpi *.vcxproj -Cheat Engine/cheatengine.lpi -Cheat Engine/cheatengine.lpi *.vsidx *.lpi Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj From a5d1c573aaafbfb3dbe7cc10c897a7e8d99dd88e Mon Sep 17 00:00:00 2001 From: Dark Byte Date: Thu, 14 Dec 2023 12:54:28 +0100 Subject: [PATCH 09/10] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 67efa300..36a7c85f 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,6 @@ Cheat Engine/MonoDataCollector/.vs/MonoDataCollector/FileContentIndex/62bb0928-9 Cheat Engine/cheatengine.lpi Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoData.941726A9.tlog/Cl.items.tlog *.tlog -*.lpi *.vcxproj *.vsidx *.lpi From c63b8d5dc75021a2286e3bdbb1fd6c65d2fc0c46 Mon Sep 17 00:00:00 2001 From: Dark Byte Date: Thu, 14 Dec 2023 12:56:22 +0100 Subject: [PATCH 10/10] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 36a7c85f..a6df2682 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,6 @@ Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoDataCollector64 Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj Cheat Engine/MonoDataCollector/.vs/MonoDataCollector/v17/ipch/AutoPCH/3d2a0f62d32e0fb5/CMEMSTREAM.ipch Cheat Engine/MonoDataCollector/.vs/MonoDataCollector/FileContentIndex/62bb0928-9760-4e2d-9c74-b56a96c8718a.vsidx -Cheat Engine/cheatengine.lpi Cheat Engine/MonoDataCollector/MonoDataCollector/x64/Release/MonoData.941726A9.tlog/Cl.items.tlog *.tlog *.vcxproj