小米路由器 MiWiFi R2D 它复活了!
2022-05-10
说好的焊接水平上升了呢?
接上文 记录一次失败的小米路由器 R2D 救砖之旅,更多技术信息请参见该文章。
通过仔细观察,测量了一些电压后发现是 3.3V 电源输出对地短路,再经过仔细观察后发现,是我的 NAND 芯片焊挂了...芯片的 VCC 与 VSS 的引脚是放在一起的,而这两个引脚都是连接了大铜皮,最后将烙铁温度升到了 410 度时,才成功从他们中间拖出了锡。
要来的密码
通过微信与原贴主询问到了压缩包的密码。压缩包内有完整的刷录镜像,其中也有设备的序列号等信息,为了设备主的隐私起见,我这里也不放上下载链接,如果有需要的人,可以通过 [email protected] 与我联系。
Ref: 小米R2D编程器固件 512M的nand芯片备份 完全好使加修改MAC和sn教程-恩山无线论坛
快要挂掉的芯片
任何刷入操作前一定要先备份!
这个小 NAND 在刷写的过程中,经常出现错误,导致编程器与电脑失去连接。经过测试发现其 0x00000000-0x01000000
区域(即前 128 个 block)可以写入数据,但是再往后就难写入了。
没有办法,只能刷入前面区域,对于一个系统来说,前面的区域包含了系统的内核,但是其他工具,软件包等数据都存储再后面的 rootfs 区域。这些写入信息不足以让系统正常启动
小米路由器的恢复系统
经过观察,小米编译的 CFE 正常情况下会启动 os0,若不成功会启动 os1,若再不成功,则会启动 os1,并且标志上两次启动不成功。
对于第三次启动,小米路由器在成功启动 os1 内核的时候,进入恢复模式,表现为红灯闪烁。
这个恢复模式是在内核中实现的,换个角度来说,这个救砖机制主要是为了解决装了错误软件(即在 rootfs
)导致的系统变砖头,而非内核编译错误导致的系统变砖头。刷机的时候,一定要往 os0 里刷入系统!刷入 os1 里,内核启动出现错误,砖头都救不动哇。
进入恢复模式后,系统会在串口输出一系列 .
等待 USB 装有新固件并且重命名为 miwifi.bin
文件的恢复 U 盘的插入。值得注意的是,小米路由器 R2D 会等待 /dev/sdb
插入,这是由于 R2D 本身有一个硬盘,即 /dev/sda
。故如果硬盘挪作他用,没有插上,同时只在 USB 口上插入一个 U 盘的话,R2D 检测不到恢复 U 盘(此时 U 盘为 /dev/sda
)。这个时候我们需要一个 USB 分线器,在启动前先把一个 U 盘(作为 /dev/sda
)插在分线器上,将分线器插在路由器上,等系统进入恢复模式等待恢复 U 盘插入的时候,我们再把恢复 U 盘插入(作为恢复系统需要的 /dev/sdb
)
之后小米系统会更新 os0 os1 rootfs0 rootfs1 重启后就可以进入系统啦。
更多关于小米编译的 CFE
在成功恢复系统之前,CFE 之后的每次重启都会进入 os1 系统。
如果 os1 安装了符合 CFE 格式(即 trx 格式)的系统,但是内核本身启动失败的话(比如给这个 arm 设备刷入了用于 mips 的内核镜像(我的情况)除非你非常清楚这两个设备的情况,否则不同设备的镜像不能乱刷!),CFE 会返回到其内置的 shell ,但是!
小米编译的 CFE 在 CFE 中的 nvram 里还增加了 uart_en
选项,如果这个选项不为 1
,CFE 不会响应开机的 Ctrl-C 中断启动,且 shell 可能也无法使用(存疑,也有可能是我把芯片 UART 的 RX 搞坏了)
以上这些问题会导致如果 os1 本身错误的话无法启动的话,整个设备会卡住。
另外,如果 os0 和 os1 里都没有安装系统(为空白盘),CFE 会报两次 Wrong header
后,尝试向 192.168.1.2 (网线插入最靠近 USB 的那个网口)上的 tftp 请求两次 vmlinuz.trx ,并每次在请求成功后,将镜像刷入到 os0 或者 os1 中。
(以上每条结论的得出都意味着对 NAND 芯片的若干次拆装和对小米编译的 CFE 二进制代码的艰苦逆向 ;_; )
CFE 具体启动过程
小米编译的 CFE 除了一些小细节上外与官版的 CFE 大体一致。
可以参考 ASUS 开源的 CFE 代码,来辅助分析 CFE 的执行过程,这部分代码可以在 ASUSWRT 梅林代码仓库中找到: RMerl/asuswrt-merlin: Enhanced version of Asus's router firmware (Asuswrt) (legacy code base)
值得关注的代码分别为:
cfe\build\broadcom\bcm947xx\compressed\Makefile
Makefileshared\cfez_arm_shmoo.lds.in
链接文件shared\startarm-ca9.S
ARM 内核Reset_Handler
所在汇编文件shared\load.c
解压缩后半段代码的c_main
函数所在文件cfe\cfe\main\cfe_main.c
真正的 CFE 执行入口文件cfe\cfe\arch\common\board\bcm947xx\src\bcm947xx_devs.c
board_final_init 等设备相关初始化函数所在文
小米编译的 CFE 启用了 CFE 自身压缩功能,系统会先启动一小段代码,解压由 LZMA 压缩的 CFE 内核,然后再执行 CFE 真正的内核。
主芯片上电复位后,由芯片内的 BootROM 拷贝 NAND 中的数据到内存中,即从 NAND 的 0x00000000
位置后拷贝若干数据拷贝到内存中的 0xC0000000
下,并且从 0xC0000000
开始执行代码。(应该)
这一行代码会直接跳转到 tr_rst
。tr_rst
为 ARM 内核芯片一般会由的 Reset_Handler
,CFE 的 tr_rst 会根据是否要解压缩去选择入口函数,对于代码运行在解压缩模式(即没有定义 __CFE__
宏)时,调用 c_main
,若运行在正常模式(即定义有 __CFE__
宏),会调用 cfe_main
。这个过程之前这段汇编也会执行 DDR 内存自检等操作。
对于小米编译的 CFE,压缩后的镜像位于 NAND 的 0x0001C000
(对应内存编址 0xC001C000
)位置,前四个字节为小段序的镜像大小,后面会跟随该大小的压缩镜像。通过 WinHex 导出这一段数据后,可以使用开源的 7zip 程序直接解压。CFE 会把这些数据解压到内存的 0xF00000
位置,然后从这个位置再继续开始执行代码。
CFE 在编译的过程中会把一些 section 的地址偏移信息,写入到特定的区域,这些信息会有助于我们分析小米编译的 CFE 的代码(如创建 bss section)。具体可以参见 cfez_arm_shmoo.lds.in
链接文件。
在 flash_init
函数中,小米增加了判断进入工厂模式的代码,在检测到指定位置(0x140000
)有特定字符的时候,重置 CFE 的 nvram(在 board_final_init
中执行逻辑),可以设置 uart_en
为 1。但是不知道为何,我自己在使用的时候,并不成功
恩山论坛上也有坛友对 CFE 的启动进行了一些分析,对我很有帮助,在此谢谢这位坛友: 博通 CFE 数据压缩与解压-恩山无线论坛 , CFE 编译、结构解析与二进制修改-恩山无线论坛
IDA 真好用
无 miwifi_ssh.bin
开启 ssh
先刷到低版本系统,我刷的是 brcm4709_r2d_ec5d6_2.5.16.bin
登录到后台,获取 url 上的 stok。
访问该网址启动 telnet 服务,替换 <>
内参数:
http://192.168.31.1/cgi-bin/luci/;stok=<stok>/api/xqnetwork/set_wifi_ap?ssid=whatever&encryption=NONE&enctype=NONE&channel=1%3B%2Fusr%2Fsbin%2Ftelnetd
访问该网址修改 root 密码:
http://192.168.31.1/cgi-bin/luci/;stok=<stok>/api/xqsystem/set_name_password?oldPwd=<old_admin_password>&newPwd=<new_admin_password>
此外,软件编译工具链可以从 sdk_package.zip 获得。
另外固件的解包可以使用 R2D 系统内的 mkxqimage 进行。
Ref:
- [OpenWrt Wiki] 小米米 WiFi Mini
- 自己收藏的小米路由器2硬盘版(R2D)固件全集-恩山无线论坛
- 小米路由器R2D官方固件解包打包-恩山无线论坛
- 交叉编译小米路由器2(R2D)shadowsocks | yxleung blog
后记
至此救砖宣告即宣告胜利。
这个砖了 3 年的设备,终于可以在 3 年吃灰后,再次发光发热了!
香香的 Cortex-A 开发板哇~