某软路由文件系统的简单分析

一、前言

朋友提供的一款软路由系统,有ISO映像文件可以安装,一般来说,这种软路由系统都是支持grub启动的,然后启动内核、加载文件系统。

└── boot
    ├── grub
    │   ├── grub.cfg
    │   ├── grub.img
    ├── rootfs
    └── vmlinuz

可以看到rootfs文件(文件系统),但经过binwalk分析,发现它是加密的文件,至于如何解密,可以分析vmlinuz文件是如何加载rootfs的,但是今天我们不用这种方式来解密rootfs。

使用虚拟机软件安装ISO,按照要求安装到硬盘。

进入系统之后,得到的权限并不是完整的SHELL,而系统命令是用来设置网络的命令,也就是受限的SHELL,那么使用系统命令的方式来获取文件系统是不可行的。

二、第1次尝试(版本1:完整的启动参数)

前面我们知道系统是grub启动的,启动系统的时候,按e键进行修改,这里我们可以看到,启动后会运行vmlinuz,然后会加载initrd。

我们知道linux内核启动是包含很多参数的,其中有一条init=参数,可以设置进入用户系统后第一个执行的程序,如果没有这个参数默认是init或linuxrc,那么我们将init=/bin/sh,是否就能进入用户系统shell了?

同样我们启动系统的是否按下e键,添加init参数,然后按F10继续运行,好的,果然进入用户系统的shell了,那么,如何将文件系统拷贝出来呢?

因为此时并没有完整的启动系统,所以网络传输是不可行的,那么可以借助外接设备或者直接挂载一个新硬盘的方式来获取,这里采用挂载一个新硬盘的方式,注意的是我为啥要选择磁盘存储为单个文件,后面会展示:

按照刚才的思路进入系统,挂载proc、dev,并查看新添加的硬盘名称sdb

完整的命令如下所示:

mount -t tmpfs mdev /dev
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs tmpfs /tmp

mkdir -p /dev/pts
mount -t devpts devpts /dev/pts

mknod /dev/sdb b 8 16
mkfs.ext4 /dev/sdb

mkdir /tmp/sdb
mount /dev/sdb /tmp/sdb
tar cvf /tmp/sdb/rootfs.tar /bin /etc /sbin /lib /usr /www
umount /tmp/sdb

执行完命令之后,关闭虚拟机,如果使用windows系统可以使用7zip软件打开新添加的硬盘vmdk文件:

刚才保存的rootfs.tar就能够获取成功。

三、第2次尝试(版本2:受限的启动参数)

版本1是启动参数比较完整的情况,而版本2则优化了启动参数,不能够添加init=参数,那么这种情况该如何办呢?

通过参考源码文档(kernel-parameters.txt)可以知道,常见的参数如下所示:

	console=	[KNL] Output console device and options.

	init=		[KNL]
			Format: <full_path>
			Run specified binary instead of /sbin/init as init
			process.

	initrd=		[BOOT] Specify the location of the initial ramdisk

	ro		[KNL] Mount root device read-only on boot

	root=		[KNL] Root filesystem
			See name_to_dev_t comment in init/do_mounts.c.

	rootfstype=	[KNL] Set root filesystem type

	rootwait	[KNL] Wait (indefinitely) for root device to show up.
			Useful for devices that are detected asynchronously
			(e.g. USB and MMC devices).

	rw		[KNL] Mount root device read-write on boot

其中有一个参数root=,可以根据加载的磁盘进行选择,那么我们可以自定义一个磁盘:

qemu-img create -f raw rootfs.img 128M
mkfs.ext4 rootfs.img
mkdir rootfs

sudo mount rootfs.img rootfs
sudo tar xvf rootfs.tar -C rootfs/
cd rootfs
sudo mkdir tmp var proc sys dev initrd
sudo mv sbin/init sbin/init.bak
echo '#!/bin/sh' |sudo tee -a sbin/init
echo 'exec /bin/sh' |sudo tee -a sbin/init
sudo chmod +x sbin/init
cd ..
sudo umount rootfs

qemu-img convert rootfs.img -f raw -O vmdk rootfs.vmdk

通过参考源码文档(do_mounts_initrd.c)可以知道,加载完initrd之后,如果有新的rootfs加载,会将initrd挂载到/initrd目录,那么我们就能获取到原始的固件了:

同样打开vmware虚拟机,点击使用现有的虚拟磁盘,加载刚才创建的rootfs.vmdk文件:

现在已经有3个磁盘了,对应系统分别是/dev/sda、/dev/sdb、/dev/sdc

启动,将root=/dev/ram0改为root=/dev/sdc

正常进入用户系统shell,其中/initrd目录为解密后的文件系统

之后的文件系统的获取可以参考第一次尝试的方式导出。

四、最后的尝试(版本3:固定的启动参数)

前两个版本都是可以对启动参数进行修改的情况,那么如果遇到了启动参数不让修改怎么办呢?

我们知道,系统启动完毕之后一定会将完整的系统给解压出来,那么解压的系统存在于/dev/ram0,也就是内存之中,那么我们是不是能通过获取虚拟机的软件的运行内存,来间接的获取系统的内存呢?

这里使用了一个挂起的方式。

挂起之后生成了一个vmem、vmss文件,其中vmem是当前内存的镜像:

我们使用16进制编辑工具查看,这里使用的是WinHex,搜索lost+found,可以找到目录结构:

再搜索/bin/bash,可以找到对应的shell脚本文件,同理可以找到其他文件,通过这种方式间接地把文件系统给提取出来:

至于如何去完整提取vmem里面的文件,了解内存中文件的存储方式,这里研究的较少,感兴趣的可以慢慢研究研究。

五、参考文档

Linux Kernel 内核源码

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注