Created
June 12, 2021 16:06
-
-
Save TheLeftExit/8a630f4ebae4a37ae213ca04b270a238 to your computer and use it in GitHub Desktop.
Standalone RTTI in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Text; | |
using System.Diagnostics; | |
using System.Runtime.InteropServices; | |
namespace TheLeftExit.RTTI | |
{ | |
static class ProcessManipulations | |
{ | |
[DllImport("kernel32.dll")] | |
private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); | |
public static IntPtr CreateHandle(this Process process) => | |
OpenProcess(0x0010, false, process.Id); | |
[DllImport("kernel32.dll")] | |
private static extern bool ReadProcessMemory(int hProcess, long lpBaseAddress, byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead); | |
public static bool ReadInt32(this IntPtr handle, long address, out int result) | |
{ | |
byte[] buffer = new byte[sizeof(int)]; | |
if (!ReadProcessMemory((int)handle, address, buffer, buffer.Length, 0)) | |
{ | |
result = 0; | |
return false; | |
} | |
result = BitConverter.ToInt32(buffer, 0); | |
return true; | |
} | |
public static bool ReadInt64(this IntPtr handle, long address, out long result) | |
{ | |
byte[] buffer = new byte[sizeof(long)]; | |
if (!ReadProcessMemory((int)handle, address, buffer, buffer.Length, 0)) | |
{ | |
result = 0; | |
return false; | |
} | |
result = BitConverter.ToInt64(buffer, 0); | |
return true; | |
} | |
public static bool ReadString(this IntPtr handle, long address, int maxLength, out string result) | |
{ | |
byte[] buffer = new byte[maxLength]; | |
if (!ReadProcessMemory((int)handle, address, buffer, buffer.Length, 0)) | |
{ | |
result = null; | |
return false; | |
} | |
result = Encoding.UTF8.GetString(buffer); | |
return true; | |
} | |
public static bool ReadFloat(this IntPtr handle, long address, out float result) | |
{ | |
byte[] buffer = new byte[sizeof(float)]; | |
if (!ReadProcessMemory((int)handle, address, buffer, buffer.Length, 0)) | |
{ | |
result = 0; | |
return false; | |
} | |
result = BitConverter.ToSingle(buffer, 0); | |
return true; | |
} | |
public static bool ReadDouble(this IntPtr handle, long address, out double result) | |
{ | |
byte[] buffer = new byte[sizeof(double)]; | |
if (!ReadProcessMemory((int)handle, address, buffer, buffer.Length, 0)) | |
{ | |
result = 0; | |
return false; | |
} | |
result = BitConverter.ToDouble(buffer, 0); | |
return true; | |
} | |
public static bool ReadBytes(this IntPtr handle, long address, int count, byte[] result) => | |
ReadProcessMemory((int)handle, address, result, count, 0); | |
} | |
static class RTTI | |
{ | |
[DllImport("dbghelp.dll", CharSet = CharSet.Unicode)] | |
private static extern int UnDecorateSymbolName(string DecoratedName, StringBuilder UnDecoratedName, int UndecoratedLength, int Flags); | |
public static string[] GetRTTIClassNames(this IntPtr handle, long address) | |
{ | |
handle.ReadInt64(address, out long struct_addr); | |
handle.ReadInt64(struct_addr - IntPtr.Size, out long object_locator_ptr); | |
handle.ReadInt64(object_locator_ptr + 0x14, out long base_offset); | |
long base_address = object_locator_ptr - base_offset; | |
handle.ReadInt32(object_locator_ptr + 0x10, out int class_hierarchy_descriptor_offset); | |
long class_hierarchy_descriptor_ptr = base_address + class_hierarchy_descriptor_offset; | |
handle.ReadInt32(class_hierarchy_descriptor_ptr + 0x08, out int base_class_count); | |
handle.ReadInt32(class_hierarchy_descriptor_ptr + 0x0C, out int base_class_array_offset); | |
long base_class_array_ptr = base_address + base_class_array_offset; | |
string[] names = new string[base_class_count]; | |
for (int i = 0; i < base_class_count; i++) | |
{ | |
handle.ReadInt32(base_class_array_ptr + 4 * i, out int base_class_descriptor_offset); | |
long base_class_descriptor_ptr = base_address + base_class_descriptor_offset; | |
handle.ReadInt32(base_class_descriptor_ptr, out int type_descriptor_offset); | |
long type_descriptor_ptr = base_address + type_descriptor_offset; | |
handle.ReadString(type_descriptor_ptr + 0x14, 32, out names[i]); | |
names[i] = names[i].Substring(0, names[i].IndexOf('\0')); // why do i have to | |
if (names[i].EndsWith("@@")) | |
{ | |
var sb = new StringBuilder(255); | |
UnDecorateSymbolName("?" + names[i], sb, sb.Capacity, 0x1000); | |
names[i] = sb.ToString(); | |
} | |
} | |
return names; | |
} | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Process gt = Process.GetProcessesByName("Growtopia").Single(); | |
IntPtr gthandle = gt.CreateHandle(); | |
gthandle.ReadInt64((long)gt.MainModule.BaseAddress + 0x7667F8, out long addr); | |
gthandle.ReadInt64(addr + 0xAB0, out addr); | |
gthandle.ReadInt64(addr + 0x198, out addr); | |
var names = gthandle.GetRTTIClassNames(addr); | |
; // breakpoint | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment