| name | reverse-engineering-ransomware-encryption-routine |
| description | Reverse engineer ransomware encryption routines to identify cryptographic algorithms, key generation flaws, and potential decryption opportunities using static and dynamic analysis. |
| domain | cybersecurity |
| subdomain | malware-analysis |
| tags | ["ransomware","encryption","reverse-engineering","cryptanalysis","aes","rsa","decryption","malware-analysis"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
Reverse Engineering Ransomware Encryption Routine
Overview
Modern ransomware uses hybrid encryption combining symmetric algorithms (AES-256-CBC/CTR, ChaCha20, Salsa20) for file encryption with asymmetric algorithms (RSA-2048/4096, Curve25519) for key protection. The encryption routine typically generates a random symmetric key per file, encrypts file contents, then encrypts the symmetric key with the attacker's embedded public key. Reverse engineering these routines identifies the specific algorithms, key derivation methods, initialization vectors, file targeting patterns, and potential implementation flaws that could enable decryption without paying the ransom. Notable examples include Rhysida (AES-256-CTR + RSA-4096), Qilin.B (AES-256-CTR with AES-NI or ChaCha20 fallback), and Medusa (AES-256 + RSA).
Prerequisites
- IDA Pro or Ghidra for static disassembly
- x64dbg/WinDbg for dynamic debugging
- Python 3.9+ with
pycryptodome, pefile
- Understanding of AES, RSA, ChaCha20, Curve25519 algorithms
- Knowledge of Windows CryptoAPI and CNG (BCrypt) functions
- Sandbox environment for safe execution
Key Concepts
Hybrid Encryption Model
Ransomware generates a unique AES key and IV for each file. The file content is encrypted with this symmetric key. The symmetric key is then encrypted with the attacker's RSA public key (embedded in the binary or fetched from C2). The encrypted key is appended or prepended to the encrypted file. Only the attacker holding the RSA private key can decrypt the per-file symmetric keys.
Cryptographic API Identification
Windows ransomware typically uses CryptoAPI (CryptAcquireContext, CryptGenKey, CryptEncrypt) or CNG (BCryptGenerateSymmetricKey, BCryptEncrypt). Some use OpenSSL or custom implementations. Identifying these API calls provides immediate insight into the algorithm, key size, and mode of operation.
Implementation Flaws
Decryption opportunities arise from: hardcoded encryption keys, weak PRNG for key generation (using GetTickCount or time() as seed), reuse of IVs across files, ECB mode usage, keys remaining in memory post-encryption, and race conditions where keys can be captured during encryption.
Practical Steps
Step 1: Identify Cryptographic Functions
"""Identify cryptographic functions in ransomware PE files."""
import pefile
import sys
CRYPTO_APIS = {
"CryptAcquireContextA": "CryptoAPI context acquisition",
"CryptAcquireContextW": "CryptoAPI context acquisition",
"CryptGenKey": "Key generation",
"CryptDeriveKey": "Key derivation",
"CryptEncrypt": "Encryption operation",
"CryptDecrypt": "Decryption operation",
"CryptImportKey": "Key import (public key?)",
"CryptExportKey": "Key export",
"CryptGenRandom": "Random number generation",
"CryptCreateHash": "Hash creation",
"CryptHashData": "Hashing operation",
"BCryptOpenAlgorithmProvider": "CNG algorithm initialization",
"BCryptGenerateSymmetricKey": "CNG symmetric key generation",
"BCryptEncrypt": "CNG encryption",
"BCryptDecrypt": "CNG decryption",
"BCryptGenerateKeyPair": "CNG key pair generation",
"BCryptImportKeyPair": "CNG key import",
"EVP_EncryptInit_ex": "OpenSSL encrypt init",
"EVP_EncryptUpdate": ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
}
AES_SBOX = ([
, , , , , , , ,
, , , , , , , ,
])
CHACHA20_CONSTANT =
():
:
pe = pefile.PE(filepath)
pefile.PEFormatError:
()
()
( * )
crypto_imports = []
(pe, ):
entry pe.DIRECTORY_ENTRY_IMPORT:
dll = entry.dll.decode(, errors=)
imp entry.imports:
imp.name:
name = imp.name.decode(, errors=)
name CRYPTO_APIS:
desc = CRYPTO_APIS[name]
crypto_imports.append((dll, name, desc))
()
crypto_imports:
()
()
crypto_imports
():
(filepath, ) f:
data = f.read()
()
( * )
offset = data.find(AES_SBOX)
offset != -:
()
offset = data.find(CHACHA20_CONSTANT)
offset != -:
()
rsa_markers = [
,
,
,
]
marker rsa_markers:
offset = data.find(marker)
offset != -:
()
re
ext_pattern = re.(, re.IGNORECASE)
extensions = ()
ext_pattern.finditer(data):
ext = .group().decode(, errors=).lower()
target_exts = [
, , , , , ,
, , , , , ,
]
ext target_exts:
extensions.add(ext)
extensions:
()
__name__ == :
(sys.argv) < :
()
sys.exit()
analyze_imports(sys.argv[])
find_crypto_constants(sys.argv[])
Step 2: Analyze Encryption Flow
def analyze_encryption_pattern(filepath):
"""Analyze file encryption patterns from ransomware artifacts."""
import os
import struct
with open(filepath, 'rb') as f:
data = f.read()
file_size = len(data)
print(f"\n[+] Encrypted File Analysis: {filepath}")
print(f" Size: {file_size:,} bytes")
tail_sizes = [256, 512, 1024, 2048]
for size in tail_sizes:
if file_size > size + 16:
tail = data[-size:]
entropy = calculate_entropy(tail)
if entropy > 7.5:
print(f" Possible encrypted key ({size} bytes) "
f"at end of file (entropy: {entropy:.2f})")
header = data[:64]
print(f" First 16 bytes: {header[:16].hex()}")
known_headers = {
: ,
: ,
: ,
: ,
: ,
}
magic, ftype known_headers.items():
header.startswith(magic):
()
:
()
():
collections Counter
math
data:
freq = Counter(data)
length = (data)
entropy = -(
(count / length) * math.log2(count / length)
count freq.values()
)
entropy
Validation Criteria
- Cryptographic algorithms identified (AES, RSA, ChaCha20, etc.)
- Key size and mode of operation determined
- Key generation method analyzed for potential weaknesses
- Per-file key encryption scheme documented
- File targeting patterns and extension list extracted
- Embedded public keys extracted for infrastructure correlation
- Potential decryption opportunities assessed
References