3. 固件加密与解密初步
任务目标
分析一段未知固件,判断其是否经过加密或压缩处理,并尝试使用常见工具(如 binwalk、firmware-mod-kit)或已知密钥进行解密/解包,最终提取出可识别的文件系统内容。
环境准备
在 Linux 虚拟机中安装以下工具(以 Ubuntu/Debian 为例):
sudo apt update
sudo apt install -y binwalk firmware-mod-kit unzip
固件样本特征
本案例使用一个模拟固件 sample_fw.bin,其构造方式为:先使用 AES-128-ECB 加密一个包含 squashfs 文件系统的镜像,再在头部添加 16 字节自定义头(含魔数 FWENC 和加密标志)。该样本用于演示加密固件的识别与解密流程。
识别加密固件
首先使用 binwalk 扫描固件,观察输出特征:
binwalk sample_fw.bin
预期输出中不会直接出现 squashfs 或 filesystem 等明文标识,而是显示高熵数据段或未知数据。此时可进一步检查文件头:
xxd sample_fw.bin | head -5
若头部出现非标准魔数(非 U-Boot、TRX、HDR0 等常见格式),且熵值较高,则高度怀疑固件已加密。
解密与解包实现
以下 Python 脚本演示了如何识别自定义头、提取密文并使用已知密钥解密,然后通过 binwalk 识别解包后的文件系统:
import struct
from Crypto.Cipher import AES
# 已知密钥(来自固件开发文档或硬编码分析)
KEY = b'0123456789abcdef' # 16字节密钥
def decrypt_firmware(input_file, output_file):
with open(input_file, 'rb') as f:
data = f.read()
# 检查自定义头
if data[:4] != b'FWENC':
print("[-] 未识别加密标志,可能未加密")
return False
# 解析头部:4字节魔数 + 4字节加密标志 + 8字节原始长度
magic, enc_flag, orig_len = struct.unpack('<4sIQ', data[:16])
print(f"[+] 魔数: {magic}, 加密标志: {enc_flag}, 原始长度: {orig_len}")
if enc_flag != 1:
print("[-] 加密标志为0,固件未加密")
return False
# 提取密文(从偏移16开始)
ciphertext = data[16:]
# AES-128-ECB 解密
cipher = AES.new(KEY, AES.MODE_ECB)
# 补齐到16字节倍数
pad_len = 16 - (len(ciphertext) % 16)
if pad_len != 16:
ciphertext += b'\x00' * pad_len
plaintext = cipher.decrypt(ciphertext)
# 截断到原始长度
plaintext = plaintext[:orig_len]
with open(output_file, 'wb') as f:
f.write(plaintext)
print(f"[+] 解密完成,输出: {output_file}")
return True
if __name__ == '__main__':
decrypt_firmware('sample_fw.bin', 'decrypted_fw.bin')
运行与验证
- 生成模拟固件(仅用于本案例复现):
# 创建一个小型squashfs镜像(需root)
mkdir rootfs
echo "test file" > rootfs/test.txt
mksquashfs rootfs rootfs.sqsh
# 加密并添加头
python3 -c "
from Crypto.Cipher import AES
import struct
with open('rootfs.sqsh', 'rb') as f:
data = f.read()
key = b'0123456789abcdef'
cipher = AES.new(key, AES.MODE_ECB)
pad_len = 16 - (len(data) % 16)
if pad_len != 16:
data += b'\x00' * pad_len
enc = cipher.encrypt(data)
header = struct.pack('<4sIQ', b'FWENC', 1, len(data))
with open('sample_fw.bin', 'wb') as f:
f.write(header + enc)
print('sample_fw.bin 生成完成')
"
- 运行解密脚本:
python3 decrypt_firmware.py
- 使用
binwalk验证解密结果:
binwalk decrypted_fw.bin
通过条件:binwalk 输出中能识别出 Squashfs filesystem 标记,且解包后能读取到 test.txt 文件内容。
常见问题
- 密钥未知:若密钥未知,可尝试在固件中搜索硬编码密钥(
strings命令),或使用firmware-mod-kit的extract-firmware.sh脚本自动尝试常见解包方式。 - 非 ECB 模式:若为 CBC 模式,需额外提取 IV(通常位于头部或密文前 16 字节),修改脚本中
AES.new(key, AES.MODE_CBC, iv)即可。 - 压缩而非加密:若
binwalk显示gzip或lzma标记,则属于压缩固件,直接使用binwalk -e即可自动解压。