从路由器刷机到对嵌入式系统的理解 – 老毛子固件 Padavan 破解

为了科学上网,把家里一直当普通无线路由的斐讯 K2 拿出来耍了一下。了解了一下各种刷机的固件和技巧之类的,基于之前对 Linux 和嵌入式的了解,以及对这个所谓老毛子(作者:Andy Padavan 是俄国人)的 OpenWrt 的固件中 /etc 的挂接到 tmpfs 十分不解,成就了此文。

前方高能,也是您挑战自己 Linux 知识的最好机会!

Linux 学习/破解第一步:机器的启动,硬件的启动都是从主板接收到上电或者 reset 信号开始的,然后去 ROM(简单理解就是CMOS/BIOS),根据其中的启动引导顺序逐个找指定地址的 55AA 的可引导标记,然后就把内存的的操作权利都交给了操作系统。在操作系统引导之前,传统的 Linux 机器都是用 grub/lilo 之类的来管理引导区。Sun Sparc 或者 IBM 的机器都有自己的 Boot PROM,你可以理解为是 CMOS。嵌入式其实也是一样,有的叫 Uboot,在目前大多数无线路由器刷机中,都用一个叫做 Breed 的所谓 不死鸟,其实通用的说法就是 Boot Loader。默认加电同时按住路由器 Reset 按钮 5-10秒钟,无线路由器会自动设置 IP 为 192.168.1.1,并提供 DHCP,管理端的 PC 只要浏览器输入 192.168.1.1 就可以看到 Breed 的刷机界面,选择普通固件,上传已经下载好的对应自己路由器的固件,等待上传完成后2-3分钟,根据自己不同的固件,可能需要重新插拔网线,看得到的 IP 地址和网关地址(老毛子默认为 192.168.123.1),然后浏览器进入网关地址就可以进入新刷的操作系统了。 当然你先需要刷入 Breed ,其实这个 Breed 就是放入 MTD(Memory Technology Device) 的第一个 Boot Loader 区里的,后面会提到。

讲到操作系统,特别是 Linux 操作系统,我们需要知道引导的第一个进程的进程号就是 1,所以,一般的 Linux/Unix ,我们敲入命令

# ps 1

就可以知道系统引导的启动进程是什么。譬如,我们在 Mac Book 的终端里敲入 ps 1,会得到:

然后我们会看系统里的分区,最常用的就是 df -h :

我们知道 tmpfs 就是临时文件系统,也就是说是里面的内容是放内存里的, 再换句话说,就是路由器重启以后信息都是要丢失的!!那么, /etc 里面重要的文件都是怎么保存和恢复的呢? 这就是本文要探讨的主题。

前面已经埋伏了 ps 1 这个东东,在继续这个话题之前,我们先看看下 /proc 这个重要的进程文件系统,我们用 mount 命令就可以看到 /proc 是一个类型为 proc 的文件系统,挂接在 proc 上。里面其实就是存放了加载到内存中的进程数据,我们可以用 cat 命令打印其中的信息。

譬如分别用 cat /proc/cpuinfo 和 cat /proc/meminfo 看 CPU 和内存信息:

我们如果要看内核引导的命令行参数,可以 cat /proc/cmdline
譬如我们在一台腾讯云的 CentOS 7 的云服务器上,打印出的信息如下:

BOOT_IMAGE=/boot/vmlinuz-3.10.0-1062.4.3.el7.x86_64 root=/dev/vda1 ro crashkernel=auto console=ttyS0 console=tty0 panic=5 net.ifnames=0 biosdevname=0 LANG=en_US.utf8

在斐讯 K2 的老毛子固件上,# cat /proc/cmdline 我们得到:

console=ttyS0,57600n8 root=/dev/mtdblock4 rootfstype=squashfs

我们看到 root=/dev/mtdblock4,这里就是一个 mtd 的概念,

在嵌入式系统中,与文件系统相关的存储设备包括硬盘、Flash存储器等。Flash存储器又分为Flash芯片设备(Raw Flash device,也叫MTD设备)和带Flash控制器的设备(Flash Translation Layer device, FTL设备),两者的关键区别是是否带有Flash控制器,这也直接决定了文件系统分为不同的两类。

我们看到 /proc 下有个 mtd 文件,就可以 cat 去看下内容了:

所以 mtd0 其实就是前面提到的 Boot Loader,不死鸟 Breed 其实就是刷入 mtd0 的。根据名字我们看到 mtd3 放的是内核,mtd4 放的是根文件系统,也就是操作系统其实就是从 mtd4 里的数据启动的, mtd5 很关键,我们先埋个机关。

从前面 mount 命令的输出截屏我们可以知道 root 根文件系统的属性是 ro,也就是 read-only,所以,什么 /sbin,/bin,/lib 只要不是挂节点的子目录,都是只读的,也就是不能往里面写文件的!!!

好,写到这里,大概介绍一下 pstree 这个很好用的命令,把进程以树状打印出来。我们可以看到所有的进程祖先都是 init,我们知道这就是 /sbin/init ,在这个固件里,是一个连接到 /sbin/rc 的软连接。

既然很多都是临时文件,连 /etc 都是临时的,我们先来看下 /sbin 下有哪些文件。

忽略哪些浅蓝色的文件,那些都是软连接到其他文件的,可以暂时不关注。注意到 dev_init.sh 这个脚本的时候,我们深入看下内容,并抓取出核心的一部分内容。

可以看到里面 /etc 就是挂接为 tmpfs 了, 其中的尺寸由 size_etc 变量定义。

那么,我们怎么确定这个 dev_init.sh 是不是被 init 或者说 /sbin/rc 调用了呢?很简单, strings 也是嵌入式系统必备的瑞士军刀工具 Busybox 的一部分,能用来输出二进制文件中的字符串,这个用作逆向工程简直就是神奇。

[YJ777 /sbin]# strings /sbin/rc|grep dev_init
dev_init.sh -8 -64

好了, 介绍到这里,基本上,我们就能理解 /etc 是怎么挂接的了, 其中的参数 -8 -64 是根据不同的硬件版本写死的,64 就是 64M 内存, 8 就是 8M Flash。

当然我们不能忽略 /sbin/mtd_storage.sh 这个脚本,就是这个脚本把 /etc/storage 里面的内容做了压缩备份,放到了 /dev/mtd5,而后面大量的引导脚本其实都是在 /etc/storage 和 /etc/storage/script 里面。特别是 /opt 里面的大量内容就是通过 Sh01_mountopt.sh 来挂接的。

总结一下:核心的素质内容就是“打破砂锅问到底”,从知道进程 1,到怎么发现进程 1 和其他脚本/程序的关联关系,再逐个击破。

哦, 差点忘记说了, 老毛子把所有的信息都写到 nvram 里面去了, 就是掉电也能保存的一个区域,mtd 里面的 Configure ? 这就是为什么你所有的配置都能在重启以后还能保存的原因。提醒一下:你的路由器登录密码在 nvram 里是 http_passwd 这个变量,是明码保存的。 nvram 直接敲回车是没有任何帮助的,要找里面的帮助,还是要用 strings 这个大神。 聪明的你一定知道怎么查询所有的 nvram 变量了。

最后提一下, 斐讯 K2 是没有 USB 口的,不能插 U盘保存 /opt 的数据,感觉有点 Low,还没怎么玩转这个老毛子,感觉整体就是一大堆的 Shell 脚本,构成了整个操作系统,没有了原生的 OpenWrt 的那种简洁。

淘路由器,一定要淘 16M Flash 以上的吧,内存当然越大越好,至少 128M。一定要有 USB 口,可以做很多存储的扩充和配置的备份。

最后的最后,补充一个刷机技巧:初学者,最好把准备刷机的路由器的 WAN 口挂接到 能上网的路由器的 LAN 口,把要用于刷机的 PC 网线连接到要刷机的路由器的 LAN 口,保证上网的路由器的 LAN 不是 192.168.1.x 即可。这样子,刷机完毕后,老毛子 WAN 口会自动 DHCP 取到原先网络环境的地址,然后用于刷机的笔记本电脑,理论上也能拿到 192.168.123.x 的地址,然后通过刷机路由器的网关 192.168.123.1 也可以上网。斐讯 K2 如果固件版本比较高的话,要降级到 22.6.526.199 才可以刷 Breed。

后记:

为了更好的理解 Flash 的分区, 这个版本默认没有 fdisk 命令,我们挂接从他们家官网下载解压到 NFS share 上的 opt 文件,然后运行 opkg update; opkg install fdisk,然后运行 fdisk -l 我们就可以看到 8M Flash 的分区情况了。

# mount -t nfs -o nolock nfs_share_server:/nfsshare/breed /mnt

我们从 dmesg 的输出也可以看到:

从这个 dmesg 的输出,我们可以了解到,地址空间 mtd6, Firmware_Stub 实际上覆盖了 Kernel/RootFS/Storage 三部分的地址,这是分层的技术。所以上面 fdisk -l 的输出里面 mtdblock6 实际上不是实际可用的空间。

另外纠正一个 NVRAM 的错误,那个不是 Flash 的 Config 区,NVRAM 是专门的一个硬件, dmesg 命令有报告如下:
ASUS NVRAM, v0.08. Available space: 61440. Integrity: OK

参考网上的教程,我们可以把 mtdblock 里面的数据读出来,修改后再刷回去。

作者: 甬洁网络

--移动互联网&物联网技术提供商