QEMU
Machine emulator that runs foreign-architecture binaries and full firmware images, so you can execute and debug embedded code without the physical device.
QEMU is a machine emulator that runs binaries and whole firmware images built for foreign CPU architectures, letting you execute and debug embedded code on your x86 laptop without the physical device. It is the standard way to bring a router daemon, an IoT service, or an entire extracted root filesystem to life when you do not have (or do not want to touch) the real hardware.
What it is
QEMU has two modes that matter for firmware work. In user mode (qemu-arm, qemu-mips, ...) it runs a single cross-architecture Linux binary by translating its instructions and forwarding its syscalls to your host kernel, no full OS required. In system mode (qemu-system-arm, ...) it emulates an entire machine: CPU, memory, and a set of virtual peripherals, so you can boot a kernel and userland as if on real silicon. User mode is fast and perfect for poking at one extracted binary; system mode is heavier but necessary when a program needs a real kernel, /proc, or hardware around it.
Why it matters
Firmware you carve out of a flash dump is code for the wrong CPU. QEMU is what lets you actually run it: execute a suspicious CGI binary to watch its behaviour, attach a debugger to a service that only exists as an ARM/MIPS ELF, or bring up a whole extracted rootfs to reach a web interface and fuzz it, all from x86. Dynamic analysis catches things static reversing misses, and QEMU is the cheapest way to get a foreign binary under a debugger without a lab full of dev boards.
How to use it
qemu-arm-static ./busybox # run one foreign (ARM) binary directly
# Analyse a binary from within a chroot of the extracted rootfs:
cp $(which qemu-mips-static) ./rootfs/usr/bin/ # drop a static QEMU inside the rootfs
sudo chroot ./rootfs /bin/sh # now foreign binaries run transparently
# Emulate a full system and expose a GDB stub on :1234, halted at reset:
qemu-system-arm -M versatilepb -kernel zImage -gdb tcp::1234 -S
The two everyday patterns are: (1) copy a qemu-<arch>-static into an extracted rootfs and chroot into it so every foreign binary just runs, and (2) qemu-system-* a full board and attach gdb to the -gdb tcp::1234 stub for source-level debugging. Register qemu-*-static with binfmt_misc and the chroot step becomes automatic, the kernel invokes QEMU for you whenever a foreign ELF is executed.
Pitfalls
- Missing peripherals break many firmwares. Real devices expect NVRAM, custom chips, and hardware registers QEMU does not model; the binary reads a nonexistent device and crashes. Wrappers like FirmAE and firmadyne exist precisely to stub these out.
- Endianness and ABI must match exactly.
qemu-mips(big-endian) andqemu-mipsel(little-endian) are different runtimes; picking the wrong one yields an immediateInvalid ELFor garbage. - User mode is not a sandbox. A binary run under
qemu-arm-staticstill makes real syscalls on your host. Run untrusted firmware in a throwaway VM or container. - Full-system emulation needs the right machine model (
-M). The genericversatilepbrarely matches a specific router SoC, and getting a clean boot often takes a custom device tree or a purpose-built board.
What it pairs with
binwalk extracts the firmware image and root filesystem that you feed into QEMU. Once a binary is running under the -gdb stub, gdb drives the dynamic session. For the static side of the same analysis, disassemble the binary in ghidra or radare2 and use QEMU to confirm what the code actually does at runtime.