Running Raspbian OS on QUEMU to learn ARM assembly Jan 19 2020
If you want to get into mobile security or reverse engineering, you'll get to a point when you would like to have access to an ARM processor. There are many devices you could use, but one very cheap (in price not in quality) is the Raspberry pi. You can get one for about 35$, which opens up the doors to a lot of learning. But sometimes you don't want to carry an additional device, so what to do? Well, you can run a virtual machine that is ARM-based. That is what we are going to explore in this short post, how to install Raspbian OS using QUEMU so you can create your own ARM lab.
We need to download the OS image that might be big, so depending on your Internet speed, you might wish to start downloading them before we start.
Raspbian latest OS - download Raspbian Buster lite
Ok, let's begin.
Table of Contents
QEMU
We want to have access to a machine that has an ARM processor, so we are going to use QEMU to emulate that machine. I'll assume you are using Ubuntu, but the installation of QEMU through your package manager should be easy. You can check the download specific instructions for your OS here.
1
2
#Ubuntu
$ sudo apt-get install qemu-system-arm
That should install all the required packages for QEMU.
Now we need to figure out which machine we are going to be emulating. You can list all the machines supported by QEMU using the -M help
command:
1
$ qemu-system-arm -M help
You can see many types of machine that can be emulated. We are going to be using versatilepb
. We'll choose this machine because there is a handy repository dhruvvyas90/qemu-rpi-kernel that already contains QEMU kernels that can be used to emulate a Raspberry Pi. We could go the hard way and build the kernel ourselves and also create the DTB (Device Tree Blob, that describes the machine and the supported devices), but I still need to learn more so I can comfortably write about it. So in the meantime, we'll take advantage of the knowledge shared by the authors of qemu-rpi-kernel
.
Let's start by getting all the necessary files.
Get the sources
First, let's create a directory where we are going to be doing all our work. You can name it whatever you want. I'll call it raspbian_vm
:
1
2
$ mkdir raspian_vm
$ cd raspbian_vm
Now, let's clone the qemu-rpi-kernel
repo so we can have access to the kernel and dtb
files:
1
$ git clone https://github.com/dhruvvyas90/qemu-rpi-kernel.git
We are going to download the Raspbian OS image. I will be using Buster Lite. We don't need a GUI if most of our work will be on the terminal while doing reverse engineering.
1
2
3
4
5
6
7
8
9
10
11
12
$ curl -JLO https://downloads.raspberrypi.org/raspbian_lite_latest
# In theory it should follow the link and use the correct file name
# but if not to check the filename use this command:
$ curl -sI https://downloads.raspberrypi.org/raspbian_lite_lates
# In my case
HTTP/1.1 302 Found
Date: Sun, 19 Jan 2020 12:06:54 GMT
Server: Apache/2.4.10 (Debian)
Location: https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-09-30/2019-09-26-raspbian-buster-lite.zip
Content-Type: text/html; charset=iso-8859-1
# so I renamed raspbian_lite_latest to 2019-09-26-raspbian-buster-lite.zip
$ mv raspbian_lite_latest 2019-09-26-raspbian-buster-lite.zip
I'm don't know of an easier way to use curl
to follow the redirect and use the name of the file. If you know, please let me know. If you want to get funky, you could use something like the following instruction, but that seems to mee a little convoluted:
1
2
3
4
5
# we are obtaining the name from the curl command inside the backticks
# then asking curl to download from that URL and use the name of the file
# I'm not sure this is easier, it seems too much, but there you have
# it. Do with that knowledge what you want.
$ curl -O `curl https://downloads.raspberrypi.org/raspbian_lite_latest -s -L -I -o /dev/null -w '%{url_effective}'`
Anyways, you should have the image on your folder. Extract the image:
1
2
#In my case the file is 2019-09-26-raspbian-buster-lite.zip
$ unzip 2019-09-26-raspbian-buster-lite.zip
Now we have everything we need to boot up our machine. You should have something similar to this directory structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
raspbian_vm/
├── 2019-09-26-raspbian-buster-lite.img
├── 2019-09-26-raspbian-buster-lite.zip
└── qemu-rpi-kernel
├── kernel-qemu-3.10.25-wheezy
├── kernel-qemu-4.14.79-stretch
├── kernel-qemu-4.19.50-buster
├── kernel-qemu-4.4.34-jessie
├── README.md
├── tools
│ ├── build-kernel-qemu
│ ├── build-kernel-qemu.conf-4.14.79
│ ├── config_file
│ ├── config_file_3.10.25
│ ├── config_file_4.19.50
│ ├── config_file_4.4.34
│ ├── config_ip_tables
│ ├── config_loopdev
│ ├── config_webcam
│ ├── linux-arm-4.4.34.patch
│ ├── linux-arm.patch
│ ├── qemu_choose_vm.sh
│ └── README.md
└── versatile-pb.dtb
2 directories, 21 files
We are ready to boot up our VM.
Booting up our Raspbian OS image
Now that we have all the missing pieces, we can put them together on one command, don't run it just yet.
1
2
3
4
5
6
7
8
9
10
11
12
$ qemu-system-arm \
-M versatilepb \
-cpu arm1176 \
-m 256 \
-hda ./2019-09-26-raspbian-buster-lite.img \
-net nic, \
-net user,hostfwd=tcp::5022-:22 \
-dtb ./qemu-rpi-kernel/versatile-pb.dtb \
-kernel ./qemu-rpi-kernel/kernel-qemu-4.19.50-buster \
-append 'root=/dev/sda2 panic=1' \
-no-reboot \
-nographic
Let's break it apart and understand what we are doing (some options are self-explanatory):
-M versatilepb
- specify the machine typeversatilepb
.-cpu arm1176
- specify the CPU we are going to use asarm1176
.-m 256
- specify the machine memory to be 256Mb.-hda ./2019-09-26-raspbian-buster-lite.img
- We tell QEMU to use the image file as the hard drive.-net nic
- Creates a network interface.-net user,hostfwd=tcp::5022-:22
- We are mapping the ssh port (22) to the local port 5022, so we can later justssh -p5022 localhost
and access the VM.-dtb ./qemu-rpi-kernel/versatile-pb.dtb
- Specify the Device Tree Blob file.-kernel ./qemu-rpi-kernel/kernel-qemu-4.19.50-buster
- Use the file as the kernel.-append 'root=/dev/sda2 panic=1'
- Send these parameters to the kernel. First, specify where to find the root directory, andpanic=1
, just sets the delay to wait after a kernel panic to reboot (You can omit this last parameter if you like).no-reboot
- Exit QEMU on reboot.-nographic
- QEMU supports graphic mode, but we are going to run it just using the command-line, so we are specifying just to use the command line and forego all the graphic window support.
We could run that command every time, but it's a long command, and if we want to tweak something, it becomes messy. So let's create a small bash script to bring our VM up. Create a file called startBusterVM.sh
and add the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
set -e
qemu-system-arm \
-M versatilepb \
-cpu arm1176 \
-m 256 \
-hda ./2019-09-26-raspbian-buster-lite.img \
-net nic, \
-net user,hostfwd=tcp::5022-:22 \
-dtb ./qemu-rpi-kernel/versatile-pb.dtb \
-kernel ./qemu-rpi-kernel/kernel-qemu-4.19.50-buster \
-append 'root=/dev/sda2 panic=1' \
-no-reboot \
-nographic
Add execution permissions and run it:
1
2
$ chmod u+x startBusterVM.sh
$ ./startBusterVM.sh
Now you can log in to your new machine! (Default user is pi
password: raspberry
, make sure to change it after login).
And that's it. You have a VM you can use for your ARM explorations.
SSH configuration
Before we are entirely done with the machine, we would like to enable ssh to login into the VM.
While logged in the VM, let's activate the SSH server, it's off by default.
1
2
3
4
5
$ sudo raspi-config
# 1. Navigate to Interfacing Options
# 2. SSH (Option number two in my case)
# 3. Select Yes when prompted to enable ssh.
# You'll get a message that it was enabled, and now you can exit (Finish).
If you haven't changed your default password, do it now, else you might get refused to login because your user has the default password. To change the password, use the passwd
command:
1
2
$ passwd
# Change your password
Let's restart the VM:
1
2
3
4
# Shutdown "halt" the computer
$ sudo shutdown -h now
#You can use our script to run the VM again
$ ./startBusterVM.sh
I prefer to log in from another terminal via ssh, so I get a nice colour terminal instead of the default vt220
.
You can log in from your computer via ssh using the port we configured:
1
$ ssh pi@localhost -p5022
You'll be prompted for the user password. You can keep writing the password like a barbarian, or you could change to using key pairs. If you don't know how to do this, check the post I wrote about Understanding SSH Keys and using Keychain to manage passphrase on macOS. The process is the same except you don't have the Keychain in Linux, but everything else applies. You would remove the line UseKeychain yes
from your ~/.ssh/config
.
Only one more small configuration left (that you can skip).
Change the prompt colour
I want to make it clear for me when I'm inside the VM, so I usually change the colour of the shell's prompt. This step is optional, but I find it useful. Let's edit your .bashrc
. Search for PS1
. This variable contains the format of your prompt.
1
2
3
4
5
6
7
#change
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] '
# you see the Ansi sequence [\033[01;32m\]\u
# [01;32m] is colour green
# let's change it to red [\033[01;31m\]\u
# Your PS1 should look like this:
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] '
Save and exit. Now, reload the bashrc
.
1
$ source ~/.bashrc
Your prompt should be displayed in red and will make you realise that you are in the raspberry VM.
Ok, that's it, enjoy playing with your VM.
Final thoughts
Virtualisation is such a handy technology. We don't have to carry around a lot of devices we can have a powerful computer and emulate the rest.
Keep in mind that sometimes the VM won't behave the same way as the real computer. Virtualisation is useful for some scenarios, but if you want to develop for ARM or any other architecture, make sure you test it on that architecture and not only on a VM.
As you saw the instructions in this post were specific to one distribution and one architecture. Still, I tried to explain the details so you can understand the steps you'll need for emulating a different architecture. You now know that you'll need a kernel, an Image, and a Device Tree Blob, you can now search the specifics for the flavour you desire.
I hope this was helpful, as always, feedback is welcomed.
Related topics/notes of interest
- If you want to build your own QEMU image have a look at this post.
- Device Tree For dummies
- A stack overflow answer that explains how to use ssh-agent.
- A docker image that gives you access to an emulated Raspberry Pi via QEMU.
- The repository for the Kernels for Raspberry PI images that work on QUEMU.