4. 固件打包与重打包
任务说明
本案例以典型嵌入式设备固件(基于 CPIO 归档 + gzip 压缩的 Linux 内核 initramfs)为例,演示固件解包、修改、重打包的完整流程。目标是在修改固件内文件后,生成一个结构合法、可被设备引导加载程序接受的固件镜像。案例不涉及签名绕过或加密固件,仅针对未签名/明文固件的打包格式还原。
环境与依赖
- Linux 环境(或 WSL),需具备
binwalk、cpio、gzip、file工具 - 安装:
sudo apt install binwalk cpio gzip file - 示例固件:
firmware.bin(由本案例脚本生成,用于验证流程)
固件结构识别
首先使用 binwalk 扫描固件,确认内部文件系统类型与偏移位置:
binwalk firmware.bin
典型输出会显示 gzip 压缩数据起始偏移(例如 0x100)。以下脚本自动完成从识别到重打包的全过程。
关键完整代码
将以下脚本保存为 repack.sh,并赋予执行权限(chmod +x repack.sh):
#!/bin/bash
# 固件解包-修改-重打包脚本(适用于 CPIO+gzip 格式)
set -e
FIRMWARE="firmware.bin"
WORKDIR="fw_work"
MODIFY_FILE="etc/config.txt" # 要修改的文件路径(相对于根目录)
MODIFY_CONTENT="version=2.0" # 新内容
# 1. 清理并创建工作目录
rm -rf "$WORKDIR"
mkdir -p "$WORKDIR"
cd "$WORKDIR"
# 2. 使用 binwalk 定位 gzip 偏移并解压
binwalk -e "../$FIRMWARE" > /dev/null 2>&1
GZ_DIR=$(find . -type d -name "_*" | head -1)
if [ -z "$GZ_DIR" ]; then
echo "错误:未找到压缩段,请检查固件格式"
exit 1
fi
# 3. 解压 gzip 得到 cpio 归档
cd "$GZ_DIR"
gzip -d -k *.gz 2>/dev/null || true
CPIO_FILE=$(ls | grep -v '\.gz$' | head -1)
if [ -z "$CPIO_FILE" ]; then
echo "错误:未找到 CPIO 归档"
exit 1
fi
# 4. 解包 cpio 到根目录
mkdir -p rootfs
cd rootfs
cpio -idmv < "../$CPIO_FILE" > /dev/null 2>&1
# 5. 修改目标文件
if [ -f "$MODIFY_FILE" ]; then
echo "$MODIFY_CONTENT" > "$MODIFY_FILE"
echo "已修改 $MODIFY_FILE"
else
echo "警告:$MODIFY_FILE 不存在,创建新文件"
mkdir -p "$(dirname "$MODIFY_FILE")"
echo "$MODIFY_CONTENT" > "$MODIFY_FILE"
fi
# 6. 重新打包 cpio(使用 newc 格式,保持权限)
find . | cpio -o -H newc > "../new_initramfs.cpio" 2>/dev/null
# 7. 重新压缩为 gzip
cd ..
gzip -9 -c new_initramfs.cpio > new_initramfs.cpio.gz
# 8. 重组固件(保留原头部偏移)
cd ..
# 获取原固件头部长度(binwalk 显示的偏移值)
HEADER_LEN=$(binwalk "../$FIRMWARE" | grep gzip | head -1 | awk '{print $1}')
if [ -z "$HEADER_LEN" ]; then HEADER_LEN=0; fi
# 提取原头部并拼接新固件
dd if="../$FIRMWARE" of=header.bin bs=1 count=$HEADER_LEN 2>/dev/null
cat header.bin "$GZ_DIR/new_initramfs.cpio.gz" > "../firmware_repacked.bin"
echo "完成:firmware_repacked.bin 已生成"
echo "验证:file ../firmware_repacked.bin"
运行与验证
- 生成测试固件(仅用于验证流程):
mkdir -p test_root/etc echo "version=1.0" > test_root/etc/config.txt cd test_root find . | cpio -o -H newc | gzip -9 > ../firmware.bin cd .. - 执行重打包脚本:
chmod +x repack.sh ./repack.sh - 验证重打包结果:
# 检查文件类型 file firmware_repacked.bin # 应输出:gzip compressed data # 解包验证修改是否生效 binwalk -e firmware_repacked.bin find _* -name "config.txt" -exec cat {} \; # 应输出:version=2.0
通过条件
file命令识别新固件为 gzip 压缩数据,且头部偏移与原固件一致- 重新解包后,
etc/config.txt内容为version=2.0,证明修改已正确写入 - 固件整体结构完整,设备引导加载程序可正常解析(若设备支持未签名固件)
常见问题
- binwalk 未识别压缩段:固件可能使用 LZMA/LZ4 等其他压缩,需调整解压命令
- cpio 格式不匹配:部分固件使用旧版 binary 格式,将
-H newc改为-H bin重试 - 权限丢失:重打包前确认
cpio命令在 rootfs 目录内执行,且文件属主为当前用户