How to get raw memory pointer to a managed class?

How to find a raw pointer to a managed class in C # and hopefully its raw size in memory? Obviously, this is not allowed by the CLR - more precisely, it is strictly forbidden, since the unmanaged representation of managed classes should never work with stability and safe reasons - that's why I'm looking for a hack. I'm not looking for serialization - I really need a dump of a managed class, as it is presented in raw memory.

More precisely, I am looking for something like the getObjectPtr function in the following example:

 IntPtr getObjectPtr(Object managedClass) {...} void main() { var test=new TestClass(); IntPtr* ptr_to_test=getObjectPtr(test); Console.WriteLine(ptr_to_test.ToString()); } 

Thanks in advance!

EDIT: I finally found the solution myself, and returning to post it as an answer, I was completely surprised by the number of answers so quickly published ... Thank you all! It was very fast and completely unexpected.

The closest to my solution was @thehennyy alone, but I didn’t post it with @Chino offered much better (sorry I was wrong to be wrong at first, I just forgot to dereference the pointer again). It does not require the code to be unsafe and endure the GC a bit:

 class Program { // Here is the function in case anyone needs it. // Note, though, it does not preserve the handle while you work with // pointer, so it is less reliable than the code in Main(): static IntPtr getPointerToObject(Object unmanagedObject) { GCHandle gcHandle = GCHandle.Alloc(unmanagedObject, GCHandleType.WeakTrackResurrection); IntPtr thePointer = Marshal.ReadIntPtr(GCHandle.ToIntPtr(gcHandle)); gcHandle.Free(); return thePointer; } class TestClass { uint a = 0xDEADBEEF; } static void Main(string[] args) { byte[] cls = new byte[16]; var test = new TestClass(); GCHandle gcHandle = GCHandle.Alloc(test, GCHandleType.WeakTrackResurrection); IntPtr thePointer = Marshal.ReadIntPtr(GCHandle.ToIntPtr(gcHandle)); Marshal.Copy(thePointer, cls, 0, 16); //Dump first 16 bytes... Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(thePointer.ToInt32()))); Console.WriteLine(BitConverter.ToString(cls)); Console.ReadLine(); gcHandle.Free(); } } /* Example output (yours should be different): 40-23-CA-02 4C-38-04-01-EF-BE-AD-DE-00-00-00-80-B4-21-50-73 That field value is "EF-BE-AD-DE", 0xDEADBEEF as it is stored in memory. Yay, we found it! */ 

Hovewer, now I'm a little clueless. According to this article, the first 2 addresses in the class must be pointers to the structure of SyncBlock and RTTI, so the first address of the field should be shifted 2 words [8 bytes in 32-bit systems, 16 bytes in 64-bit systems] from the very beginning. Mine is 64-bit; however, as you can see in the output, it is obvious that the first offset of the source field from the address of the object is only 4 bytes, which makes no sense.

I asked this as a separate question . Perhaps I should ask this as a separate question, but it is possible that there is an error in my solution.

+4
source share
2 answers

Hey, is that what you want ?:

 GCHandle gcHandle = GCHandle.Alloc(yourObject,GCHandleType.WeakTrackResurrection); IntPtr thePointer = GCHandle.ToIntPtr(gcHandle); 
+3
source

You can write a small IL function that leaks the addresses of objects.

 var o = new object(); var d = new DynamicMethod("GetPtr", typeof(IntPtr), new Type[] {typeof(object)}, Assembly.GetExecutingAssembly().ManifestModule); var il = d.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); var address = (IntPtr)d.Invoke(null, new object[] {o}); Console.WriteLine(address); 

Source: IllidanS4 / SharpUtils /UnsafeTools.cs

+2
source

Source: https://habr.com/ru/post/1236347/


All Articles