小米路由器 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 Makefile
  • shared\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_rsttr_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。但是不知道为何,我自己在使用的时候,并不成功

factory-mode

reset-nvram

恩山论坛上也有坛友对 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:

后记

至此救砖宣告即宣告胜利。

这个砖了 3 年的设备,终于可以在 3 年吃灰后,再次发光发热了!

香香的 Cortex-A 开发板哇~

加载中...

(。・∀・)ノ゙嗨,欢迎来到 lookas 的小站!

这里是 lookas 记录一些事情的地方,可能不时会有 lookas 的一些神奇的脑洞或是一些不靠谱的想法。

总之多来看看啦。