从bzImage启动镜像到解密固件得到文件系统

前言

就是为了学这个事情所以去学习了linux底层机制,包括CPU加电直到第一个main函数的过程

在知晓其机制以前,刚开始是对着镜像文件硬啃,但由于不知道镜像自解压的逻辑,也由于有一部分操作是操作系统参与的,所以当然不会出任何结果,

后面花了一周多去学习(外加一些学校的任务),理清关系,然后这周回到逆向过程,就能很快搞懂整个过程了,其实还挺简单的

因为某些原因只能省略细节,没关系,直接看思路即可

镜像文件结构

根目录

│ bootargs.cfg

│ bzImage

│ diskmap

│ initramfs.img

│ initrd.gz

│ memtest

├─dtb

│ *.dtb 若干

│ u-boot-*.dtb 若干

├─grub

│ .gdb_history

│ grub.cfg等文件

└─initrd_data

│ dec_initrd等文件

└─mount

知晓bzImage机制前的探索

Findcrypt启动找到如下密码算法,但是很奇怪:这些算法最终的引用都没有指向?

查看引用,也没有引用该文件的地方,怎么回事呢

实际上这是加解密的库被包装在镜像里面,而且该固件的解密,后来确实并没有使用这几个被检测到的算法,但是当时在这里绕了一阵子圈圈,怀疑过是IDA版本不够高等问题

于是询问师傅,师傅说学习一下initrd那些东西你就懂了,于是网上搜索了bzImage这个关键词,首先看到的是这样一张图

恍然明白了,原来这么长条的灰色(7.7是灰色条,8.3是绿色条),是被压缩的vmlinux.bin空间呀

知晓bzImage机制后

于是课下花去了大概一周左右的时间,断断续续把从CPU加电到整个系统初始化完成的机制都学习了,其中就包括bzImage的解压为vmlinux的过程,再回来看这个固件的解密

这是我在学习的时候画的图,可能有细节问题请见谅,详见本站的文章:

解压bzImage为vmlinux

bzImage可以使用https://blog.csdn.net/qq_40421991/article/details/111241980来解密

https://github.com/marin-m/vmlinux-to-elf

当然可以直接使用虚拟机上的

/usr/src/linux-headers-6.5.0-26-generic/scripts/extract-vmlinux

然后就导出来一个文件,拖IDA分析,此时整个bzImage解压后的状态就能分析了、

分析vmlinux

根据这一篇文章https://www.iotsec-zone.com/article/218

可以参照linux/init /initramfs.c后面populate_rootfs前后逻辑来分析其解密逻辑。

发现大量decrypt字样,以及,rc解密算法

但是这是没有引用的,内核上的那种调用关系,ida分析不出来

当然非常幸运的看到了rc4函数,直接查看引用,发现作者是改写了populate_rootfs的代码,直接让其自身具备rc4解密能力

所以跟进到populate_rootfs:

发现这个解压的函数实在是太长了,如图所示:

解密后的结果存放到/initrd.image

接下来有两个方案:

1.跑起来,让这个bzImage自行解压出来(具备一定普适性)

2.直接写破解脚本(麻烦,暂时可以不这么做)

那在这里就直接尝试跑起来这个镜像先吧

镜像加载

qemu-system-aarch64 \ 
-machine virt,virtualization=true,gic-version=3 \ 
-nographic \ 
-m size=1024M \ 
-cpu cortex-a72 \ 
-smp 4 \ 
-kernel bzImage \ 
-initrd initrd.gz \ 
--append "console=ttyAMA0 rdinit=/linuxrc"

这样直接启动却报错了,仔细观察报错:

按道理,这里执行是没问题的

但是到后面就是不行,显示挂载不到rootfs

Please append a correct "root=" boot option; here are the available partitions

原来,是qemu启动参数里append中root指定有问题

参考grub.cfg或者boot.cfg设置参数即可

qemu-system-aarch64 \ 
-machine virt,virtualization=true,gic-version=3 \ 
-nographic \ 
-m size=4096M \ 
-cpu cortex-a72 \ 
-smp 4 \ 
-kernel bzImage \ 
-initrd initrd.gz \ 
--append "console=ttyAMA0,115200 hugepagesz=2M hugepages=5120 ramdisk_size=60000 libata.dma=5 root=/dev/ram0 rw bonding.miimon=100 bonding.mode=active-backup pci=noaer pcie_aspm=off earlycon=uart8250,mmio32,0x28001000 rdinit=/linuxrc" \
-dtb ./dtb/u-boot-general.dtb

不过,并没有这么简单,这个固件体积可不小啊,内存不够大

师傅:应该是16g,但可以把pagesize改小点,2g也能跑

qemu-system-aarch64 \ 
-machine virt,virtualization=true,gic-version=3 \ 
-nographic \ 
-m size=12416M \ 
-cpu cortex-a72 \ 
-smp 4 \ 
-kernel bzImage \ 
-initrd initrd.gz \ 
--append "console=ttyAMA0,115200 hugepagesz=1M hugepages=1M ramdisk_size=60000 libata.dma=5 root=/dev/ram0 rw bonding.miimon=100 bonding.mode=active-backup pci=noaer pcie_aspm=off earlycon=uart8250,mmio32,0x28001000 rdinit=/linuxrc" \
-dtb ./dtb/u-boot-general.dtb

确实如此,可以跑起来了,终于

此时虽然确实可以进系统,但是有这个字样,一度以为实在不行了,问了一下师傅,他说是没有磁盘啊,但是qemu是可以无视这个条件的。如果想进shell,可以加init=/bin/bash启动参数就ok

qemu-system-aarch64 \ 
-machine virt,virtualization=true,gic-version=3 \ 
-nographic \ 
-m size=12416M \ 
-cpu cortex-a72 \ 
-smp 4 \ 
-kernel bzImage \ 
-initrd initrd.gz \ 
--append "console=ttyAMA0,115200 hugepagesz=1M hugepages=1M ramdisk_size=60000 libata.dma=5 root=/dev/ram0 rw bonding.miimon=100 bonding.mode=active-backup pci=noaer pcie_aspm=off earlycon=uart8250,mmio32,0x28001000 rdinit=/linuxrc init=/bin/bash" \
-dtb ./dtb/u-boot-general.dtb

文件系统导出

看起来/bin/decrypt就是核心的解密程序,跟进就行

有个问题:

这个RC4加密,密钥是什么,加密了什么,怎么导出解密的内容,实际上这里就是翻找各种启动脚本,以及看看它们引用了什么二进制文件,然后就推断出来个大概的样子

主要的启动逻辑在这:DecryptAndMount

好的,谜解开了,其实是因为initrd_data这个文件夹里面的内容是动调内核然后在populate_rootfs下断点然后dump内存解压出来的

QEMU仿真指令

qemu-system-aarch64 \ 
-machine virt,virtualization=true,gic-version=3 \ 
-nographic \ 
-m size=12416M \ 
-cpu cortex-a72 \ 
-smp 4 \ 
-kernel bzImage \ 
-initrd initrd.gz \ 
--append "console=ttyAMA0,115200 hugepagesz=1M hugepages=1M ramdisk_size=60000 libata.dma=5 root=/dev/ram0 rw bonding.miimon=100 bonding.mode=active-backup pci=noaer pcie_aspm=off earlycon=uart8250,mmio32,0x28001000 rdinit=/linuxrc init=/bin/bash" \
-dtb ./dtb/u-boot-general.dtb \
-virtfs local,path=/mnt/shared,mount_tag=host0,security_model=passthrough,id=host0

Shell上挂载

mkdir -p /mnt/shared sudo mount -t 9p -o trans=virtio,version=9p2000.L host0 /mnt/shared sudo mount -t nfs host0:/ /mnt/shared

如果我们希望能够直接导出文件系统,那么有两个办法,其一是

其一比较麻烦,配置网卡让虚拟机和本机产生网络连接,然后就可以通过scp之类的指令传文件,首先可预先了解一下TAP/TUN是怎么回事,巧了刚好朋友今天分享了相关知识,所以立马理解了。听起来是个很不错的方法,于是跟着

https://wzt.ac.cn/2021/05/28/QEMU-networking/试了一下,可惜的是,我配置完以后,这个qemu虚拟机仍然是不可以使用网络的,不仅仅是busybox阉割net-tools的问题

但我认为这个方法本身没有任何问题,倒是不太适合这种,如果是uart串口会不会就适用呢

其二则可以让qemu虚拟机mount某个镜像(建议先了解一下镜像和mount的那些知识,不然搞不明白),然后在qemu跑起来的shell里面操作,把整个文件系统都放进镜像里面,之后直接分析镜像即可,听起来非常靠谱,因为即使固件再阉割,也是需要mount的吧,不可能把这个功能也给阉割了

刚开始试了下qemu使用这个来挂载镜像,失败

-drive format=raw,file=share.img

然后发现/dev/下仍然没有任何新记录

卡了挺久的,试了好多个都不行,再抱着不怕失败的心态尝试一下这个,感谢作者,终于可以了

http://pwn4.fun/2020/05/27/Qemu%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%B8%8E%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B9%8B%E9%97%B4%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93/

接下来详细讲讲怎么导出来文件系统的,首先是宿主机:

还是先创建一个镜像

dd if=/dev/zero of=share.img bs=1M count=2048

ext4格式化镜像

mkfs.ext4 share.img

再在宿主机创建一个空间/tmp/share,提供给镜像挂载,

还有先别把这个镜像挂到这个空间上面,因为宿主机和qemu虚拟机同时挂载镜像以后,并不能够同步,重新挂载才能得到最新的文件

mkdir /tmp/share 
//先别sudo mount -o loop $PWD/share.img /tmp/share

然后就是qemu跑起来。我的append是根据配置文件来配置的,其实与镜像挂载无关,真正有关的是最后一行

qemu-system-aarch64 \ 
-machine virt,virtualization=true,gic-version=3 \ 
-nographic \ 
-m size=12416M \ 
-cpu cortex-a72 \ 
-smp 4 \ 
-kernel bzImage \ 
-initrd initrd.gz \ 
--append "console=ttyAMA0,115200 hugepagesz=1M hugepages=1M ramdisk_size=60000 libata.dma=5 root=/dev/ram0 rw bonding.miimon=100 bonding.mode=active-backup pci=noaer pcie_aspm=off earlycon=uart8250,mmio32,0x28001000 rdinit=/linuxrc init=/bin/bash" \ 
-drive file=$PWD/share.img,if=virtio

然后进shell第一件事是,看看/dev/有没有多东西?有,太好了

多的是/dev/vda,将它挂载到qemu虚拟机里面某个文件夹,

mount -t ext4 /dev/vda /mnt/

至此,这个镜像挂载上了qemu虚拟机里面的/mnt/

这时候,就可以放文件进去了,我们需要打包整个文件系统,以支撑下一步的漏洞研究。

在qemu shell里执行:

tar -czvf rootfs.tar.gz / cp rootfs.tar.gz /mnt/

现在可以退出qemu虚拟机了,回到宿主机,对镜像进行挂载

sudo mount -o loop $PWD/share.img /tmp/share

然后就可以去/tmp/share/找到我们需要从qemu shell导出来的文件了

自此,bzIamge->解密->解压文件系统到内存->qemu shell->导出固件文件系统,这个解密固件的流程是走完了,后面就可以进行进一步的安全研究啦

评论

  1. 风之子.
    5 月前
    2024-5-08 9:54:15

    代码颜色变透明啦,可以调一下哈

    • 博主
      风之子.
      5 月前
      2024-5-08 14:38:57

      噢噢好的,谢谢stone师傅提醒,晚点看看是怎么回事0.0

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
粤ICP备20015830号