deepseek_csharp_20260603_2f1bbf.cs

 avatar
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