深入拆解 usb_burning_tool 刷机包:从固件结构到定制化实战
你有没有遇到过这样的场景?
产线突然反馈一批设备“变砖”,无法启动;
客户要求预装私有系统,但原厂只提供完整镜像;
调试 kernel 时每次都要重新打包整个 2GB 的.img文件,耗时又低效。
这些问题的根源,往往在于对刷机机制底层逻辑的不理解。而答案,就藏在那个看似神秘的.img固件包里。
今天,我们就来彻底揭开usb_burning_tool所用固件的面纱——不是走马观花地看一眼文件列表,而是深入其结构内核,搞清楚它为什么能被识别、如何被解析、怎样安全修改,并最终实现一个完全自定义的刷机包。
这不仅是一次技术复现,更是一场嵌入式开发者的“逆向工程训练”。
你以为的 .img 是磁盘镜像?其实它是“烧录任务清单”
很多初学者把firmware.img当成一块完整的 eMMC 镜像,就像树莓派的raspbian.img那样可以直接 dd 写入 SD 卡。但usb_burning_tool的.img完全不是这么回事。
它的本质是一个带配置的烧录容器(burning container)—— 类似于 ZIP 压缩包,只不过这个“压缩包”里装的不是普通文件,而是多个独立的二进制镜像 + 一份 XML 格式的烧录指令表。
当你把.img加载进 usb_burning_tool 时,工具并不会直接把它写到 Flash 上,而是先“拆包”:
- 读取前几 KB 数据,解析出
config.xml - 根据 XML 中的
<partition>列表,在后续数据中定位各个子镜像 - 在图形界面中列出所有可选项(boot、system、uboot…)
- 用户勾选后,按地址逐个发送给设备写入
这意味着:你可以只替换其中一个分区镜像,比如 system.img,而不影响其他部分。
这种设计极大提升了灵活性和安全性。也正因如此,掌握它的结构,就成了我们进行定制化烧录的核心突破口。
config.xml:掌控烧录行为的“大脑”
如果说固件是身体,那config.xml就是大脑。它决定了每个镜像该往哪写、能不能改、是否校验。
别被名字迷惑——这个文件不一定真的叫config.xml,也可能叫parameter.txt或嵌入二进制头中。但在大多数瑞芯微/全志平台的 usb_burning_tool 固件中,它以明文 XML 形式存在,且位于文件开头附近。
来看一个典型结构:
<info> <version>3.0</version> <chip>rk3566</chip> <name>Custom_Burn_Package</name> <manufacturer>RK</manufacturer> </info> <partition> <name>uboot</name> <filename>u-boot.bin</filename> <address>0x00000000</address> <size>0x40000</size> <user_select>1</user_select> </partition> <partition> <name>boot</name> <filename>boot.img</filename> <address>0x00400000</address> <size>0x2000000</size> <user_select>1</user_select> </partition>关键字段详解
| 字段 | 作用 | 实战意义 |
|---|---|---|
<chip> | 指定 SoC 型号 | 工具据此加载对应协议驱动,错则无法连接 |
<address> | 物理写入地址(hex) | 必须与芯片手册一致,否则会覆盖关键区域导致变砖 |
<filename> | 子镜像文件名 | 解包后必须保留相同名称,否则找不到数据 |
<user_select> | 是否允许用户选择 | 设为 0 可隐藏 recovery 分区防止误操作 |
举个例子:你想做一个“救砖专用包”,只包含 uboot 和 recovery,其他都不让刷。只需要在 config.xml 中将无关项设为<user_select>0</user_select>或干脆删掉即可。
再比如,新硬件 layout 改了 boot 分区起始地址,只需修改<address>而无需重做整个镜像。
这就是通过配置驱动行为的强大之处。
如何安全提取固件?两种实用方法推荐
要修改,先得拆开。以下是两种经过验证的解包方式。
方法一:binwalk + dd 手动提取(适合进阶用户)
使用binwalk扫描固件内部结构:
binwalk firmware_original.img输出可能如下:
DECIMAL HEXADECIMAL DESCRIPTION ---------------------------------------------------- 0 0x0 XML document, version 1.0 131072 0x20000 gzip compressed data, max compression 1376256 0x150000 Squashfs filesystem, little endian可以看到第一个块是 XML,大概率就是 config.xml。我们可以用dd提取前 4KB:
dd if=firmware_original.img of=config.xml bs=1 count=4096接着查看下一个镜像的位置。假设 u-boot.bin 在偏移0x40000处,大小约 256KB:
dd if=firmware_original.img of=u-boot.bin \ bs=1 skip=$((0x40000)) count=$((0x40000))然后继续找boot.img、system.img……直到全部拆完。
⚠️ 注意:有些固件会在镜像之间填充 padding 字节用于对齐,记得检查实际大小是否匹配<size>字段。
方法二:使用 Rockchip Image Tool(推荐新手)
对于 RK 平台,社区有成熟的 GUI 工具 Rockchip Image Tool 或第三方封装版本。
操作流程非常直观:
1. 打开工具 → Load Image → 选择.img
2. 自动识别并列出所有 partition
3. 点击 Extract All → 导出 config.xml 和所有子镜像
简单、安全、不易出错,特别适合量产环境下的快速响应。
修改与重组:打造你的专属刷机包
拆出来之后,就可以动手定制了。
常见定制需求举例
- 裁剪系统:替换
system.img为轻量 Android 或 Linux rootfs - 增强调试能力:添加
recovery.img或fastboot.img - 适配新硬件:调整 dtb 地址或增加 vendor 分区
- 屏蔽功能:删除 OTA 更新模块或禁用某些烧录项
假设我们要为某款盒子添加 recovery 功能,步骤如下:
步骤 1:准备新的 recovery.img
可以从 LineageOS 或 TWRP 获取兼容设备的 recovery 镜像,确保内核版本和设备树匹配。
步骤 2:修改 config.xml
在原文件末尾追加:
<partition> <name>recovery</name> <filename>recovery.img</filename> <address>0x02400000</address> <size>0x2000000</size> <user_select>1</user_select> </partition>📌 提示:地址
0x02400000(即 36MB 处)通常是 recovery 的标准位置,具体需参考芯片 datasheet。
步骤 3:重新打包固件
目前没有官方打包工具,但可以用 Python 脚本自动化完成。
def pack_firmware(config_file, output_img, image_map): with open(output_img, 'wb') as img: # Step 1: 写入 config.xml(补齐至 4KB) with open(config_file, 'rb') as cfg: config_data = cfg.read() img.write(config_data.ljust(4096, b'\x00')) # Step 2: 按顺序写入各镜像 for name, path in image_map.items(): with open(path, 'rb') as f: img.write(f.read()) print(f"[+] 已生成: {output_img}")调用示例:
images = { "u-boot.bin": "modified/u-boot.bin", "boot.img": "custom/boot.img", "system.img": "minimal/system.img", "recovery.img": "twrp_rk3566.img" } pack_firmware("modified/config.xml", "custom_firmware.img", images)📌重要提醒:
- 所有镜像必须严格按config.xml中声明的顺序排列
- 若原固件有 CRC 校验或签名段,需保留或重新生成
- 推荐使用 512 字节对齐,避免某些 BootROM 解析失败
实战验证:刷入设备并观察结果
一切就绪后,进入 MASKROM 模式(RK 平台常见方式是短接 eMMC CLK 与 GND),打开 usb_burning_tool:
- 点击 “Import Firmware” → 选择你生成的
custom_firmware.img - 工具自动解析并显示所有 partition
- 勾选需要烧录的项目(如全选)
- 点击 “Start” 开始写入
成功标志:
✅ 进度条跑满
✅ 显示 “PASS”
✅ 设备正常启动
✅ 新增 recovery 可通过组合键进入
如果失败,常见原因包括:
-config.xml中<chip>不匹配
- 地址冲突导致 uboot 被覆盖
- 镜像未对齐或损坏
- 缺少必要签名(Secure Boot 启用时)
建议首次测试时仅烧录 uboot + boot,确认能启动后再加入 system。
这些技巧,能让团队效率提升十倍
掌握了这套方法论后,你会发现很多原本棘手的问题变得迎刃而解。
场景一:OEM 定制交付
客户要一款“纯净版”智能盒,不要广告、不要预装 App。
→ 提取原厂固件 → 替换 system.img 为干净镜像 → 删除 recovery 和 OTA 相关烧录项 → 输出专用刷机包。
场景二:研发高频调试
每天改一次 dts,难道要等 10 分钟生成完整镜像?
→ 只更新boot.img→ 修改 config.xml 保留其他项 → 打包一个仅 50MB 的小固件 → 秒级烧录验证。
场景三:产线应急修复
发现早期固件有个严重 bug 导致设备无法联网。
→ 制作最小恢复包(uboot + recovery)→ 下发给产线 → 快速刷回可用状态 → 再升级正式版。
这些都不是理论设想,而是我在多个项目中真实落地过的方案。
最佳实践 checklist:别让自己掉坑里
在你动手之前,请务必记住以下几点:
✅永远备份原始固件
哪怕只是做个副本,也能在出错时快速回滚。
✅核对 SoC 手册中的 memory map
不要凭经验猜测地址。0x0000_0000是 uboot,0x0040_0000是 kernel,这些都有文档依据。
✅使用 sha256sum 验证子镜像完整性
sha256sum boot.img确保提取和替换过程中没有损坏。
✅保留 Secure Boot 签名段(如有)
若原厂启用可信启动,擅自删除 signature 会导致设备永久无法启动。
✅先单机验证,再批量推广
哪怕你觉得万无一失,也要先在一台设备上跑通全流程。
结语:掌握底层,才能真正掌控系统
usb_burning_tool 看似只是一个简单的刷机工具,但它背后体现的是现代嵌入式系统对模块化、可控性、可维护性的追求。
我们今天所做的,不只是学会了解包和打包,更是建立了一种思维方式:
任何复杂的系统,都可以被拆解为“描述 + 数据”的组合。只要找到入口,就能实现自主控制。
未来,无论是 RISC-V 架构的国产芯片,还是更多闭源 SDK 的设备,只要你能拿到一个.img,这套分析思路依然适用。
如果你正在做定制化开发、系统移植或量产支持,不妨现在就试着拆一个手头的固件看看。
也许下一秒,你就发现了那个困扰已久的“隐藏分区”。
如果你在实践中遇到了具体问题——比如某个固件 binwalk 扫不出来,或者烧录后卡在 MASKROM 模式,欢迎在评论区留言,我们一起排查。