Skip to content

Instantly share code, notes, and snippets.

@NaxAlpha
Last active October 24, 2024 12:53
Show Gist options
  • Save NaxAlpha/144d1dd96c7d0ad29fe149e4063a8f25 to your computer and use it in GitHub Desktop.
Save NaxAlpha/144d1dd96c7d0ad29fe149e4063a8f25 to your computer and use it in GitHub Desktop.
Windows API Hook with C#
using System;
using System.Runtime.InteropServices;
public class FxHook:IDisposable {
const int nBytes = 5;
IntPtr addr;
Protection old;
byte[] src = new byte[5];
byte[] dst = new byte[5];
public FxHook(IntPtr source, IntPtr destination) {
VirtualProtect(source, nBytes, Protection.PAGE_EXECUTE_READWRITE, out old);
Marshal.Copy(source, src, 0, nBytes);
dst[0] = 0xE9;
var dx = BitConverter.GetBytes((int)destination - (int)source - nBytes);
Array.Copy(dx, 0, dst, 1, nBytes-1);
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
}
}
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
class Program {
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
// Function to be hooked
[DllImport("kernel32.dll")]
static extern void Sleep(uint dwMilliseconds);
// Must create delegate type
// Marshal.GetFunctionPointerForDelegate requires non generic delegate tpe
delegate void SleepFx(uint ms);
static FxHook hook;
// Hook function must be of same signature as of original function
static void Sleep2(uint ms) {
MessageBox.Show("Sleeping for: " + ms.ToString());
// Uninstall hook before calling real function otherwise stack overflow
hook.Uninstall();
Sleep(ms);
hook.Install();
}
static void Main(string[] args) {
var k32 = LoadLibrary("kernel32");
var slp = GetProcAddress(k32, "Sleep");
using(hook = new FxHook(slp, (SleepFx)Sleep2)) {
hook.Install();
Sleep(1000);
}
// This will call original sleep
Sleep(1000);
}
}
@DennisVM-D2i
Copy link

DennisVM-D2i commented Oct 24, 2024

The sample seems to work fine for x86 (/32 bits), but fails for x64 (/64 bits).

It would (also) be nice to have this line described - in terms of the relation of 'destination' to 'source':

var dx = BitConverter.GetBytes((int)destination - (int)source - nBytes);

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