4. 固件加密检测与识别
任务目标
给定一个未知固件镜像文件,通过熵分析、字符串搜索等方法判断其是否经过加密或压缩处理,并在判定为加密后尝试识别可能的加密算法类型。本案例以典型的嵌入式固件(如U-Boot、RTOS镜像)为分析对象,输出可复现的检测流程与判定结论。
环境与依赖
- Python 3.8+,需安装
numpy(熵计算)与binwalk(可选,用于辅助文件签名扫描) - 示例固件:自行构造或使用真实固件,本案例使用一个模拟加密的二进制文件作为输入
核心实现
以下代码实现三个核心功能:分块熵计算、字符串可打印性检测、常见加密算法特征匹配。输入为固件文件路径,输出为判定结果与可能的算法候选。
import math
import re
import struct
from collections import Counter
def calculate_entropy(data: bytes) -> float:
"""计算字节序列的香农熵"""
if not data:
return 0.0
freq = Counter(data)
entropy = -sum((count / len(data)) * math.log2(count / len(data)) for count in freq.values())
return entropy
def block_entropy_analysis(data: bytes, block_size: int = 4096) -> list:
"""分块计算熵值,返回每块的熵列表"""
entropies = []
for i in range(0, len(data), block_size):
block = data[i:i+block_size]
if len(block) < 64: # 忽略过小的尾部块
continue
entropies.append(calculate_entropy(block))
return entropies
def printable_string_ratio(data: bytes) -> float:
"""计算可打印ASCII字符串占比(长度≥4的连续可打印字符)"""
printable_chars = set(bytes(range(0x20, 0x7f)))
strings = re.findall(rb'[\x20-\x7e]{4,}', data)
total_string_len = sum(len(s) for s in strings)
return total_string_len / len(data) if data else 0.0
def detect_encryption_patterns(data: bytes) -> list:
"""检测常见加密/压缩算法特征"""
candidates = []
# AES: 查找可能的S盒特征(不精确,仅作提示)
if b'\x63\x7c\x77\x7b\xf2\x6b\x6f\xc5' in data[:4096]:
candidates.append('AES (S-box pattern found in header)')
# XOR: 检测重复密钥长度(通过周期性自相关简单判断)
if len(data) > 1024:
sample = data[:1024]
best_period = 0
best_score = 0
for period in range(2, 65):
score = 0
for i in range(period, len(sample)):
if sample[i] == sample[i - period]:
score += 1
if score > best_score:
best_score = score
best_period = period
if best_period > 0 and best_score / len(sample) > 0.6:
candidates.append(f'Possible XOR with key length {best_period}')
# LZMA/gzip 压缩特征
if data[:6] == b'\xfd7zXZ\x00':
candidates.append('XZ/LZMA compressed')
elif data[:2] == b'\x1f\x8b':
candidates.append('gzip compressed')
elif data[:4] == b'\x28\xb5\x2f\xfd':
candidates.append('zstd compressed')
return candidates
def analyze_firmware(filepath: str) -> dict:
"""主分析函数:返回判定结果"""
with open(filepath, 'rb') as f:
data = f.read()
result = {
'file_size': len(data),
'overall_entropy': calculate_entropy(data),
'block_entropies': [],
'printable_ratio': 0.0,
'is_encrypted': False,
'likely_algorithm': [],
'notes': []
}
# 1. 整体熵判断
overall_ent = result['overall_entropy']
if overall_ent > 7.5:
result['is_encrypted'] = True
result['notes'].append('High overall entropy suggests encryption or compression')
elif overall_ent < 5.0:
result['notes'].append('Low entropy: likely plaintext or lightly structured data')
else:
result['notes'].append('Medium entropy: further analysis required')
# 2. 分块熵分析(检测是否均匀高熵)
block_ents = block_entropy_analysis(data)
result['block_entropies'] = block_ents
if block_ents:
avg_block_ent = sum(block_ents) / len(block_ents)
if avg_block_ent > 7.2 and max(block_ents) - min(block_ents) < 0.5:
result['is_encrypted'] = True
result['notes'].append('Uniform high block entropy: consistent with encryption')
# 3. 字符串检测
printable_ratio = printable_string_ratio(data)
result['printable_ratio'] = printable_ratio
if printable_ratio < 0.05 and result['is_encrypted']:
result['notes'].append('Very few printable strings, consistent with encrypted payload')
elif printable_ratio > 0.3:
result['is_encrypted'] = False
result['notes'].append('High printable ratio: likely plaintext firmware')
# 4. 算法特征匹配
if result['is_encrypted']:
result['likely_algorithm'] = detect_encryption_patterns(data)
if not result['likely_algorithm']:
result['likely_algorithm'] = ['Unknown: consider AES, ChaCha20, or custom XOR']
return result
if __name__ == '__main__':
import sys
if len(sys.argv) != 2:
print('Usage: python fw_encrypt_detect.py <firmware_file>')
sys.exit(1)
res = analyze_firmware(sys.argv[1])
print(f'File size: {res["file_size"]} bytes')
print(f'Overall entropy: {res["overall_entropy"]:.4f} bits/byte')
print(f'Printable string ratio: {res["printable_ratio"]:.4f}')
print(f'Encrypted: {res["is_encrypted"]}')
if res['likely_algorithm']:
print('Possible algorithms:')
for alg in res['likely_algorithm']:
print(f' - {alg}')
for note in res['notes']:
print(f'Note: {note}')
运行与验证
- 保存上述代码为
fw_encrypt_detect.py - 准备测试固件:
dd if=/dev/urandom of=test_enc.bin bs=1024 count=64(生成随机数据模拟加密固件)
echo "U-Boot 2024.01" > test_plain.bin && dd if=/dev/urandom bs=1 count=2048 >> test_plain.bin(生成含明文头的混合固件) - 运行检测:
python3 fw_encrypt_detect.py test_enc.bin
python3 fw_encrypt_detect.py test_plain.bin
通过条件:
- 对随机数据文件,程序输出
Encrypted: True,整体熵值 > 7.5,可打印字符串占比 < 0.05 - 对含明文头的文件,程序输出
Encrypted: False(因可打印字符串占比高于阈值)或熵值处于中等区间并给出相应说明 - 若固件头部包含AES S盒特征字节,程序能识别出AES候选
判定逻辑说明
熵值接近8.0表示数据接近随机分布,是加密或压缩的强信号;均匀的高分块熵进一步排除局部明文区域。可打印字符串占比是区分明文与密文的直接指标。算法识别基于特征字节匹配与统计模式,对于未知算法只能给出可能性提示,实际算法确认需结合固件加载地址、已知固件格式或硬件加密引擎文档进一步分析。