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.