This is going to be a series of small and manageable tutorials explaining the ARM processor, how to exploit applications running on ARM, and writing ARM shellcode.
PART 1In this first part, I will give you a quick and dirty intro to the ARM architecture and run you through a small sample application to get your head around it.
ARM INTROYou can easily find a description of ARM on wikipedia [1], hence I'm just gonna go really basic and in relation to knowledge needed for exploitation. The ARM architecture has 13 general purpose registers
- Registers 0-3 are general purpose registers used for for function arguments
Register 0 is first argument, 1 is 2nd and so forth.
- Registers 4-12 are general purpose registers
- Register 13 is the stack pointer (SP)
- Register 14 is the link register* (LR)
- Register 15 is the program counter (PC)
Register 0 is also used for return value.
ARM is a RISC arcitechture (reduced instruction set computing) and does not handle complex instruction as in e.g. the i386 which is a CISC (complex instruction st computing). This means we have a more basic set of operators. Lets get right into it and make a small vulnerable application. I'm working on a raspberry pi environment running the raspbian distro.
#include <stdio.h>
#include <string.h>
void exploitme(char * s){
char buf[0x10];
strcpy(buf, s);
}
int main(int ac, char**av){
if (ac < 2){
printf("Usage: %s <string>\n", av[0]);
return -1;
}
exploitme(av[1]);
return 0;
}
And when compiled with gcc we have this snippet of the functions using objdump.
00008400 <exploitme>:
8400: e92d4800 push {fp, lr}
8404: e28db004 add fp, sp, #4
8408: e24dd018 sub sp, sp, #24
840c: e50b0018 str r0, [fp, #-24]
8410: e51b3018 ldr r3, [fp, #-24]
8414: e24b2014 sub r2, fp, #20
8418: e1a00002 mov r0, r2
841c: e1a01003 mov r1, r3
8420: ebffffbf bl 8324 <_init+0x2c>
8424: e24bd004 sub sp, fp, #4
8428: e8bd8800 pop {fp, pc}
0000842c <main>:
842c: e92d4800 push {fp, lr}
8430: e28db004 add fp, sp, #4
8434: e24dd008 sub sp, sp, #8
8438: e50b0008 str r0, [fp, #-8]
843c: e50b100c str r1, [fp, #-12]
8440: e51b3008 ldr r3, [fp, #-8]
8444: e3530001 cmp r3, #1
8448: ca000007 bgt 846c <main+0x40>
844c: e59f203c ldr r2, [pc, #60] ; 8490 <main+0x64>
8450: e51b300c ldr r3, [fp, #-12]
8454: e5933000 ldr r3, [r3]
8458: e1a00002 mov r0, r2
845c: e1a01003 mov r1, r3
8460: ebffffac bl 8318 <_init+0x20>
8464: e3e03000 mvn r3, #0
8468: ea000005 b 8484 <main+0x58>
846c: e51b300c ldr r3, [fp, #-12]
8470: e2833004 add r3, r3, #4
8474: e5933000 ldr r3, [r3]
8478: e1a00003 mov r0, r3
847c: ebffffdf bl 8400 <exploitme>
8480: e3a03000 mov r3, #0
8484: e1a00003 mov r0, r3
8488: e24bd004 sub sp, fp, #4
848c: e8bd8800 pop {fp, pc}
8490: 00008504 andeq r8, r0, r4, lsl #10
A small run down of frequently used opcodes, different from x86.
str r,[m] - store the value r at memory address m
ldr r, [m] - load the value at memory address m to register r
b m - PC = m (continue execution from address at m)
bl m - LR = PC+4 and PC = m.
ARM has a great reference for their instructions[2] online for your pleasure. If you have previous experience with x86, you will notice that the functions are heavily based on the same parts.
1. Main
1.1 The main starts by saving frame pointer and link register on the stack
1.2 It then saves the arguments from r0 and r1 on the stack at fp-8 and fp-12
We get have a stack layout of:
0xFFFFFFFF
...
<Return address / link address> <--- fp
<saved frame pointer>
<argc>
<argv>
...
0x00000000
1.3 It then finally loads the first argument (argc) and branches to
0x846c on greater than 1.
1.4 At 0x846c main starts setting up arguments for the call to exploit me,
by loading argv into r3, choosing the 2nd index and placing the pointer
in argument 1.
1.5 Main then branches and links to exploitme
2. Exploitme
2.1 The prologue of exploitme is almost the same. Starts by savin FP and the
link address.
2.2 Makes room for the local buffer and stores the exploitme argument on the
stack
2.3 Moves the address of the local buffer to argument 1 in register 0,
and the 2nd argument, the source, in register 1
2.4 branch and link strcpy (init+0x20 is the .plt address to call strcpy)
See if you can connect the different parts on your own in the disassembly output.
This is the end of part 1. In the second part we will get into the binary and see what we can get from this. Please provide comments and improvements as you feel. If you noticed any mistakes then tell me.
References
[1]
http://en.wikipedia.org/wiki/ARM_architecture[2]
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/CIHEDHIF.html