4a. Direct Syscalls cpp

1. Direct Syscall for NtAllocateVirtualMemory in C++ (x64 Windows)

#include <windows.h>
#include <iostream>

typedef LONG NTSTATUS;
typedef SIZE_T* PSIZE_T;

// Declare the syscall function
extern "C" NTSTATUS DirectSyscall(
    HANDLE ProcessHandle,
    PVOID* BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T RegionSize,
    ULONG AllocationType,
    ULONG Protect);

// Define the syscall function with proper 64-bit assembly
extern "C" NTSTATUS DirectSyscall(
    HANDLE ProcessHandle,
    PVOID* BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T RegionSize,
    ULONG AllocationType,
    ULONG Protect) 
{
    NTSTATUS status;

    // Pass the value of RegionSize (dereferenced) directly to r8
    SIZE_T regionSizeValue = *RegionSize;

    // Ensure stack alignment (Windows x64 requires 16-byte alignment)
    // We push one value (8 bytes), so we need to adjust rsp to align
    __asm__ __volatile__ (
        "subq $8, %%rsp \n\t"   // Align stack to 16 bytes (rsp % 16 == 0)
        "movq %1, %%r10 \n\t"   // Move ProcessHandle to r10 (64-bit)
        "movq %2, %%rcx \n\t"   // BaseAddress to rcx
        "movq %3, %%rdx \n\t"   // ZeroBits to rdx
        "movq %4, %%r8 \n\t"    // RegionSize value to r8 (64-bit)
        "movl %5, %%r9d \n\t"   // AllocationType to r9d (32-bit, zero-extends to r9)
        "movl %6, %%eax \n\t"   // Protect to eax
        "pushq %%rax \n\t"      // Push Protect onto the stack (6th arg)
	        "movl $0x18, %%eax \n\t" // Syscall number for NtAllocateVirtualMemory
        "syscall \n\t"          // Execute syscall
        "movl %%eax, %0 \n\t"   // Store NTSTATUS return value
        "addq $16, %%rsp \n\t"  // Clean up the stack (8 for push, 8 for alignment)
        : "=r" (status)         // Output
        : "r" (ProcessHandle), "r" (BaseAddress), "r" (ZeroBits), "r" (regionSizeValue),
          "r" (AllocationType), "r" (Protect) // Inputs
        : "rax", "rcx", "rdx", "r8", "r9", "r10", "r11", "memory" // Clobbered
    );

    return status;
}

int main() {
    PVOID baseAddress = NULL;
    SIZE_T regionSize = 0x1000;  // 4KB page
    NTSTATUS status;

    std::cout << "[*] Calling NtAllocateVirtualMemory via direct syscall..." << std::endl;

    status = DirectSyscall(
        GetCurrentProcess(),      // Current process handle
        &baseAddress,             // Pointer to base address
        0,                        // ZeroBits
        &regionSize,              // Pointer to region size
        MEM_COMMIT | MEM_RESERVE, // Allocation type
        PAGE_READWRITE            // Protection
    );

    if (status == 0) {
        std::cout << "[+] Memory allocated at: 0x" << std::hex << baseAddress << std::endl;
    } else {
        std::cout << "[-] NtAllocateVirtualMemory failed with status: 0x" << std::hex << status << std::endl;
    }

    return 0;
}

.vscode/tasks.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build for Windows (64-bit)",
            "type": "shell",
            "command": "x86_64-w64-mingw32-g++",
            "args": [
                "-g",
                "-Wall",
                "-static",
                "/home/tester/tools/cobaltstrike/payloads/cpp/a.cpp",
                "-o",
                "/home/tester/tools/cobaltstrike/payloads/cpp/a.exe"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": ["$gcc"],
            "options": {
                "cwd": "${workspaceFolder}"
            }
        }
    ]
}

.vscode/c_cpp_properties.json

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "/usr/include",
                "/usr/local/include",
                "/usr/share/mingw-w64/include"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/x86_64-w64-mingw32-g++", 
            "cStandard": "c17",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}


.vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
      {
          "name": "Debug Windows Executable with GDB (Wine)",
          "type": "cppdbg",
          "request": "launch",
          "program": "${workspaceFolder}/${input:executableName}.exe",
          "args": [],
          "stopAtEntry": true,
          "cwd": "${workspaceFolder}",
          "environment": [],
          "externalConsole": false,
          "MIMode": "gdb",
          "miDebuggerPath": "/usr/bin/gdb",
          "setupCommands": [
              {
                  "description": "Enable pretty-printing for gdb",
                  "text": "-enable-pretty-printing",
                  "ignoreFailures": true
              }
          ],
          "preLaunchTask": "Build for Windows (64-bit)",
          "winePath": "/usr/bin/wine",
          "windows": {
              "MIMode": "gdb"
          }
      }
  ],
  "inputs": [
      {
          "type": "promptString",
          "id": "executableName",
          "description": "Name of your executable",
          "default": "alloc_memory"
      }
  ]
}

2. How This Works

Step Explanation
1. Prepare Parameters Sets up parameters for NtAllocateVirtualMemory.
2. Move ProcessHandle to R10 x64 syscalls require RCX → R10.
3. Set EAX = 0x18 (Syscall Number) Loads the syscall number for NtAllocateVirtualMemory.
4. Execute syscall Instruction Directly transitions to kernel mode (Ring 0).
5. Return Result The syscall result (NTSTATUS) is returned to the program.
6. Check Success or Failure If NTSTATUS == 0, memory was allocated. Otherwise, error code is printed.

3. Compile and Run

Compile with MinGW-w64 (for x64)

x86_64-w64-mingw32-g++ -o alloc_memory.exe alloc_memory.cpp -Wall -static

Run the Executable in Windows

alloc_memory.exe

Success Output:

[*] Calling NtAllocateVirtualMemory via direct syscall...
[+] Memory allocated at: 0x00000012345678

Failure Output:

[*] Calling NtAllocateVirtualMemory via direct syscall...
[-] NtAllocateVirtualMemory failed with status: 0xC000000D