RedBird.Core 1.3.2

dotnet add package RedBird.Core --version 1.3.2
                    
NuGet\Install-Package RedBird.Core -Version 1.3.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RedBird.Core" Version="1.3.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RedBird.Core" Version="1.3.2" />
                    
Directory.Packages.props
<PackageReference Include="RedBird.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RedBird.Core --version 1.3.2
                    
#r "nuget: RedBird.Core, 1.3.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RedBird.Core@1.3.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RedBird.Core&version=1.3.2
                    
Install as a Cake Addin
#tool nuget:?package=RedBird.Core&version=1.3.2
                    
Install as a Cake Tool

<div align="center"> <img src="docs/images/logo.png" alt="logo" width="256" height="256"/>

RedBird.NET

RedBird is a (mostly) managed native-hooking toolkit for .NET. It offers X64 and X86 detour engines, transactional pattern-based hooks, executable-memory helpers, modular backends, and calling convention intermediary stubs.

<br/>

CI/CD Release Downloads License
pipeline latest release NuGet Downloads license

x86 | x64 C# Iced Windows Linux

</div>

Highlights

  • Managed native X64 and X86 detour backends with relocated-original trampolines.
  • Safe executable-code patching on Windows X64/X86 and Linux X64: peer threads are parked while instruction pointers inside a replaced prologue are moved to their trampoline equivalents.
  • Hook chaining with safe reverse-order unhooking.
  • Pattern (wildcard AOB), relative-call destination, address, RVA, and export targets with transactional commit and rollback policies.
  • Context hooks, inline hooks, function clones, stateful assembly patches, and instruction walkers.
  • Public runtime-assembled executable functions for X64 and X86.
  • Supports X86 cdecl, stdcall, fastcall, thiscall, GCC, Pascal, and custom register/stack layouts.
  • Supports X64 managed ABI and Microsoft __vectorcall intermediary stubs in both directions, including scalar, SIMD, HVA, and supported aggregate-return layouts on Windows and System V Linux.
  • Multi-targeted packages for net10.0 and .NET Framework 4.8.

Packages

dotnet add package RedBird
dotnet add package RedBird.Extensions.CallingConventions

The RedBird meta-package includes the main X64/X86 libraries and native backends. Every package can also be referenced separately:

Package Purpose
RedBird Meta-package for the main X64/X86 libraries and native backends
RedBird.Abstractions Backend-agnostic hook, transaction, and ABI contracts
RedBird.Core Executable memory, scanners, platform helpers, and the Linux X64 patch companion
RedBird.X64 X64 scanners, transactions, inline/context hooks, and executable functions
RedBird.X86 X86 hooks and executable functions
RedBird.Backends.NativeX64 Managed X64 function-detour engine
RedBird.Backends.NativeX86 Managed X86 function-detour engine
RedBird.Backends.PolyHook2 Optional PolyHook2 backend with safe logical chaining
RedBird.Backends.MinHook Optional MinHook.NET backend
RedBird.Extensions.CallingConventions X86 convention and X64 vectorcall adapters

Example: assemble and detour a real function

This self-contained example creates native code, calls it, hooks it, calls the relocated original, and restores it. The complete runnable version lives in samples/RedBird.Examples.

using System;
using System.Runtime.InteropServices;
using Iced.Intel;
using RedBird.Abstractions.Hooks;
using RedBird.Backends.NativeX64;
using RedBird.X64.Assembly;
using static Iced.Intel.AssemblerRegisters;

internal static class Program
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    private delegate int BinaryInt(int left, int right);

    private static void Main()
    {
        using var target = ExecutableFunction.Create(assembler =>
        {
            if (OperatingSystem.IsWindows())
            {
                assembler.mov(eax, ecx);
                assembler.add(eax, edx);
            }
            else
            {
                assembler.mov(eax, edi);
                assembler.add(eax, esi);
            }
            for (var i = 0; i < 20; i++) assembler.nop();
            assembler.ret();
        });

        var call = target.GetDelegate<BinaryInt>();
        IDetour<BinaryInt>? hook = null;
        hook = NativeDetourBackend.Instance.CreateDetour(new DetourRequest<BinaryInt>
        {
            Name = "multiply-add-result",
            TargetAddress = target.Address,
            Callback = (a, b) => hook!.Original(a, b) * 10,
        });

        using (hook)
        {
            Console.WriteLine(call(3, 4)); // 7
            hook.Enable();
            Console.WriteLine(call(3, 4)); // 70
        }
        Console.WriteLine(call(3, 4)); // 7
    }
}

Example: adapt an X86 fastcall target

The delegate describes the managed cdecl view. The intermediary factory generates both directions: native fastcall → managed callback and managed Original call → native fastcall.

using System.Runtime.InteropServices;
using RedBird.Abstractions.CallingConventions;
using RedBird.Abstractions.Hooks;
using RedBird.Backends.NativeX86;
using RedBird.Extensions.CallingConventions.NativeX86;

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int NativeFunction(int first, int second, int third);

var request = new DetourRequest<NativeFunction>
{
    Name = "fastcall-target",
    TargetAddress = targetAddress,
    Callback = callback,
    IntermediaryFactory =
        new X86CallingConventionIntermediaryFactory<NativeFunction>(X86CallingConvention.Fastcall),
};

using var hook = X86DetourBackend.Instance.CreateDetour(request);
hook.Enable();

Custom X86 layouts use [X86CallingConvention], [X86RegisterArgument], explicit stack cleanup, argument order, and optional custom return registers.

Example: bridge the managed X64 ABI and vectorcall

using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using RedBird.Abstractions.Hooks;
using RedBird.Extensions.CallingConventions.NativeX64;

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate float VectorOperation(float scale, [VectorcallArgument(16)] Vector128<float> value);

var request = new DetourRequest<VectorOperation>
{
    Name = "vectorcall-target",
    TargetAddress = targetAddress,
    Callback = callback,
    IntermediaryFactory = new X64VectorcallIntermediaryFactory<VectorOperation>(),
};

The factory wraps both the callback entry and Original trampoline path. See the calling-convention guide for HVA annotations, supported returns, and ABI limitations.

Transaction and scanner conveniences

Transactions return a fresh handle when a hook does not need a predeclared field. This works for detours and context hooks; the transaction retains ownership, so the return value may be ignored:

transaction.AddContextHook(
    HookTarget.FromPattern("48 89 5C 24 ?? 57", offset: 6),
    OnContext);

When only a call site has a stable signature, resolve the direct relative CALL destination explicitly. This hooks the called function, while leaving the call instruction itself intact:

transaction.AddDetour(
    createTribeHook,
    HookTarget.FromRelativeCall("E8 ?? ?? ?? ?? 48 63 F8 89 7C 24 ?? 85 C0"),
    OnCreateTribe);

Use callOffset when the signature begins before the call. Indirect calls are rejected. FromPattern continues to mean that the matched address itself is the hook target.

Persistent AOB cache

Transactions can persist pattern matches as region-relative virtual addresses and reuse them on the next run:

using RedBird.Core.Memory.Scanners;

string cacheDirectory = "MyCacheDir";

AobCacheOptions aobCache = new(Path.Combine(cacheDirectory, "game-module.aobcache.json"));

var options = new HookTransactionOptions
{
    Backend = NativeDetourBackend.Instance,
    AobCache = aobCache,
};

using var transaction = new HookTransaction(region, options: options);

DataScanner scanner = DataScanner.Create(
    region,
    logger: null,
    aobCache: aobCache);

The parent directory is created on the first write. The compact JSON file contains AOB-to-RVA maps. A complete cache hit avoids the multi-pattern scan; partial hits scan only the missing patterns and then update the file. Missing patterns are cached too.

The same cache works with the x64 and x86 DataScanner. Scan reuses first-match RVAs, while ScanAll persists complete multi-match RVA sets. When ScanAll reaches its result limit, that truncated set is returned but is not reused later as a complete result. A scanner instance loads the document once, then shares that state across its fluent scan calls. Core callers can also pass a ScanRegion and AobCacheOptions to the cached MultiPatternScanner.FindFirst/FindAll overloads.

Use one cache file per module or scan region. Cached entries are authoritative: RedBird does not validate the region, pattern bytes, or RVA before use. Delete the cache whenever the target binary or its signatures change. Malformed files and cache I/O errors fall back to normal scans and do not fail the hook transaction. RVA entries never reuse an absolute address from a previous process.

AobCacheOptions.Store defaults to JsonAobCacheStore.Instance, which uses System.Text.Json and plain AobCacheDocument objects. Implement IAobCacheStore and set that property when a binary format such as MessagePack is preferable; transaction and scanner behavior remain the same.

When a callback needs Original, initialize its persistent handle before registration. Export targets do not change that requirement:

private readonly DetourHandle<LoadMapDelegate> loadMapHook = new();

transaction.AddDetour(
    loadMapHook,
    HookTarget.FromExport("DLL_LoadMapToPlay", moduleHandle),
    OnLoadMap);

Passing an uninitialized (null) handle fails during registration, before the export is resolved. If no persistent handle is needed, omit the first argument and keep the handle returned by the handle-less overload instead.

DataScanner.CurrentAddress reports the absolute virtual address. CurrentOffset reports the signed byte offset from the associated ScanRegion.BaseAddress, which is useful when recording an RVA. Check Found first because both a failed scan and a successful match at the region base report an offset of zero.

X86 and X64 switch/FSM dispatches

SwitchDispatchDecoder resolves supported compiler jump tables back into selector values, handler addresses, shared/default blocks, and half-open linear boundaries. A case block can create an InstructionWalker that is automatically capped before the next distinct handler:

SwitchDispatch dispatch = SwitchDispatchDecoder.Decode(region, functionAddress);
SwitchCaseBlock state65 = dispatch.GetCase(0x65);
InstructionWalker walker = state65.CreateWalker(walkerConfig, logger);

The x64 implementation handles direct signed table-relative layouts commonly emitted by GCC and Clang, plus direct or byte-remapped unsigned image-relative layouts used by MSVC.

The x86 package handles absolute pointer tables and statically based relative tables, with optional byte remapping.

See the switch-dispatch guide for supported shapes and boundary caveats.

Platform support

Feature Windows X64 Windows X86 Linux X64 Linux X86
Native detours Build-supported
Safe peer-thread patching
X86 convention adapters Build-supported
X64 vectorcall adapters
PolyHook2 backend Dependency-supported
MinHook backend

Build-supported means the code compiles for that combination but is not exercised by this repository's CI runners.

Safe patching on Linux X64

NativeDetourBackend protects enable and disable operations by default on Linux X64 when /proc/self/maps is available. Its packaged, C-runtime-free native companion (libredbird_thread_patch.so) selects an unused real-time signal, parks peer threads on futexes, relocates a saved instruction pointer when it falls inside the displaced prologue, applies the patch, restores page protections, and releases the threads. The installed hook has no additional steady-state overhead from this mechanism.

The selected signal remains reserved for the process lifetime. If a peer thread blocks it, another component replaces its handler, thread enumeration fails, or all peers cannot be parked within five seconds, RedBird reports the failure without writing the patch. Set SuspendThreadsDuringPatch to false only when the host provides its own safe point or when you accept the patching race.

Unity Mono exposes GC.TryStartNoGCRegion on some profiles but throws NotImplementedException when it is called. RedBird detects that unsupported capability and uses its allocation-free critical patch path without no-GC mode. Runtimes which implement the API but cannot reserve the requested budget still fail before any peer thread is suspended.

See Getting started: configure safe patching and the native companion notes.

Build, test, docs, and package

On Linux x64, build the native thread-patching companion before creating distributable packages:

sh src/RedBird.Core/native/linux-x64/build.sh

Then build the managed projects, documentation, and packages:

dotnet restore RedBird.slnx
dotnet build RedBird.slnx -c Release --no-restore
dotnet tool restore
dotnet tool run docfx docs/docfx.json
dotnet pack RedBird.slnx -c Release --no-build -p:PackageVersion=0.1.0

Windows execution tests are architecture-specific:

./scripts/ci/run-tests.ps1 -Architecture X64
./scripts/ci/run-tests.ps1 -Architecture X86

GitLab CI also rebuilds and smoke-tests the native Linux X64 companion, then runs the X64 test suite on Linux. The companion's standalone build and test commands are documented in its native README.

Documentation

License

RedBird.NET is licensed under LGPL-3.0-or-later.

Credits and Thanks

  • 0xd4d and the contributors of the amazing Iced dis(assembler) engine! (Seriously its cracked)
  • Stevemk14ebr and the contributors of the native PolyHook2 hooking library (Pretty much the best standalone hooking lib out there I reckon)
  • -1212 (Safe Linux64 patching)
  • Henry (The picture used for the logo - CC-BY-2.0, please see ATTRIBUTIONS.md)

Support the Project

This is a project maintained in my (@Rawra) free time.
If you enjoy it and want to support its continued development, you can buy me a coffee:

ko-fi

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on RedBird.Core:

Package Downloads
RedBird.Extensions.CallingConventions

Calling-convention intermediary stubs for RedBird native detours.

RedBird.Backends.NativeX86

A managed x86 function-detour engine, based on PolyHook2

RedBird.X86

x86 (32-bit) inline hooking backend.

RedBird.Backends.NativeX64

A managed x64 function-detour engine, based on PolyHook2

RedBird.X64

Advanced x64 inline hooking for .NET: instruction/function walkers, transactional hook installation, stateful assembly patches, and CPU-context-aware detours built on Iced and PolyHook2.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.2 0 9/15/2026
1.3.1 9 9/15/2026
1.3.0 40 9/15/2026
1.2.0 80 9/12/2026
1.1.0 141 9/7/2026
1.0.0 143 9/4/2026