Casting in .NET via object mutation
In this post, we will see how to make the following code fail:
object it = new SomeStruct { Item = 1 }; Floatsy(it); Console.WriteLine(((SomeStruct)it).Item);
At runtime, it will throw an InvalidCastException!
Here’s how. In .NET, each object has also associated with it a value which determines the type of the object. In memory, this is stored before the object’s data, like so (I got this information from the MSDN article Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects):

Now, if we can write to that, we can set the type of the object to whatever we want!
There’s one small problem — in .NET we can’t take the address of a managed object (which we need in order to write to the object in memory). There are various reasons for this, one of them being that the garbage collector likes to be able to move objects around. Being able to take arbitrary pointers of objects would mean that the pointers could become invalidated.
What we can do is to pin a struct, which allows us to retrieve the address of it (this facility exists so that users can pass pinned managed structs into unmanaged code as pointers). Here’s how to pin a struct:
var handle = GCHandle.Alloc(o, GCHandleType.Pinned); var addr = handle.AddrOfPinnedObject();
We can then write to the type handle like so (both the sync block and type handle are 32 bits):
*(((int*)addr)-1) = someValue;
Another problem is that all of this is only true for values on the heap. As far as I can tell, the static type of the variable is what .NET uses to identify values on the stack. So in order for this to work, we must use a boxed copy of a struct.
Finally, here’s some demo code, showing runtime changing of types for both a primitive and custom struct:
using System; using System.Runtime.InteropServices; unsafe class Program { struct SomeStruct { public int Item; } public static void Main() { object notAFloat = 1; object me = new SomeStruct {Item = 1}; Console.WriteLine("{0} ({1})", notAFloat, notAFloat.GetType()); Floatify(notAFloat); Console.WriteLine("{0} ({1})", notAFloat, notAFloat.GetType()); Console.WriteLine(); Console.WriteLine(me); Floatify(me); Console.WriteLine(me); } static void Floatify<T>(T o) { var handle = GCHandle.Alloc(o, GCHandleType.Pinned); var addr = handle.AddrOfPinnedObject(); object f = (float)1.0; var handle2 = GCHandle.Alloc(f, GCHandleType.Pinned); var addr2 = handle2.AddrOfPinnedObject(); // copy type handle of a float to the object *(((int*)addr)-1) = *(((int*)addr2)-1); handle2.Free(); handle.Free(); } }
The output is:
1 (System.Int32) 1.401298E-45 (System.Single) Program+SomeStruct 1.401298E-45
