Merge pull request #2681 from PeaceBeUponYou/master

Mono: Data Structure Dissect Fix and Debug Features
This commit is contained in:
Dark Byte 2023-12-14 12:58:10 +01:00 committed by GitHub
commit 9a3ade0443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 480 additions and 164 deletions

15
.gitignore vendored
View File

@ -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

View File

@ -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;

View File

@ -21,7 +21,6 @@
#endif //linux
#include <signal.h>
#include <sys/types.h>
@ -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<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::string dest = convert.to_bytes((char16_t*)ptr);
WriteString(dest.c_str());
//todo: unsure about this
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, 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;

View File

@ -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);

View File

@ -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