MIPS Reversing
reversingintermediate
Reverse engineer MIPS binaries in CTF challenges - embedded systems, routers, IoT.
reversingmipsmipselqemughidraembeddediot
MIPS Reversing
MIPS is common in embedded systems, routers, and IoT devices. CTF challenges sometimes provide MIPS binaries extracted from firmware. Like ARM, Ghidra handles MIPS natively — the decompilation workflow is the same as x86. The main differences are register names, calling conventions, and the branch delay slot.
Identifying MIPS Binary
file challenge
# → ELF 32-bit MSB executable, MIPS, MIPS-I version 1
# → ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (MIPSEL)
# MSB = big-endian, LSB = little-endian (MIPSEL)Running with QEMU
sudo apt install qemu-user qemu-user-static
# Run MIPS big-endian
qemu-mips ./mips_binary
# Run MIPS little-endian
qemu-mipsel ./mipsel_binary
# With libraries
sudo apt install libc6-mips-cross libc6-mipsel-cross
qemu-mips -L /usr/mips-linux-gnu ./mips_binaryMIPS Assembly Key Concepts
; Registers
$zero / $0 = always 0
$v0, $v1 = return values
$a0-$a3 = function arguments
$t0-$t9 = temporaries (caller-saved)
$s0-$s7 = saved (callee-saved)
$sp = stack pointer
$ra = return address (like ARM's LR)
; Key instructions
addiu $t0, $t1, 42 ; t0 = t1 + 42
lw $t0, 0($sp) ; t0 = memory[sp+0]
sw $t0, 4($sp) ; memory[sp+4] = t0
xor $t0, $t1, $t2 ; t0 = t1 XOR t2
beq $t0, $t1, label ; branch if equal
jal func ; call func (ra = return addr)
jr $ra ; return from functionMIPS Delay Slots
MIPS has branch delay slots — the instruction after a branch always executes before the branch takes effect:
beq $t0, $t1, target ; branch if equal
addiu $t0, $t0, 1 ; this ALWAYS executes (delay slot!)
; branch happens hereGhidra handles this automatically in decompilation.
Ghidra for MIPS
# Import the MIPS binary into Ghidra
# Select "MIPS:BE:32:default" or "MIPS:LE:32:default"
# Auto-analyze → decompileTypical CTF MIPS Pattern
// Decompiled MIPS check function:
int check(char *input) {
char key[] = {0x66, 0x6c, 0x61, 0x67}; // "flag"
for (int i = 0; i < 4; i++) {
if (input[i] != (key[i] ^ 0x10)) return 0;
}
return 1;
}
// → key XOR 0x10: 0x76, 0x7c, 0x71, 0x77 = "v|qw"Checklist
-
file→ MIPS MSB or MIPSEL (little-endian)? -
qemu-mipsorqemu-mipselto run - Ghidra: select correct MIPS variant when importing
- Remember delay slots (Ghidra handles automatically)
- Arguments:
$a0-$a3, return:$v0 - XOR:
xorinstruction (same as x86 but different syntax) - Return:
jr $ra
Last updated on