| name | analyzing-ransomware-encryption-mechanisms |
| description | 分析勒索软件家族使用的加密算法、密钥管理和文件加密例程, 评估解密可行性、识别实现上的弱点并支持恢复工作。 涵盖 AES、RSA、ChaCha20 及混合加密方案。 适用于勒索软件密码分析、加密分析、密钥恢复评估或勒索软件解密可行性等请求。
|
| domain | cybersecurity |
| subdomain | malware-analysis |
| tags | ["malware","ransomware","encryption","cryptanalysis","reverse-engineering"] |
| version | 1.0.0 |
| author | mahipal |
| license | Apache-2.0 |
分析勒索软件加密机制
适用场景
- 发生勒索软件感染,恢复工作需要了解所使用的加密方案
- 评估无需支付赎金是否可以解密(实现缺陷、已知解密工具)
- 对勒索软件进行逆向工程,以识别加密算法、密钥派生和密钥存储机制
- 当发现勒索软件密码实现中的弱点时,开发解密工具
- 通过加密方式对勒索软件样本进行分类,将其归属到已知家族
不适用于在未事先用加密文件的测试副本验证解密方法的情况下对生产数据进行恢复操作。
前置条件
- Ghidra 或 IDA Pro,用于对勒索软件二进制文件进行逆向工程
- Python 3.8+,安装
pycryptodome 库用于测试加密/解密例程
- 加密文件样本及其对应的明文原件(已知明文对)
- 访问勒索软件二进制文件(如有必要需先解包)
- 熟悉对称(AES、ChaCha20)和非对称(RSA)密码算法
- NoMoreRansom.org 数据库,用于检查是否存在免费解密工具
工作流程
步骤 1:识别加密算法
确定勒索软件使用的密码算法:
import pefile
pe = pefile.PE("ransomware.exe")
crypto_apis = {
"CryptAcquireContextA": "Windows CryptoAPI",
"CryptAcquireContextW": "Windows CryptoAPI",
"CryptGenKey": "Windows CryptoAPI 密钥生成",
"CryptEncrypt": "Windows CryptoAPI 加密",
"CryptImportKey": "Windows CryptoAPI 密钥导入",
"BCryptOpenAlgorithmProvider": "Windows CNG(现代加密)",
"BCryptEncrypt": "Windows CNG 加密",
"BCryptGenerateKeyPair": "Windows CNG 非对称密钥生成",
}
print("加密 API 导入:")
for entry in pe.DIRECTORY_ENTRY_IMPORT:
for imp in entry.imports:
if imp.name and imp.name.decode() in crypto_apis:
print(f" {entry.dll.decode()} -> {imp.name.decode()}: {crypto_apis[imp.name.decode()]}")
常见勒索软件加密方案:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AES-256-CBC + RSA-2048: 最常见的混合方案(LockBit、REvil、Conti)
AES-256-CTR + RSA-4096: 流密码模式变体(BlackCat/ALPHV)
ChaCha20 + RSA-4096: 现代流密码(Hive、Royal)
Salsa20 + ECDH: Curve25519 密钥交换(Babuk)
AES-128-ECB: 弱模式——可能通过已知明文解密
仅 XOR: 简单加密——始终可恢复
自定义算法: 通常包含实现缺陷
步骤 2:分析密钥生成和管理
逆向工程密钥的生成和存储方式:
勒索软件中的密钥管理模式:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 强(无密钥则无法恢复):
- 使用 CryptGenRandom 为每个文件生成 AES 密钥
- AES 密钥用嵌入的 RSA 公钥加密
- 加密后的密钥附加到每个文件末尾或单独存储
- RSA 私钥仅由攻击者的 C2 服务器持有
2. 弱(可能可以恢复):
- AES 密钥从可预测的种子派生(时间戳、PID)
- 所有文件使用相同的 AES 密钥(破解一个密钥即可完全恢复)
- 加密开始前密钥已传输到 C2(PCAP 可能包含密钥)
- 使用短的重复密钥进行 XOR 加密(可暴力破解)
- PRNG 以 GetTickCount 或 time() 为种子(密钥空间有限)
3. 存在缺陷的实现:
- ECB 模式(保留明文模式)
- 跨文件重用初始化向量(IV)
- 密钥以明文形式存储在内存中(可从内存转储中恢复)
- 部分加密(仅加密前 N 字节)
步骤 3:检查文件加密例程
逆向工程文件处理逻辑:
void encrypt_file(char *filepath) {
if (!is_target_extension(filepath)) return;
BYTE aes_key[32];
CryptGenRandom(hProv, 32, aes_key);
BYTE iv[16];
CryptGenRandom(hProv, 16, iv);
HANDLE hFile = CreateFile(filepath, GENERIC_READ, ...);
BYTE *plaintext = read_entire_file(hFile);
aes_cbc_encrypt(plaintext, file_size, aes_key, iv);
BYTE encrypted_key[256];
rsa_encrypt(aes_key, 32, rsa_pubkey, encrypted_key);
write_file(filepath, encrypted_data, encrypted_key, iv);
rename_file(filepath, strcat(filepath, ".locked"));
}
步骤 4:检查密码学弱点
测试实现中是否存在可利用的缺陷:
from Crypto.Cipher import AES
import os
import struct
def check_key_reuse(file1_enc, file2_enc):
with open(file1_enc, "rb") as f:
data1 = f.read()
with open(file2_enc, "rb") as f:
data2 = f.read()
iv1 = data1[-16:]
iv2 = data2[-16:]
if iv1 == iv2:
print("[!] 检测到相同 IV——可能存在密钥重用")
def brute_force_timestamp_key(encrypted_file, known_header, timestamp_range):
with open(encrypted_file, "rb") as f:
encrypted_data = f.read()
for ts in timestamp_range:
import hashlib
key = hashlib.sha256(str(ts).encode()).digest()
iv = encrypted_data[-16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(encrypted_data[:16])
if decrypted[:len(known_header)] == known_header:
print(f"[!] 找到密钥!时间戳:")
key
():
(encrypted_file, ) f:
data = f.read()
blocks = [data[i:i+] i (, (data), )]
unique = ((blocks))
total = (blocks)
unique < total * :
()
步骤 5:尝试密钥恢复
利用已识别的弱点进行密钥恢复:
def xor_key_recovery(encrypted_file, known_plaintext):
"""从已知明文-密文对恢复 XOR 密钥"""
with open(encrypted_file, "rb") as f:
ciphertext = f.read()
key = bytes(c ^ p for c, p in zip(ciphertext, known_plaintext))
for key_len in range(1, 256):
candidate = key[:key_len]
if all(key[i] == candidate[i % key_len] for i in range(min(len(key), key_len * 4))):
print(f"XOR 密钥(长度 {key_len}):{candidate.hex()}")
return candidate
return None
步骤 6:记录加密分析
将发现整理成结构化报告:
分析应记录:
- 识别的算法(AES、RSA、ChaCha20、自定义)
- 密钥大小和工作模式(CBC、CTR、ECB、GCM)
- 密钥生成方法(CSPRNG、可预测种子、静态密钥)
- 密钥存储位置(附加到文件、注册表、C2 传输)
- 文件修改模式(完整加密、部分加密、仅头部)
- 目标文件扩展名
- 勒索信格式和支付基础设施
- 解密可行性评估(可行/不可行/部分可行)
- 建议的恢复方法
核心概念
| 术语 | 定义 |
|---|
| 混合加密(Hybrid Encryption) | 将对称加密(AES)用于快速文件加密与非对称加密(RSA)用于安全密钥包装相结合;这是勒索软件的标准方法 |
| 密钥包装(Key Wrapping) | 用攻击者的 RSA 公钥加密每个文件的对称密钥,使得只有攻击者的私钥才能解密 |
| ECB 模式 | 电子密码本模式对每个块独立加密;保留明文中的模式,这是一个允许部分恢复的关键弱点 |
| 已知明文攻击(Known-Plaintext Attack) | 利用已知的原始文件及其加密版本来推导加密密钥;对 XOR 和弱流密码有效 |
| 密钥调度(Key Schedule) | 内存中 AES 密钥的扩展形式;可在内存转储中扫描以在密钥被清除前恢复它 |
| CSPRNG | 密码学安全伪随机数生成器;使用 CryptGenRandom 的勒索软件产生不可预测的密钥 |
| 部分加密(Partial Encryption) | 某些勒索软件为提高速度只加密前 N 字节或每第 N 个块;未加密的部分可能有助于恢复 |
工具与系统
- Ghidra:逆向工程套件,用于在汇编级别分析勒索软件加密例程
- PyCryptodome:Python 密码学库,用于实现和测试解密例程
- NoMoreRansom.org:由 Europol 和安全厂商维护的免费解密工具库,针对已知勒索软件家族
- Volatility:内存取证框架,用于从受感染系统的 RAM 转储中提取加密密钥
- CryptoTester:基于常量和代码模式识别密码算法的工具
常见场景
场景:评估勒索软件事件的解密可行性
场景背景:一个组织遭受勒索软件攻击,文件服务器被加密。管理层在做出恢复决策前需要了解是否可以不支付赎金进行解密。
方法:
- 从勒索信、文件扩展名和样本哈希识别勒索软件家族(检查 ID Ransomware)
- 在 NoMoreRansom.org 上检查该家族是否有现成的免费解密工具
- 在 Ghidra 中逆向工程加密例程,识别算法和密钥管理
- 测试实现弱点(密钥重用、可预测种子、ECB 模式)
- 检查事件期间的 PCAP 是否捕获了向 C2 传输的密钥(如果密钥在加密前已发送)
- 扫描受影响机器的内存转储,查找 RAM 中的 AES 密钥调度
- 报告发现:提供解密可行/不可行的具体技术依据
常见陷阱:
- 在加密文件的唯一副本上测试解密方法(始终在副本上操作)
- 假设所有文件使用相同密钥而不加以验证(某些勒索软件使用每文件密钥)
- 未检查卷影副本(vssadmin),勒索软件可能未能删除它们
- 在报告中混淆文件加密算法与密钥包装算法
输出格式
勒索软件加密分析
================================
样本: lockbit3.exe
家族: LockBit 3.0 / LockBit Black
SHA-256: abc123def456...
加密方案
文件密码: AES-256-CTR(每文件唯一密钥)
密钥包装: RSA-2048(公钥嵌入二进制文件中)
密钥生成: CryptGenRandom(CSPRNG——不可预测)
IV 生成: 每文件随机 16 字节
文件结构: [加密数据][RSA加密密钥(256B)][IV(16B)][魔数(8B)]
目标扩展名
总计: 412 个扩展名被目标
类别: 文档(.doc, .xls, .pdf)、数据库(.sql, .mdb)、
压缩包(.zip, .7z)、源代码(.py, .java, .cs)
排除: .exe, .dll, .sys, .lnk(系统文件保留)
实现分析
密钥强度: 强——每文件随机密钥,无重用
模式安全性: 强——CTR 模式带唯一随机数
密钥存储: RSA 加密的密钥附加到每个文件
卷影副本: 已通过 vssadmin 和 WMI 删除
解密可行性
无密钥: 不可能
- 未发现实现缺陷
- RSA-2048 密钥包装防止暴力破解
- CSPRNG 防止密钥预测
- 无现成的免费解密工具
恢复选项
1. 从离线备份恢复(推荐)
2. 检查卷影副本(可能性低——勒索软件会删除它们)
3. 内存取证(如果机器未重启,密钥可能仍在 RAM 中)
4. 与攻击者谈判(最后手段——无解密保证)