As a reverse engineer, especially if we deal with embedded system, facing various architecture and its typical system is expected. Sometimes we have no access to the device and got only the firmware. In this condition, our only option is static analysis of the firmware, or it is not?
Our goal is to observe and extract the knowledge from inner part of the device. From the abstract things we call software. Modern device implement logic on a software and most of them incorporate an operating system to manage the resources and to run the program. Linux is very popular for it’s existence and support in various processor. This software stack (from linux kernel to various user space program) are coupled and packaged as a firmware (or firmware stack).
In this article we will discuss about firmware stack and how we can possibly run it on Qemu. The steps described here should be treated as a generic steps. I hope it can be used for the different setup you use.
Obtain the Materials
You can install Qemu from source or download it via your package manager.
We are discussing about firmware so naturally to practicing we need a firmware for reference. Here we will use following firmware. This fimware is a firmware for Linksys EA4500 , a wifi router that is publicly available for download. You can also download and use arbitrary firmware you want, but make sure you read the next section and know the architecture of the devices. It can be either ARM, MIPS, x86, etc.
Firmware Stack and Basic Concept
Fundamentally, software stack for PC-compatible and embedded system have different arrangement. In PC we use HDD to store the operating system and any user space program we need. The booting process come from BIOS (which is firmware in motherboard), to bootloader, and then the kernel on the disk. It’s very modular and we can replace the components as we want. We can upgrade it individually. In embedded system we have no luxury on that level. In most case, every components are tightly coupled, as well as the firmware.
Most modern embedded system incorporate linux system. The firmware stack, be it for your typical wireless routers to smart devices, consists not only softwares. They are also packed with a whole partition, in this case in squashfs format. This filesystem, known as rootfs, is used in runtime in similar manner to our partition. You might ask why. Linux kernel always need a minimum filesystem. Even in booting proses it use initramfs or initrd which is minimal filesystem.
There might be many sections inside the firmware file, but for most firmware they have minimum three components: the bootloader (ex: U-boot), kernel, rootfs. Flashing process might rearrange them to different place, but our focus is on the firmware file itself, before flashing.
So here’s the basic concept.
The filesystem used in runtime is packed inside the firmware, mostly using squashfs format. Therefore, we need to extract that filesystem. One of the tool in our disposal is binwalk. Read the next section for detail. So if we have both kernel and filesystem we can boot the system? That’s a pitfall there. We have no guarantee that booting the firmware in “normal” flow will give success result. If we are successful, we can see the system running. If not, we might not able to enter the shell and stuck.
Remember that the operating system in embedded system is interfacing many things, including peripheral, sensors, actuators, etc. When linux kernel is booting, it spawn the first use space program called init to initialize all runtime configuration the embedded system need. If for some reason the initialization fail, and high chance it will, then the system might have no stable state. And, that’s why we might have our system stuck.
So here’s the trick. In the end we need working kernel with working filesystem. How do we make sure that booting is completed? No, we don’t. We are cheating a little here. We skip it. We are pretending that the booting is complete. From here on we can invoke various commands there, and investigate how system behave. We complete this by using chroot and use the Qemu as the shell. While observing foreign architecture, all of this operations are done in our lovely x86 machine.
If the firmware layout is simple enough, then we might identifying something like this.
We use binwalk to identify the firmware component and automatically extract the content.
binwalk -e FW_EA4500V3_126.96.36.199919_prod.img
Here, binwalk is generous enough. We see three sections there. The first section, blue rectangle, start from offset 0, is a bootloader. It will boot a Linux kernel for MIPS architecture. The second is red rectangle, the linux kernel. The third one is the squashfs filesystem.
Binwalk will create a folder and extract the content to that folder. For example, we got this. The squashfs is automatically extracted as squashfs-root.
There we can see the familiar directory structure.
Running the System
After all preparation we have done, it’s time for the actual thing.
Note that the kernel in this case is the 40.7z however, when doing a chroot we are using our own kernel and sandboxing the environment of running embedded system so kernel is not really used here.
Because we will interact with MIPS
First we need to copy the qemu-mips-static to the root directory of our squashfs (squashfs-root). Then we will chroot to that environment.
cd squashfs-root cp $(which qemu-mips-static) bin/qemu chroot . qemu /bin/sh
Sure, we can then do anything as if this were the fully working embedded system shell.