计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
re-fw-extract【效率与协作】固件提取与解包:binwalk/unblob、magic 扫描、字节序。 触发词:固件、binwalk、解包固件、firmware、IoT、MCU、8051、AVR、PIC、MSP430、Intel HEX、.hex
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
所有工具先验证再使用。解包与 magic 扫描是纯静态分析,可免沙箱([[re-analyze/platform-tips]] 最高原则);解出产物要运行时转 [[re-fw-emulate]]。
binwalk 有两条并存的产品线,装前先分辨:v3(Rust 重写)是 upstream 当前主线,v2(原 Python 实现)属 legacy,两者的参数集合与模块支持不同。
cargo install binwalk / 源码构建。upstream 已不再把 pip 当作安装入口binwalk 包停在 2.1.0(2015-01),各发行版仓库包同属 2.x 线(Debian trixie 2.4.3、bookworm 2.3.4)
apt install binwalk(Debian/Ubuntu)/ dnf install binwalk / pacman -S binwalkpip install binwalkbrew install binwalkbinwalk --version——使用前先确认 major。本技能的命令示例(-e / -M / -E)在 v2 与 v3 均保留;需要 v3 的其它参数时按实际版本查 binwalk --helppip install unblob(依赖较多,建议 venv: python3 -m venv venv && venv/bin/pip install unblob)unblob --versiondd --versionapt install bsdmainutils(Debian/Ubuntu)/ dnf install util-linux(Fedora/RHEL,含 hexdump)hexdump -C /dev/null(无报错即可用;macOS 版无 --version)git clone https://github.com/devttys0/sasquatch,需 apt install zlib1g-dev liblzma-dev build-essential 后 make)sasquatch -h 输出用法(编译产物在仓库子目录,需加入 PATH)按顺序执行,每步记下结果。
自动解包(unblob 优先,binwalk 兜底):
unblob firmware.bin # 更准,自动识别 50+ 容器格式并递归解包
# 或 binwalk:
binwalk firmware.bin # 先列出签名与偏移
binwalk -Me firmware.bin # -M 递归 -e 提取
产物:firmware.bin/(unblob)或 _firmware.bin.extracted/(binwalk)目录。解出的文件系统转 [[re-fw-rootfs]],ELF 转 [[re-binary-core]]。
magic 手工扫描(自动解包不全时):
hexdump -C firmware.bin | head -40
# 或按 binwalk 报告的偏移核对:
dd if=firmware.bin bs=1 skip=<偏移> count=16 | hexdump -C
常见魔数:JPEG FF D8 FF、gzip 1F 8B、squashfs hsqs、cramfs 45 3D CD 28(小端,大端反序)、U-Boot 27 05 19 56、jffs2 85 19、ELF 7F 45 4C 46。识别出一个就按该格式处理。
字节序判断:
file firmware.bin # 输出含 LSB/MSB 提示
readelf -h <解出的ELF> # Machine 字段 + Data 字段(大小端)
strings firmware.bin | head # 可读串确认字节序
大端 ARM/MIPS 固件常见:大端时魔数与字符串按大端编码(如 hsqs 反序出现);确认后整个流程按该字节序进行。
嵌套容器逐层解:
binwalk -Me 会自动递归,但嵌套(tar 里再 zip、自定义头包着 gzip)常中途断file 确认内层类型 → 用对应工具(tar/gzip 系统自带;squashfs 用 sasquatch;其他用 [[re-fw-rootfs]] 工具准备的 7z/unsquashfs)再解,直到出现文件系统或 ELFIEND、JPEG FFD9)等格式的结束标记之后常附加容器/压缩流(解析器读到结束标记即停,附加数据对正常查看不可见)——file 会把整文件报成图片。定结束标记位置不能靠裸字节 first/last 搜索(IEND 字样可出现在 tEXt chunk 载荷内、FF D9 可出现在 JPEG 的 APP/COM 段内,首个/末个命中都可能是假标记):PNG 从 8 字节签名起按 Length/Type/Data/CRC 遍历到结构合法且长度为 0 的 IEND,JPEG 从 SOI 起按 marker/segment 解析、SOS 后按 FF00 stuffing 与 RSTn 处理,取语法位置成立的 EOI;用解析出的真实结尾偏移去切附加数据(裸搜结果只作候选)PK\x03\x04(4 字节被剥)——用字段自洽验证:补上签名后 version(常见 20/45)、mod date(年 1980+)、compressed/uncompressed size(与 EOCD/中央目录条目一致)全部合理,且 EOCD 在尾部完好 → 补 PK\x03\x04 前缀即完整可解(unzip 报 "missing 4 bytes" 或 zipfile OSError: Invalid argument 是典型征兆)自动失败时手工切分(dd 按偏移):
binwalk firmware.bin # 找内嵌文件偏移
dd if=firmware.bin of=part1.bin bs=1 skip=<偏移1> count=<长度1>
dd if=firmware.bin of=part2.bin bs=1 skip=<偏移2>
file part*.bin # 每块验证
厂商自定义头最常见:跳过头部 N 字节后才是标准格式(先 hexdump 目测头长度再切)。
file 报 data/unknown;strings 无操作系统与库特征串(无 "libc"、无 RTOS 内核名);镜像开头低地址处是短跳转/向量数据而非可读头:LLAAAATT<数据><校验和>——LL 数据长度、AAAA 段内地址、TT 记录类型(00 数据 / 01 结束 / 02·04 扩展地址 / 03·05 起始地址)、末字节校验和
file + readelf -h 确认字节序(步骤 3),后续解包/分析全程保持一致file 报 data;原因——签名误报或切分偏移错位;对策——每个产物 file + 看头 16 字节验证 magic,无效即重试偏移.jpg 报 PNG、.so 报 tar、.c 报 XZ;原因——作者故意用无关扩展名(隐写/套娃/免检场景常见);对策——永远以 file/魔数为准,扩展名只当线索;file 输出带 "with extra data prepended" 等提示时直接照做unzip 报 "missing 4 bytes"/"invalid zip with overlapped components"(zip bomb 误报)或 Python zipfile OSError: [Errno 22] Invalid argument;原因——本地文件头缺 PK\x03\x04 签名,或数据前有前缀垃圾;对策——先 unzip -l 看能否列出(能列出说明 EOCD/中央目录完好),补签名(步骤 4)或用 UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE 强制rbe_utok_check 定位校验逻辑:标志位 UTOK[0x298]==1 才启动调试能力(厂家默认 FF 不启动),且 DCI 开放受多层校验链控制(boot_mode==2、boot_cfg 解析、CT handler 门控、FPF Debug Auth 等),单改标志位不够;定位技巧:ME 运行 base 是 0x4000,字符串偏移按此换算num_records(偏移 +0x06 的 uint16)无校验,record 数超 100 覆写栈 cookie/返回地址),ROP 却打不通;原因——ME 的 cookie 由 ROM(mask ROM 不可提取)在 SRAM 预填充进程上下文表生成,无法像 TXE 平台那样用 TLS 绕过;对策——先确认目标平台 cookie 来源(ROM 生成则溢出利用受限),完整逆向认证链路(UTOK→boot_cfg→CT handler 多层校验)后找非溢出路径mask = block[0]、plain[i] = ROR8(packed[i], n) XOR mask(mask 字节自身不参与变换,i 从 1 起));对策——先用强 crib(向量表 SRAM 栈指针/Thumb Reset Vector)约束恢复首块,再验证模型