Skip to content

Instantly share code, notes, and snippets.

@sunnyneo
Forked from susMdT/managedhook.cs
Created January 25, 2023 13:51
Show Gist options
  • Save sunnyneo/809d00f795f5c7e40b67e9c2556c5e4c to your computer and use it in GitHub Desktop.
Save sunnyneo/809d00f795f5c7e40b67e9c2556c5e4c to your computer and use it in GitHub Desktop.

Revisions

  1. @susMdT susMdT revised this gist Jan 24, 2023. 1 changed file with 142 additions and 117 deletions.
    259 changes: 142 additions & 117 deletions managedhook.cs
    Original file line number Diff line number Diff line change
    @@ -1,129 +1,154 @@
    using System;
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    namespace ShittyHook
    {
    internal class Program
    {
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate uint NtAllocateVirtualMemory(
    IntPtr ProcessHandle,
    ref IntPtr BaseAddress,
    IntPtr ZeroBits,
    ref IntPtr RegionSize,
    UInt32 AllocationType,
    UInt32 Protect
    );
    [DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    public static void Main()
    internal class Program
    {
    IntPtr ntdll = default;
    foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
    {
    if (mod.ModuleName.ToLower() == "ntdll.dll")
    ntdll = mod.BaseAddress;
    }
    IntPtr pOGAlloc = GetProcAddress(ntdll, "NtAllocateVirtualMemory");

    // Why do i have to jit the hook now??
    MethodInfo method = typeof(Program).GetMethod(nameof(NtAllocateVirtualMemoryHook), BindingFlags.Static | BindingFlags.Public);
    RuntimeHelpers.PrepareMethod(method.MethodHandle);

    using (FxHook hook = new FxHook(pOGAlloc, (NtAllocateVirtualMemory)NtAllocateVirtualMemoryHook))
    {
    hook.Install();

    // Calling the ntallocate from ntdll, which is hooked
    object[] allocArgs = { (IntPtr)(-1), IntPtr.Zero, IntPtr.Zero, (IntPtr)2048, (UInt32)0x3000, (UInt32)0x420 };
    uint ntstatus = (uint)Marshal.GetDelegateForFunctionPointer<NtAllocateVirtualMemory>(pOGAlloc).DynamicInvoke(allocArgs);
    Console.WriteLine("Ntstatus was 0x{0:X}", (long)ntstatus);
    Console.WriteLine("Allocated to 0x{0:X}", (long)(IntPtr)allocArgs[1]);

    Console.ReadKey();
    }
    static int hooks = 0;
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate uint NtAllocateVirtualMemory(
    IntPtr ProcessHandle,
    ref IntPtr BaseAddress,
    IntPtr ZeroBits,
    ref IntPtr RegionSize,
    UInt32 AllocationType,
    UInt32 Protect
    );
    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    public static void Main()
    {
    IntPtr ntdll = default;
    foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
    {
    if (mod.ModuleName.ToLower() == "ntdll.dll")
    ntdll = mod.BaseAddress;
    }
    IntPtr pOGAlloc = GetProcAddress(ntdll, "NtAllocateVirtualMemory");

    // Why do i have to jit the hook now??
    MethodInfo method = typeof(Program).GetMethod(nameof(NtAllocateVirtualMemoryHook), BindingFlags.Static | BindingFlags.Public);
    RuntimeHelpers.PrepareMethod(method.MethodHandle);

    Console.WriteLine("Our hooked NtAllocateVirtualMemory is at 0x{0:X}", (long)method.MethodHandle.GetFunctionPointer());

    using (FxHook hook = new FxHook(pOGAlloc, (NtAllocateVirtualMemory)NtAllocateVirtualMemoryHook))
    {
    hook.Install();

    // Calling the ntallocate from ntdll, which is hooked
    object[] allocArgs = { (IntPtr)(-1), IntPtr.Zero, IntPtr.Zero, (IntPtr)420420, (UInt32)0x3000, (UInt32)0x420 };
    uint ntstatus = (uint)Marshal.GetDelegateForFunctionPointer<NtAllocateVirtualMemory>(pOGAlloc).DynamicInvoke(allocArgs);

    Console.ReadKey();

    Console.WriteLine("Going to do a managed allocation");
    IntPtr m = Marshal.AllocHGlobal(12);
    Console.WriteLine("Managed allocation to 0x{0:X}", (long)m);
    Console.ReadKey();
    }
    }
    public static uint NtAllocateVirtualMemoryHook(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, UInt32 AllocationType, UInt32 Protect)
    {
    if (hooks != 0)
    {
    Console.WriteLine($"This is hooked call number {hooks+1}");
    }
    if (Protect == 0x420)
    {
    Console.WriteLine("============DETECTED 0x420=============");
    Console.WriteLine("Why did you pass 0x420 as the protection? Im returned code 0x6969");
    Console.WriteLine("=======================================");
    return (uint)0x6969;
    }
    Marshal.Copy(FxHook.src, 0, FxHook.addr, FxHook.nBytes); // temporarily remove hook
    // Console.WriteLine() apparently will make a stack overflow the first time this hook is called for some reason
    Console.WriteLine("==========RECEIVED NTALLOCATE==========");
    Console.WriteLine("Handle 0x{0:X}", (long)ProcessHandle);
    Console.WriteLine("BaseAddress 0x{0:X}", (long)BaseAddress);
    Console.WriteLine("RegionSize 0x{0:X}", (long)RegionSize);
    Console.WriteLine("AllocationType 0x{0:X}", (long)AllocationType);
    Console.WriteLine("Protect 0x{0:X}", (long)Protect);
    Console.WriteLine("=======================================");
    object[] args = { ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect };
    uint retVal = (uint)Marshal.GetDelegateForFunctionPointer(FxHook.addr, typeof(NtAllocateVirtualMemory)).DynamicInvoke(args);
    Marshal.Copy(FxHook.dst, 0, FxHook.addr, FxHook.nBytes); // restore hook
    BaseAddress = (IntPtr)args[1];
    RegionSize = (IntPtr)args[3];
    hooks += 1;
    return retVal;
    }
    }
    public static uint NtAllocateVirtualMemoryHook(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, UInt32 AllocationType, UInt32 Protect)
    public class FxHook : IDisposable
    {
    if (Protect == 0x420)

    public const int nBytes = 13;
    // movabs r11, address
    // jmp r11

    public static IntPtr addr; // the function we are hooking
    Protection old;
    public static byte[] src = new byte[13]; //source bytes
    public static byte[] dst = new byte[13]; //trampoline

    public FxHook(IntPtr source, IntPtr destination)
    {
    Console.WriteLine("Our delegate is at 0x{0:X}", (long)destination);
    VirtualProtect(source, nBytes, Protection.PAGE_EXECUTE_READWRITE, out old);
    Marshal.Copy(source, src, 0, nBytes); //copy the original 13 we will patch
    dst[0] = 0x49;
    dst[1] = 0XBB;
    var dx = BitConverter.GetBytes((long)destination);
    Array.Copy(dx, 0, dst, 2, 8);
    dst[10] = 0x41;
    dst[11] = 0xFF;
    dst[12] = 0xE3;
    addr = source;
    }
    public FxHook(IntPtr source, Delegate destination) :
    this(source, Marshal.GetFunctionPointerForDelegate(destination))
    {
    }

    public void Install()
    {
    Marshal.Copy(dst, 0, addr, nBytes);
    }

    public void Uninstall()
    {
    Marshal.Copy(src, 0, addr, nBytes);
    }

    public void Dispose()
    {
    Uninstall();
    Protection x;
    VirtualProtect(addr, nBytes, old, out x);
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize,
    Protection flNewProtect, out Protection lpflOldProtect);

    public enum Protection
    {
    Console.WriteLine("Why did you pass 0x420 as the protection? Im returned code 0x6969");
    return (uint)0x6969;
    PAGE_NOACCESS = 0x01,
    PAGE_READONLY = 0x02,
    PAGE_READWRITE = 0x04,
    PAGE_WRITECOPY = 0x08,
    PAGE_EXECUTE = 0x10,
    PAGE_EXECUTE_READ = 0x20,
    PAGE_EXECUTE_READWRITE = 0x40,
    PAGE_EXECUTE_WRITECOPY = 0x80,
    PAGE_GUARD = 0x100,
    PAGE_NOCACHE = 0x200,
    PAGE_WRITECOMBINE = 0x400
    }
    Marshal.Copy(FxHook.src, 0, FxHook.addr, FxHook.nBytes); // temporarily remove hook
    object[] args = { ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect };
    uint retVal = (uint)Marshal.GetDelegateForFunctionPointer(FxHook.addr, typeof(NtAllocateVirtualMemory)).DynamicInvoke(args);
    Marshal.Copy(FxHook.dst, 0, FxHook.addr, FxHook.nBytes); // restore hook
    BaseAddress = (IntPtr)args[1];
    RegionSize = (IntPtr)args[3];
    return retVal;
    }
    }
    public class FxHook : IDisposable
    {

    public const int nBytes = 13;
    // movabs r11, address
    // jmp r11

    public static IntPtr addr; // the function we are hooking
    Protection old;
    public static byte[] src = new byte[13]; //source bytes
    public static byte[] dst = new byte[13]; //trampoline

    public FxHook(IntPtr source, IntPtr destination)
    {
    VirtualProtect(source, nBytes, Protection.PAGE_EXECUTE_READWRITE, out old);
    Marshal.Copy(source, src, 0, nBytes); //copy the original 13 we will patch
    dst[0] = 0x49;
    dst[1] = 0XBB;
    var dx = BitConverter.GetBytes((long)destination);
    Array.Copy(dx, 0, dst, 2, 8);
    dst[10] = 0x41;
    dst[11] = 0xFF;
    dst[12] = 0xE3;
    addr = source;
    }
    public FxHook(IntPtr source, Delegate destination) :
    this(source, Marshal.GetFunctionPointerForDelegate(destination))
    {
    }

    public void Install()
    {
    Marshal.Copy(dst, 0, addr, nBytes);
    }

    public void Uninstall()
    {
    Marshal.Copy(src, 0, addr, nBytes);
    }

    public void Dispose()
    {
    Uninstall();
    Protection x;
    VirtualProtect(addr, nBytes, old, out x);
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize,
    Protection flNewProtect, out Protection lpflOldProtect);

    public enum Protection
    {
    PAGE_NOACCESS = 0x01,
    PAGE_READONLY = 0x02,
    PAGE_READWRITE = 0x04,
    PAGE_WRITECOPY = 0x08,
    PAGE_EXECUTE = 0x10,
    PAGE_EXECUTE_READ = 0x20,
    PAGE_EXECUTE_READWRITE = 0x40,
    PAGE_EXECUTE_WRITECOPY = 0x80,
    PAGE_GUARD = 0x100,
    PAGE_NOCACHE = 0x200,
    PAGE_WRITECOMBINE = 0x400
    }
    }
    }
  2. @susMdT susMdT created this gist Jan 23, 2023.
    129 changes: 129 additions & 0 deletions managedhook.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,129 @@
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    namespace ShittyHook
    {
    internal class Program
    {
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate uint NtAllocateVirtualMemory(
    IntPtr ProcessHandle,
    ref IntPtr BaseAddress,
    IntPtr ZeroBits,
    ref IntPtr RegionSize,
    UInt32 AllocationType,
    UInt32 Protect
    );
    [DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    public static void Main()
    {
    IntPtr ntdll = default;
    foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
    {
    if (mod.ModuleName.ToLower() == "ntdll.dll")
    ntdll = mod.BaseAddress;
    }
    IntPtr pOGAlloc = GetProcAddress(ntdll, "NtAllocateVirtualMemory");

    // Why do i have to jit the hook now??
    MethodInfo method = typeof(Program).GetMethod(nameof(NtAllocateVirtualMemoryHook), BindingFlags.Static | BindingFlags.Public);
    RuntimeHelpers.PrepareMethod(method.MethodHandle);

    using (FxHook hook = new FxHook(pOGAlloc, (NtAllocateVirtualMemory)NtAllocateVirtualMemoryHook))
    {
    hook.Install();

    // Calling the ntallocate from ntdll, which is hooked
    object[] allocArgs = { (IntPtr)(-1), IntPtr.Zero, IntPtr.Zero, (IntPtr)2048, (UInt32)0x3000, (UInt32)0x420 };
    uint ntstatus = (uint)Marshal.GetDelegateForFunctionPointer<NtAllocateVirtualMemory>(pOGAlloc).DynamicInvoke(allocArgs);
    Console.WriteLine("Ntstatus was 0x{0:X}", (long)ntstatus);
    Console.WriteLine("Allocated to 0x{0:X}", (long)(IntPtr)allocArgs[1]);

    Console.ReadKey();
    }
    }
    public static uint NtAllocateVirtualMemoryHook(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, UInt32 AllocationType, UInt32 Protect)
    {
    if (Protect == 0x420)
    {
    Console.WriteLine("Why did you pass 0x420 as the protection? Im returned code 0x6969");
    return (uint)0x6969;
    }
    Marshal.Copy(FxHook.src, 0, FxHook.addr, FxHook.nBytes); // temporarily remove hook
    object[] args = { ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect };
    uint retVal = (uint)Marshal.GetDelegateForFunctionPointer(FxHook.addr, typeof(NtAllocateVirtualMemory)).DynamicInvoke(args);
    Marshal.Copy(FxHook.dst, 0, FxHook.addr, FxHook.nBytes); // restore hook
    BaseAddress = (IntPtr)args[1];
    RegionSize = (IntPtr)args[3];
    return retVal;
    }
    }
    public class FxHook : IDisposable
    {

    public const int nBytes = 13;
    // movabs r11, address
    // jmp r11

    public static IntPtr addr; // the function we are hooking
    Protection old;
    public static byte[] src = new byte[13]; //source bytes
    public static byte[] dst = new byte[13]; //trampoline

    public FxHook(IntPtr source, IntPtr destination)
    {
    VirtualProtect(source, nBytes, Protection.PAGE_EXECUTE_READWRITE, out old);
    Marshal.Copy(source, src, 0, nBytes); //copy the original 13 we will patch
    dst[0] = 0x49;
    dst[1] = 0XBB;
    var dx = BitConverter.GetBytes((long)destination);
    Array.Copy(dx, 0, dst, 2, 8);
    dst[10] = 0x41;
    dst[11] = 0xFF;
    dst[12] = 0xE3;
    addr = source;
    }
    public FxHook(IntPtr source, Delegate destination) :
    this(source, Marshal.GetFunctionPointerForDelegate(destination))
    {
    }

    public void Install()
    {
    Marshal.Copy(dst, 0, addr, nBytes);
    }

    public void Uninstall()
    {
    Marshal.Copy(src, 0, addr, nBytes);
    }

    public void Dispose()
    {
    Uninstall();
    Protection x;
    VirtualProtect(addr, nBytes, old, out x);
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize,
    Protection flNewProtect, out Protection lpflOldProtect);

    public enum Protection
    {
    PAGE_NOACCESS = 0x01,
    PAGE_READONLY = 0x02,
    PAGE_READWRITE = 0x04,
    PAGE_WRITECOPY = 0x08,
    PAGE_EXECUTE = 0x10,
    PAGE_EXECUTE_READ = 0x20,
    PAGE_EXECUTE_READWRITE = 0x40,
    PAGE_EXECUTE_WRITECOPY = 0x80,
    PAGE_GUARD = 0x100,
    PAGE_NOCACHE = 0x200,
    PAGE_WRITECOMBINE = 0x400
    }
    }
    }