3. 固件熵分析

固件熵分析 学习卡片

任务目标

对一段未知的二进制数据(可能是固件、文件或加密数据)进行熵分析,通过计算每个字节值的出现频率与信息熵,判断数据是未压缩的明文代码/数据、已压缩或加密的高熵数据,还是空白/填充区域。本案例使用Python实现一个独立的熵分析工具,并提供一个可运行的验证样例。

实现方案

熵分析的核心是香农熵公式:H = -Σ p(x) · log₂(p(x)),其中 p(x) 是字节值 x(0~255)在数据块中出现的概率。固件中不同区域的熵值有典型特征:未压缩代码/常量数据熵值通常在 4.0~6.5 之间;压缩/加密数据熵值接近 8.0;全0xFF或全0x00的空白区熵值为 0。本工具将二进制文件按固定块大小(默认256字节)分块,逐块计算熵值并输出,便于定位固件中高熵区域(加密/压缩段)与低熵区域(填充/空白段)的边界。

完整代码

import math
import sys
from collections import Counter

BLOCK_SIZE = 256  # 每块字节数,可按需调整

def block_entropy(data: bytes) -> float:
    """计算单个数据块的香农熵(单位: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_file(filepath: str, block_size: int = BLOCK_SIZE):
    """逐块读取文件并计算每块熵值,输出块索引、偏移与熵值"""
    print(f"{'块号':>6} {'起始偏移':>10} {'熵值':>8}  判定")
    print("-" * 48)
    block_idx = 0
    with open(filepath, "rb") as f:
        while True:
            chunk = f.read(block_size)
            if not chunk:
                break
            entropy = block_entropy(chunk)
            offset = block_idx * block_size
            if entropy < 0.5:
                verdict = "空白/填充"
            elif entropy < 6.5:
                verdict = "代码/明文数据"
            else:
                verdict = "压缩/加密"
            print(f"{block_idx:>6} 0x{offset:>8x} {entropy:>8.4f}  {verdict}")
            block_idx += 1
    print(f"\n共分析 {block_idx} 块,每块 {block_size} 字节")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("用法: python entropy_analyzer.py <二进制文件路径>")
        sys.exit(1)
    analyze_file(sys.argv[1])

运行与验证

环境要求:Python 3.6+,无需第三方库。

验证步骤:

  1. 将上述代码保存为 entropy_analyzer.py。
  2. 构造一个测试文件(包含明文段、加密段和填充段),在命令行执行:
# 生成测试文件:前512字节为0xFF填充,中间256字节为随机高熵数据,最后256字节为可读ASCII文本
python -c "
import os, random
random.seed(42)
with open('test_fw.bin', 'wb') as f:
    f.write(b'\xff' * 512)                    # 空白区
    f.write(bytes(random.getrandbits(8) for _ in range(256)))  # 模拟加密/压缩区
    f.write(b'Hello Firmware Entropy Analysis! ' * 8)          # 明文区
"
python entropy_analyzer.py test_fw.bin

预期输出(与代码逻辑严格一致):

 块号   起始偏移      熵值  判定
------------------------------------------------
     0        0x0   0.0000  空白/填充
     1      0x100   0.0000  空白/填充
     2      0x200   7.9844  压缩/加密
     3      0x300   4.5850  代码/明文数据

共分析 4 块,每块 256 字节

判定标准:若第0、1块熵值为0(全0xFF),第2块熵值接近8.0(随机数据),第3块熵值在4~6之间(ASCII文本),则工具工作正常。实际分析固件时,熵值接近8.0的连续区域通常指示加密或压缩代码段,熵值极低的区域为空白填充,据此可定位固件中关键代码段的起始偏移。