2. 固件熵分析
任务目标
对固件二进制文件进行分块熵分析,通过熵值分布判断固件整体是否经过加密或压缩,并定位高熵区域(通常对应加密数据或压缩段)与低熵区域(如向量表、字符串、未初始化填充)。
核心原理
熵衡量数据的随机程度。未加密的代码/数据通常熵值在 4.0~6.5 之间;加密或高度压缩的数据熵值接近 8.0;全 0xFF 或 0x00 填充块熵为 0。通过滑动窗口计算每个块的 Shannon 熵,即可从统计特征上识别固件内部结构。
完整实现(Python 3)
import math
import sys
from collections import Counter
BLOCK_SIZE = 256 # 每块字节数,可按需调整(常用 256/512/1024)
def shannon_entropy(data: bytes) -> float:
"""计算一段字节数据的 Shannon 熵(0~8 bit/byte)"""
if not data:
return 0.0
counter = Counter(data)
length = len(data)
entropy = 0.0
for count in counter.values():
p = count / length
entropy -= p * math.log2(p)
return entropy
def analyze_firmware(filepath: str, block_size: int = BLOCK_SIZE):
with open(filepath, 'rb') as f:
firmware = f.read()
total_len = len(firmware)
print(f"文件大小: {total_len} 字节")
print(f"分块大小: {block_size} 字节")
print(f"总块数: {math.ceil(total_len / block_size)}")
print("-" * 60)
# 整体熵
whole_entropy = shannon_entropy(firmware)
print(f"整体熵值: {whole_entropy:.4f} bit/byte")
if whole_entropy > 7.5:
print("判定: 固件整体极可能已加密或强压缩")
elif whole_entropy > 6.8:
print("判定: 固件整体可能部分加密/压缩,或包含大段高随机数据")
else:
print("判定: 固件整体未加密(可能包含压缩段,需结合分块结果)")
print("-" * 60)
# 分块熵统计
high_blocks = [] # 高熵块(>= 7.5)
low_blocks = [] # 低熵块(<= 1.0)
offset = 0
block_idx = 0
while offset < total_len:
chunk = firmware[offset:offset + block_size]
ent = shannon_entropy(chunk)
start = offset
end = min(offset + block_size, total_len) - 1
if ent >= 7.5:
high_blocks.append((start, end, ent))
elif ent <= 1.0:
low_blocks.append((start, end, ent))
# 打印每块熵值(可注释掉以减少输出)
# print(f"块{block_idx:4d} [0x{start:08X}-0x{end:08X}] 熵={ent:.4f}")
offset += block_size
block_idx += 1
# 汇总高/低熵区域
print(f"\n高熵区域(熵≥7.5,疑似加密/压缩): {len(high_blocks)} 块")
for start, end, ent in high_blocks[:20]: # 最多显示前20块
print(f" 0x{start:08X} - 0x{end:08X} 熵={ent:.4f}")
if len(high_blocks) > 20:
print(f" ... 其余 {len(high_blocks)-20} 块略")
print(f"\n低熵区域(熵≤1.0,疑似填充/空数据): {len(low_blocks)} 块")
for start, end, ent in low_blocks[:10]:
print(f" 0x{start:08X} - 0x{end:08X} 熵={ent:.4f}")
if len(low_blocks) > 10:
print(f" ... 其余 {len(low_blocks)-10} 块略")
# 连续高熵区间合并(相邻高熵块合并为一个大区间)
if high_blocks:
merged = []
cur_start, cur_end, cur_max = high_blocks[0]
for start, end, ent in high_blocks[1:]:
if start == cur_end + 1: # 相邻块
cur_end = end
cur_max = max(cur_max, ent)
else:
merged.append((cur_start, cur_end, cur_max))
cur_start, cur_end, cur_max = start, end, ent
merged.append((cur_start, cur_end, cur_max))
print(f"\n合并后的连续高熵区间: {len(merged)} 个")
for start, end, ent in merged:
size_kb = (end - start + 1) / 1024
print(f" 0x{start:08X} - 0x{end:08X} ({size_kb:.1f} KB) 峰值熵={ent:.4f}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("用法: python entropy_analysis.py <固件文件路径>")
sys.exit(1)
analyze_firmware(sys.argv[1])
运行方式
python entropy_analysis.py firmware.bin
无需安装第三方库,仅依赖 Python 3 标准库(math、sys、collections)。
验证方法与判定标准
- 构造已知样本测试:生成一个包含明确高低熵区域的测试文件,验证程序输出与预期一致:
python -c "
import os, random
# 前 1KB 全 0xFF(低熵),中间 2KB 随机字节(高熵),后 1KB 全 0x00(低熵)
data = b'\xff'*1024 + bytes(random.getrandbits(8) for _ in range(2048)) + b'\x00'*1024
with open('test_fw.bin','wb') as f: f.write(data)
print('测试文件已生成: test_fw.bin (4KB)')
"
python entropy_analysis.py test_fw.bin
通过条件:
- 整体熵值应落在 4~6 之间(因包含低熵填充与高熵随机段混合);
- 分块输出中,偏移
0x00000400至0x00000BFF范围内的块熵应 ≥7.5,被标记为高熵区; - 偏移
0x00000000至0x000003FF及0x00000C00至0x00000FFF的块熵应 ≤1.0,被标记为低熵区; - 合并后的连续高熵区间应显示为
0x00000400 - 0x00000BFF,大小约 2.0 KB。
对真实固件执行时,若整体熵值 >7.5 且高熵块占比超过 90%,可判定固件已整体加密;若高熵区呈局部块状分布,则对应固件中的压缩段或加密密钥/签名区域。
常见问题
- 块大小选择:256 字节适合粗粒度扫描;若需精确定位小段高熵数据(如 128 字节的密钥),可改用 64 或 128 字节块,但输出行数会增加。
- 高熵阈值调整:某些压缩算法(如 LZMA)熵值可达 7.9 以上;若固件使用弱加密或编码转换,熵值可能略低(7.0~7.5),可下调阈值至 7.0 重新分析。
- 误报处理:固件中的随机填充(如安全启动签名后的随机 padding)也会产生高熵块,需结合固件基地址和已知结构(如头部偏移)综合判断。