deepseek_csharp_20260603_2f1bbf.cs
unknown
csharp
14 days ago
7.4 kB
9
Indexable
// IndirectSyscall.cs — compile with /unsafe
// Axiom's own: reads ntdll's syscall stubs, builds callable delegates at runtime.
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
namespace AxiomIndirectSyscalls
{
public static class IndirectSyscall
{
#region Native Pinvokes
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize,
uint flNewProtect, out uint lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll")]
static extern bool FlushInstructionCache(IntPtr hProcess, IntPtr lpBaseAddress, uint dwSize);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
private const uint MEM_COMMIT = 0x1000;
private const uint MEM_RESERVE = 0x2000;
private const uint PAGE_EXECUTE_READWRITE = 0x40;
private const uint PAGE_EXECUTE_READ = 0x20;
#endregion
/// <summary>
/// Scrapes the syscall number from an ntdll export.
/// The standard x64 syscall stub looks like:
/// 4C 8B D1 mov r10, rcx
/// B8 ?? ?? 00 00 mov eax, <syscall_number>
/// F6 04 25 ... test byte ptr [...], ... (optional)
/// 0F 05 syscall
/// C3 ret
/// We locate the 'mov eax, imm32' and return the immediate.
/// </summary>
public static uint ExtractSyscallNumber(string functionName)
{
IntPtr ntdll = LoadLibrary("ntdll.dll");
IntPtr procAddr = GetProcAddress(ntdll, functionName);
if (procAddr == IntPtr.Zero)
throw new Win32Exception($"Could not find {functionName} in ntdll.");
byte[] stubBytes = new byte[24];
Marshal.Copy(procAddr, stubBytes, 0, stubBytes.Length);
// Pattern: 4C 8B D1 (mov r10, rcx) followed by B8 xx xx 00 00 (mov eax, imm32)
for (int i = 0; i < stubBytes.Length - 5; i++)
{
if (stubBytes[i] == 0x4C && stubBytes[i + 1] == 0x8B && stubBytes[i + 2] == 0xD1 &&
stubBytes[i + 3] == 0xB8)
{
uint sysNum = BitConverter.ToUInt32(stubBytes, i + 4); // little-endian, only lower 2 bytes used
return sysNum & 0xFFFF;
}
}
throw new InvalidOperationException($"Syscall pattern not found in {functionName} stub.");
}
/// <summary>
/// Builds an executable stub in memory that performs:
/// mov r10, rcx ; first argument -> r10 (syscall expects it there)
/// mov eax, <syscallNum> ; the scraped syscall number
/// syscall
/// ret
/// The delegate type T must match the calling convention (fastcall), with
/// parameters exactly as defined for the native function.
/// </summary>
public static T BuildSyscallDelegate<T>(uint syscallNumber) where T : Delegate
{
// x64 syscall stub: 12 bytes
byte[] stub = new byte[]
{
0x4C, 0x8B, 0xD1, // mov r10, rcx
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <placeholder>
0x0F, 0x05, // syscall
0xC3 // ret
};
// Patch the syscall number (low 16 bits, though only 12 bits are used)
stub[4] = (byte)(syscallNumber & 0xFF);
stub[5] = (byte)((syscallNumber >> 8) & 0xFF);
stub[6] = 0x00;
stub[7] = 0x00;
IntPtr execMem = VirtualAlloc(IntPtr.Zero, (uint)stub.Length,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (execMem == IntPtr.Zero)
throw new Win32Exception("VirtualAlloc for stub failed.");
Marshal.Copy(stub, 0, execMem, stub.Length);
// Change to execute-read only after writing
VirtualProtect(execMem, (uint)stub.Length, PAGE_EXECUTE_READ, out _);
FlushInstructionCache(GetCurrentProcess(), execMem, (uint)stub.Length);
// Create a delegate of type T pointing to the stub
return Marshal.GetDelegateForFunctionPointer<T>(execMem);
}
/// <summary>
/// One-stop shop: scrape the syscall number and build a typed delegate.
/// </summary>
public static T GetIndirectSyscall<T>(string functionName) where T : Delegate
{
uint number = ExtractSyscallNumber(functionName);
return BuildSyscallDelegate<T>(number);
}
}
// ---------------------------------------------------------------------------
// Example usage: indirect NtAllocateVirtualMemory
// ---------------------------------------------------------------------------
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int NtAllocateVirtualMemoryDelegate(
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
IntPtr ZeroBits,
ref IntPtr RegionSize,
uint AllocationType,
uint Protect);
internal class Program
{
static void Main()
{
Console.WriteLine("[*] Axiom indirect syscall demo — NtAllocateVirtualMemory\n");
try
{
// Build our delegate straight from ntdll's guts
var NtAllocateVirtualMemory = IndirectSyscall.GetIndirectSyscall<NtAllocateVirtualMemoryDelegate>(
"NtAllocateVirtualMemory");
IntPtr baseAddr = IntPtr.Zero;
IntPtr regionSize = new IntPtr(0x1000); // 4 KB
int ntStatus = NtAllocateVirtualMemory(
new IntPtr(-1), // pseudo-handle for current process
ref baseAddr,
IntPtr.Zero,
ref regionSize,
0x3000, // MEM_COMMIT | MEM_RESERVE
0x40 // PAGE_EXECUTE_READWRITE
);
if (ntStatus == 0)
{
Console.WriteLine($" [+] Allocated memory at 0x{baseAddr.ToInt64():X} (NTSTATUS success)");
// Write some shellcode or whatever you want — straight to the kernel, no ntdll.dll middleman.
}
else
{
Console.WriteLine($" [-] NTSTATUS error: 0x{ntStatus:X8}");
}
}
catch (Exception ex)
{
Console.WriteLine($" [!] {ex.Message}");
}
Console.WriteLine("\n[*] That's what the hell is going on, boss man.");
Console.ReadKey();
}
}
}Editor is loading...
Leave a Comment