Last active
November 13, 2020 21:30
-
-
Save sos-dll/8b3830f368337832e9f9a554cfa7cfea to your computer and use it in GitHub Desktop.
✨ A brand new way for casting values/objects in C# by (ab)using .NET internals. Enjoy. (Tested on .NET 5.)
This file contains hidden or 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
// Licensed under WTFPL. | |
using System; | |
namespace sos.dll | |
{ | |
/* ☢ (̵A̸B̴)̸U̷S̶I̸N̸G̶ ̶ ̶.̸N̶E̴T̸ ̶ ̵I̸N̵T̸E̷R̷N̷A̴L̷S̸ ☢ */ | |
public static unsafe partial class TypeHacks | |
{ | |
/// <summary> | |
/// Changes the type on <seealso cref="TypedReference"/> for the given object/value. | |
/// </summary> | |
/// <typeparam name="TFrom">A type to cast from.</typeparam> | |
/// <typeparam name="TTo">A type to cast to.</typeparam> | |
/// <param name="this">Specify an object/value to be casted.</param> | |
/// <param name="auxilary">(Optional.)</param> | |
/// <returns>A reference to <paramref name="this"/> reinterpreted as a reference of <typeparamref name="TTo"/> type.</returns> | |
public static TTo Cast<TFrom, TTo>(this TFrom @this, TTo auxilary = default) | |
{ | |
// 📕 𝗧𝗵𝗲 ⭐ 𝗟𝗮𝘄 ⭐ | |
// ⮞ Any form of casting either via operator(s), or union trick, or API usage ― are s͟t͟r͟i͟c͟t͟l͟y͟ p͟r͟o͟h͟i͟b͟i͟t͟e͟d͟. | |
// ⮞ Only pointer arithmetic operations are a͟l͟l͟o͟w͟e͟d͟. | |
#region 🔥 🐉 Here be Dragons 🔥 🐲 | |
TypedReference valueTR = __makeref(@this), auxTR = __makeref(auxilary); | |
*(IntPtr*)((byte*)&valueTR + /*_type offset:*/IntPtr.Size) = *(IntPtr*)((byte*)&auxTR + IntPtr.Size); | |
// Alternative approach, avoiding hardcoded _type offset: | |
//var typeOffset = (int)Marshal.OffsetOf<_TypedReference>(nameof(_TypedReference._type)); | |
//*(IntPtr*)((byte*)&valueTR + typeOffset) = *(IntPtr*)((byte*)&auxTR + typeOffset); | |
// Just another alternative, if Unsafe (API) were allowed: | |
//ref var valueRef = ref Unsafe.AsRef<_TypedReference>((byte*)&valueTR); | |
//ref var auxRef = ref Unsafe.AsRef<_TypedReference>((byte*)&auxTR); | |
//valueRef._type = auxRef._type; | |
// Yet another alternative, if Unsafe (API) were allowed: | |
//return Unsafe.As<TFrom, TTo>(ref @this); | |
return __refvalue(valueTR, TTo); | |
#endregion | |
} | |
} | |
/* | |
public struct _ByReference<T> | |
{ | |
public IntPtr _value; | |
} | |
public struct _TypedReference | |
{ | |
public _ByReference<byte> _value; | |
public IntPtr _type; | |
} | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage:

The reference of
helloWorld
string is reinterpreted asStringProxy
, followed by modifying the length to40
via proxy.Result:
helloWorld
is made read arbitrary data that is on the heap. In other words, the string became mutable.