diff --git a/.gitignore b/.gitignore index fee7431b..b5d64f71 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,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/MonoDataCollector/MonoDataCollector/x64/Release/MonoData.941726A9.tlog/Cl.items.tlog +*.tlog +*.vcxproj +*.vsidx +*.lpi +Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.vcxproj diff --git a/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp b/Cheat Engine/MonoDataCollector/MonoDataCollector/MonoDataCollector.cpp index b144c321..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,20 +94,35 @@ 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(); + OutputDebugString("Destroying PipeServer\n"); DataCollectorThread=0; delete pw; +#ifdef CUSTOM_DEBUG + if (console) + fclose(console); +#if DEBUG_CONSOLE + FreeConsole(); +#endif +#endif + if (SuicideThread) TerminateThread(SuicideThread, 0); 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..04a8e7c0 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"); @@ -505,11 +514,14 @@ 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"); + 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"); @@ -542,13 +554,15 @@ 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"); 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"); @@ -558,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"); @@ -666,10 +684,12 @@ 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"); 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"); @@ -709,6 +729,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"); @@ -720,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"); @@ -772,7 +795,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); } @@ -1522,6 +1545,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(); @@ -1588,19 +1625,42 @@ 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); } +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(); @@ -1647,6 +1707,7 @@ void CPipeServer::GetMethodParameters() { void* returntype = il2cpp_method_get_return_type(method); + WriteQword((UINT64)returntype); if (returntype) WriteDword(mono_type_get_type(returntype)); else @@ -1677,35 +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); - 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); @@ -1943,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; @@ -1957,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(); @@ -2385,102 +2444,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 (...) { @@ -2664,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(); @@ -2928,6 +3017,10 @@ void CPipeServer::Start(void) case MONOCMD_GETMETHODNAME: GetMethodName(); break; + + case MONOCMD_GETMETHODFULLNAME: + GetMethodFullName(); + break; case MONOCMD_GETMETHODCLASS: GetMethodClass(); @@ -2946,6 +3039,11 @@ void CPipeServer::Start(void) break; case MONOCMD_TERMINATE: + if (pipehandle != INVALID_HANDLE_VALUE) + { + DisconnectNamedPipe(pipehandle); + CloseHandle(pipehandle); + } return; case MONOCMD_DISASSEMBLE: @@ -2972,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: @@ -3012,6 +3114,10 @@ void CPipeServer::Start(void) IsSubClassOf(); break; + case MONOCMD_TYPEISBYREF: + IsTypeByReference(); + break; + case MONOCMD_ISIL2CPP: IsIL2CPP(); break; @@ -3084,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 2c98158a..fd171fe1 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 @@ -42,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 @@ -78,6 +83,11 @@ #define MONOCMD_MONOOBJECTUNBOX 60 #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; @@ -149,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); @@ -166,6 +179,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); @@ -328,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; @@ -337,9 +352,12 @@ 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; + 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; @@ -451,6 +469,7 @@ private: void FindClass(); void FindMethod(); void GetMethodName(); + void GetMethodFullName(); void GetMethodClass(); void GetKlassName(); void GetClassNamespace(); @@ -470,7 +489,8 @@ private: void UnBoxMonoObject(); void GetVTableFromClass(); void GetStaticFieldAddressFromClass(); - void GetTypeClass(); + void GetFieldClass(); + void GetFieldType(); void GetArrayElementClass(); void FindMethodByDesc(); void InvokeMethod(); @@ -483,6 +503,7 @@ private: void IsEnumClass(); void IsValueTypeClass(); void IsSubClassOf(); + void IsTypeByReference(); void GetArrayElementSize(); void NewCSArray(); void IsIL2CPP(); @@ -492,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 8e942db1..9ea524b1 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 @@ -89,6 +89,11 @@ MONOCMD_GETREFLECTIONMETHODOFMONOMETHOD = 59 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 @@ -144,6 +149,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 +174,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 +1423,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 @@ -1548,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 @@ -1593,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() @@ -2112,7 +2160,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 @@ -2573,6 +2621,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 @@ -2622,10 +2681,12 @@ 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 --result + result.returnmonotype = monopipe.readQword() result.returntype=monopipe.readDword() monopipe.unlock() @@ -3097,11 +3158,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() @@ -3387,9 +3455,6 @@ function monoform_createInstanceOfClass(sender) end end - - - --[[ function monoform_miCreateObject(sender) if (monoForm.TV.Selected~=nil) then @@ -3995,7 +4060,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 ")) @@ -4493,23 +4566,56 @@ 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 - -- 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 - + minusoffset = minusoffset or 0 local hasStatic = false structure_beginUpdate(s) @@ -4529,14 +4635,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)) @@ -4609,6 +4717,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)) @@ -4628,35 +4780,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_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") - 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= 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