The interface is localized. Skill descriptions and documents are machine-translated by AI into your language; code, commands, paths and technical terms stay in the original, and the author's document governs.
Explore skills
Productivity · SKILL.md

reverse-engineering-ransomware-encryption-routine

reverse-engineering-ransomware-encryption-routine

对勒索软件加密例程进行逆向工程,以识别密码学算法、密钥生成缺陷,以及通过静态和动态分析挖掘潜在的解密机会。

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill documentation

GitHub

name: reverse-engineering-ransomware-encryption-routine description: 对勒索软件加密例程进行逆向工程,以识别密码学算法、密钥生成缺陷,以及通过静态和动态分析挖掘潜在的解密机会。 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

对勒索软件加密例程进行逆向工程

概述

现代勒索软件使用混合加密方案,将对称算法(AES-256-CBC/CTR、ChaCha20、Salsa20)用于文件加密,将非对称算法(RSA-2048/4096、Curve25519)用于密钥保护。加密例程通常为每个文件生成一个随机对称密钥,加密文件内容,然后用攻击者内嵌的公钥加密对称密钥。对这些例程进行逆向工程,可以识别具体算法、密钥派生方法、初始化向量(IV)、文件定向模式,以及可能在不支付赎金的情况下实现解密的实现缺陷。典型案例包括 Rhysida(AES-256-CTR + RSA-4096)、Qilin.B(带 AES-NI 的 AES-256-CTR 或 ChaCha20 回退)和 Medusa(AES-256 + RSA)。

前置条件

  • IDA Pro 或 Ghidra,用于静态反汇编
  • x64dbg/WinDbg,用于动态调试
  • Python 3.9+,安装 pycryptodome、pefile
  • 理解 AES、RSA、ChaCha20、Curve25519 算法
  • 了解 Windows CryptoAPI 和 CNG(BCrypt)函数
  • 用于安全执行的沙箱环境

核心概念

混合加密模型

勒索软件为每个文件生成唯一的 AES 密钥和 IV。文件内容使用该对称密钥加密。对称密钥再用攻击者的 RSA 公钥(内嵌于二进制文件中或从 C2 获取)加密。加密后的密钥追加或前置到加密后的文件中。只有持有 RSA 私钥的攻击者才能解密每个文件的对称密钥。

密码学 API 识别

Windows 勒索软件通常使用 CryptoAPI(CryptAcquireContext、CryptGenKey、CryptEncrypt)或 CNG(BCryptGenerateSymmetricKey、BCryptEncrypt)。部分使用 OpenSSL 或自定义实现。识别这些 API 调用可立即获取算法、密钥大小和操作模式的信息。

实现缺陷

解密机会来自:硬编码加密密钥、密钥生成使用弱伪随机数生成器(PRNG)(以 GetTickCount 或 time() 为种子)、跨文件复用 IV、使用 ECB 模式、加密后密钥仍留在内存中,以及在加密过程中可捕获密钥的竞争条件。

实践步骤

步骤 1:识别密码学函数

#!/usr/bin/env python3
"""识别勒索软件 PE 文件中的密码学函数。"""
import pefile
import sys

CRYPTO_APIS = {
    # Windows CryptoAPI
    "CryptAcquireContextA": "CryptoAPI 上下文获取",
    "CryptAcquireContextW": "CryptoAPI 上下文获取",
    "CryptGenKey": "密钥生成",
    "CryptDeriveKey": "密钥派生",
    "CryptEncrypt": "加密操作",
    "CryptDecrypt": "解密操作",
    "CryptImportKey": "密钥导入(公钥?)",
    "CryptExportKey": "密钥导出",
    "CryptGenRandom": "随机数生成",
    "CryptCreateHash": "哈希创建",
    "CryptHashData": "哈希操作",
    # Windows CNG(BCrypt)
    "BCryptOpenAlgorithmProvider": "CNG 算法初始化",
    "BCryptGenerateSymmetricKey": "CNG 对称密钥生成",
    "BCryptEncrypt": "CNG 加密",
    "BCryptDecrypt": "CNG 解密",
    "BCryptGenerateKeyPair": "CNG 密钥对生成",
    "BCryptImportKeyPair": "CNG 密钥导入",
    # OpenSSL
    "EVP_EncryptInit_ex": "OpenSSL 加密初始化",
    "EVP_EncryptUpdate": "OpenSSL 加密更新",
    "EVP_EncryptFinal_ex": "OpenSSL 加密完成",
    "RSA_public_encrypt": "OpenSSL RSA 加密",
    "AES_set_encrypt_key": "OpenSSL AES 密钥设置",
    # 文件操作
    "CreateFileW": "文件打开(目标文件)",
    "ReadFile": "文件读取(加密前)",
    "WriteFile": "文件写入(加密后)",
    "FindFirstFileW": "文件枚举(目标定向)",
    "FindNextFileW": "文件枚举",
    "MoveFileW": "文件重命名(扩展名更改)",
    "DeleteFileW": "文件删除(原始文件)",
}

AES_SBOX = bytes([
    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
    0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
])

CHACHA20_CONSTANT = b"expand 32-byte k"


def analyze_imports(filepath):
    """分析 PE 导入表中的密码学 API。"""
    try:
        pe = pefile.PE(filepath)
    except pefile.PEFormatError:
        print("[-] 非有效 PE 文件")
        return

    print("[+] 密码学 API 分析")
    print("=" * 60)

    crypto_imports = []
    if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
        for entry in pe.DIRECTORY_ENTRY_IMPORT:
            dll = entry.dll.decode('utf-8', errors='replace')
            for imp in entry.imports:
                if imp.name:
                    name = imp.name.decode('utf-8', errors='replace')
                    if name in CRYPTO_APIS:
                        desc = CRYPTO_APIS[name]
                        crypto_imports.append((dll, name, desc))
                        print(f"  [{dll}] {name}: {desc}")

    if not crypto_imports:
        print("  导入表中未发现已知密码学 API")
        print("  恶意软件可能使用自定义实现或动态加载")

    return crypto_imports


def find_crypto_constants(filepath):
    """搜索内嵌的密码学常量。"""
    with open(filepath, 'rb') as f:
        data = f.read()

    print("\n[+] 密码学常量搜索")
    print("=" * 60)

    # AES S-Box
    offset = data.find(AES_SBOX)
    if offset != -1:
        print(f"  AES S-Box 位于偏移量 0x{offset:x}")

    # ChaCha20/Salsa20 常量
    offset = data.find(CHACHA20_CONSTANT)
    if offset != -1:
        print(f"  ChaCha20 常量位于偏移量 0x{offset:x}")

    # RSA 公钥标记
    rsa_markers = [
        b'-----BEGIN PUBLIC KEY-----',
        b'-----BEGIN RSA PUBLIC KEY-----',
        b'\x30\x82',  # ASN.1 SEQUENCE
    ]
    for marker in rsa_markers:
        offset = data.find(marker)
        if offset != -1:
            print(f"  RSA 密钥标记位于偏移量 0x{offset:x}")

    # 常见勒索软件文件扩展名模式
    import re
    ext_pattern = re.compile(rb'\.\w{3,10}(?=\x00)', re.IGNORECASE)
    extensions = set()
    for match in ext_pattern.finditer(data):
        ext = match.group().decode('ascii', errors='replace').lower()
        target_exts = [
            '.doc', '.docx', '.xls', '.xlsx', '.pdf', '.ppt',
            '.jpg', '.png', '.sql', '.mdb', '.bak', '.zip',
        ]
        if ext in target_exts:
            extensions.add(ext)

    if extensions:
        print(f"\n  目标文件扩展名: {', '.join(sorted(extensions))}")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <勒索软件样本>")
        sys.exit(1)

    analyze_imports(sys.argv[1])
    find_crypto_constants(sys.argv[1])

步骤 2:分析加密流程

def analyze_encryption_pattern(filepath):
    """从勒索软件产物分析文件加密模式。"""
    import os
    import struct

    with open(filepath, 'rb') as f:
        data = f.read()

    file_size = len(data)
    print(f"\n[+] 加密文件分析: {filepath}")
    print(f"  大小: {file_size:,} 字节")

    # 检查追加的密钥材料(常见模式)
    # 许多勒索软件家族在文件末尾追加加密后的密钥
    tail_sizes = [256, 512, 1024, 2048]  # 常见 RSA 密文大小
    for size in tail_sizes:
        if file_size > size + 16:
            tail = data[-size:]
            # 高熵值表明为加密数据
            entropy = calculate_entropy(tail)
            if entropy > 7.5:
                print(f"  文件末尾可能存在加密密钥({size} 字节),"
                      f"熵值: {entropy:.2f}")

    # 检查头部修改
    # 许多勒索软件会前置元数据
    header = data[:64]
    print(f"  前 16 字节: {header[:16].hex()}")

    # 检查原始文件头是否被保留
    known_headers = {
        b'PK': 'ZIP/Office',
        b'\x89PNG': 'PNG',
        b'\xff\xd8\xff': 'JPEG',
        b'%PDF': 'PDF',
        b'\xd0\xcf\x11\xe0': 'OLE(DOC/XLS)',
    }
    for magic, ftype in known_headers.items():
        if header.startswith(magic):
            print(f"  原始格式已保留: {ftype}")
            break
    else:
        print("  原始文件头已被销毁/加密")


def calculate_entropy(data):
    """计算数据的香农熵。"""
    from collections import Counter
    import math

    if not data:
        return 0

    freq = Counter(data)
    length = len(data)
    entropy = -sum(
        (count / length) * math.log2(count / length)
        for count in freq.values()
    )
    return entropy

验证标准

  • 识别密码学算法(AES、RSA、ChaCha20 等)
  • 确定密钥大小和操作模式
  • 分析密钥生成方法中的潜在弱点
  • 记录每个文件的密钥加密方案
  • 提取文件定向模式和扩展名列表
  • 提取内嵌公钥用于基础设施关联
  • 评估潜在解密机会

参考资料

Saved skills