Skip to content

Instantly share code, notes, and snippets.

@sos-dll
Last active November 13, 2020 21:30
Show Gist options
  • Save sos-dll/8b3830f368337832e9f9a554cfa7cfea to your computer and use it in GitHub Desktop.
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.)
// 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;
}
*/
}
@sos-dll
Copy link
Author

sos-dll commented Oct 8, 2020

Example usage:
image
The reference of helloWorld string is reinterpreted as StringProxy, followed by modifying the length to 40 via proxy.
Result: helloWorld is made read arbitrary data that is on the heap. In other words, the string became mutable.


image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment