pwnlib.shellcraft.arm — Shellcode for ARM
pwnlib.shellcraft.arm
Shellcraft module containing generic ARM little endian shellcodes.
- pwnlib.shellcraft.arm.crash()[source]
Crash.
Example
>>> run_assembly(shellcraft.crash()).poll(True) -11
- pwnlib.shellcraft.arm.itoa(v, buffer='sp', allocate_stack=True)[source]
Converts an integer into its string representation, and pushes it onto the stack. Uses registers r0-r5.
- Parameters:
v (str, int) – Integer constant or register that contains the value to convert.
alloca
Example
>>> sc = shellcraft.arm.mov('r0', 0xdeadbeef) >>> sc += shellcraft.arm.itoa('r0') >>> sc += shellcraft.arm.linux.write(1, 'sp', 32) >>> run_assembly(sc).recvuntil(b'\x00') b'3735928559\x00'
- pwnlib.shellcraft.arm.memcpy(dest, src, n)[source]
Copies memory.
- Parameters:
dest – Destination address
src – Source address
n – Number of bytes
- pwnlib.shellcraft.arm.mov(dst, src)[source]
Move src into dest.
Support for automatically avoiding newline and null bytes has to be done.
If src is a string that is not a register, then it will locally set context.arch to ‘arm’ and use
pwnlib.constants.eval()to evaluate the string. Note that this means that this shellcode can change behavior depending on the value of context.os.Examples
>>> print(shellcraft.arm.mov('r0','r1').rstrip()) mov r0, r1 >>> print(shellcraft.arm.mov('r0', 5).rstrip()) mov r0, #5 >>> print(shellcraft.arm.mov('r0', 0x34532).rstrip()) movw r0, #0x34532 & 0xffff movt r0, #0x34532 >> 16 >>> print(shellcraft.arm.mov('r0', 0x101).rstrip()) movw r0, #0x101 >>> print(shellcraft.arm.mov('r0', 0xff << 14).rstrip()) mov r0, #0x3fc000 >>> print(shellcraft.arm.mov('r0', 0xff << 15).rstrip()) movw r0, #0x7f8000 & 0xffff movt r0, #0x7f8000 >> 16 >>> print(shellcraft.arm.mov('r0', 0xf00d0000).rstrip()) eor r0, r0 movt r0, #0xf00d0000 >> 16 >>> print(shellcraft.arm.mov('r0', 0xffff00ff).rstrip()) mvn r0, #(0xffff00ff ^ (-1)) >>> print(shellcraft.arm.mov('r0', 0x1fffffff).rstrip()) mvn r0, #(0x1fffffff ^ (-1))
- Parameters:
dest (str) – ke destination register.
src (str) – Either the input register, or an immediate value.
- pwnlib.shellcraft.arm.push(word, register='r12')[source]
Pushes a 32-bit integer onto the stack. Uses r12 as a temporary register.
r12 is defined as the inter-procedural scartch register ($ip), so this should not interfere with most usage.
- Parameters:
word (int, str) – The word to push
tmpreg (str) – Register to use as a temporary register. R7 is used by default.
- pwnlib.shellcraft.arm.pushstr(string, append_null=True, register='r7')[source]
Pushes a string onto the stack.
- Parameters:
string (str) – The string to push.
append_null (bool) – Whether to append a single NULL-byte before pushing.
register (str) – Temporary register to use. By default, R7 is used.
Examples
>>> print(shellcraft.arm.pushstr("Hello!").rstrip()) /* push b'Hello!\x00A' */ movw r7, #0x4100216f & 0xffff movt r7, #0x4100216f >> 16 push {r7} movw r7, #0x6c6c6548 & 0xffff movt r7, #0x6c6c6548 >> 16 push {r7}
- pwnlib.shellcraft.arm.pushstr_array(reg, array)[source]
Pushes an array/envp-style array of pointers onto the stack.
- Parameters:
reg (str) – Destination register to hold the pointer.
array (str,list) – Single argument or list of arguments to push. NULL termination is normalized so that each argument ends with exactly one NULL byte.
- pwnlib.shellcraft.arm.ret(return_value=None)[source]
A single-byte RET instruction.
- Parameters:
return_value – Value to return
Examples
>>> with context.local(arch='arm'): ... print(enhex(asm(shellcraft.ret()))) ... print(enhex(asm(shellcraft.ret(0)))) ... print(enhex(asm(shellcraft.ret(0xdeadbeef)))) 1eff2fe1 000020e01eff2fe1 ef0e0be3ad0e4de31eff2fe1
- pwnlib.shellcraft.arm.setregs(reg_context, stack_allowed=True)[source]
Sets multiple registers, taking any register dependencies into account (i.e., given eax=1,ebx=eax, set ebx first).
- Parameters:
reg_context (dict) – Desired register context
stack_allowed (bool) – Can the stack be used?
Example
>>> print(shellcraft.setregs({'r0':1, 'r2':'r3'}).rstrip()) mov r0, #1 mov r2, r3 >>> print(shellcraft.setregs({'r0':'r1', 'r1':'r0', 'r2':'r3'}).rstrip()) mov r2, r3 eor r0, r0, r1 /* xchg r0, r1 */ eor r1, r0, r1 eor r0, r0, r1
- pwnlib.shellcraft.arm.udiv_10(N)[source]
Divides r0 by 10. Result is stored in r0, N and Z flags are updated.
- Code is from generated from here:
https://raw.githubusercontent.com/rofirrim/raspberry-pi-assembler/master/chapter15/magic.py
- With code:
python magic.py 10 code_for_unsigned
- pwnlib.shellcraft.arm.xor(key, address, count)[source]
XORs data a constant value.
- Parameters:
key (int,str) – XOR key either as a 4-byte integer, If a string, length must be a power of two, and not longer than 4 bytes.
address (int) – Address of the data (e.g. 0xdead0000, ‘rsp’)
count (int) – Number of bytes to XOR.
Example
>>> sc = shellcraft.read(0, 'sp', 32) >>> sc += shellcraft.xor(0xdeadbeef, 'sp', 32) >>> sc += shellcraft.write(1, 'sp', 32) >>> io = run_assembly(sc) >>> io.send(cyclic(32)) >>> result = io.recvn(32) >>> expected = xor(cyclic(32), p32(0xdeadbeef)) >>> result == expected True
pwnlib.shellcraft.arm.linux
Shellcraft module containing ARM shellcodes for Linux.
- pwnlib.shellcraft.arm.linux.cacheflush()[source]
Invokes the cache-flush operation, without using any NULL or newline bytes.
Effectively is just:
mov r0, #0 mov r1, #-1 mov r2, #0 swi 0x9F0002
How this works:
… However, SWI generates a software interrupt and to the interrupt handler, 0x9F0002 is actually data and as a result will not be read via the instruction cache, so if we modify the argument to SWI in our self-modifyign code, the argument will be read correctly.
- pwnlib.shellcraft.arm.linux.cat(filename, fd=1)[source]
Opens a file and writes its contents to the specified file descriptor.
Example
>>> f = tempfile.mktemp() >>> write(f, 'FLAG\n') >>> run_assembly(shellcraft.arm.linux.cat(f)).recvline() b'FLAG\n'
- pwnlib.shellcraft.arm.linux.cat2(filename, fd=1, length=16384)[source]
Opens a file and writes its contents to the specified file descriptor. Uses an extra stack buffer and must know the length.
Example
>>> f = tempfile.mktemp() >>> write(f, 'FLAG\n') >>> run_assembly(shellcraft.arm.linux.cat2(f)).recvline() b'FLAG\n'
- pwnlib.shellcraft.arm.linux.connect(host, port, network='ipv4')[source]
Connects to the host on the specified port. Network is either ‘ipv4’ or ‘ipv6’. Leaves the connected socket in R6.
- pwnlib.shellcraft.arm.linux.dir(in_fd='r6', size=2048, allocate_stack=True)[source]
Reads to the stack from a directory.
- Parameters:
in_fd (int/str) – File descriptor to be read from.
size (int) – Buffer size.
allocate_stack (bool) – allocate ‘size’ bytes on the stack.
You can optioanlly shave a few bytes not allocating the stack space.
The size read is left in eax.
- pwnlib.shellcraft.arm.linux.dupio(sock='r6')[source]
Args: [sock (imm/reg) = r6] Duplicates sock to stdin, stdout and stderr
- pwnlib.shellcraft.arm.linux.dupsh(sock='r6')[source]
Args: [sock (imm/reg) = r6] Duplicates sock to stdin, stdout and stderr and spawns a shell.
- pwnlib.shellcraft.arm.linux.echo(string, sock='1')[source]
Writes a string to a file descriptor
Example
>>> run_assembly(shellcraft.echo('hello\n', 1)).recvline() b'hello\n'
- pwnlib.shellcraft.arm.linux.egghunter(egg, start_address=0, double_check=True)[source]
Searches for an egg, which is either a four byte integer or a four byte string. The egg must appear twice in a row if double_check is True. When the egg has been found the egghunter branches to the address following it. If start_address has been specified search will start on the first address of the page that contains that address.
- pwnlib.shellcraft.arm.linux.forkexit()[source]
Attempts to fork. If the fork is successful, the parent exits.
- pwnlib.shellcraft.arm.linux.kill(pid, sig) str[source]
Invokes the syscall kill.
See ‘man 2 kill’ for more information.
- Parameters:
pid (pid_t) – pid
sig (int) – sig
- Returns:
int
- pwnlib.shellcraft.arm.linux.killparent()[source]
Kills its parent process until whatever the parent is (probably init) cannot be killed any longer.
- pwnlib.shellcraft.arm.linux.setresuid(ruid=None, euid=None, suid=None)[source]
Args: [ruid = geteuid(), euid = ruid, suid = ruid] Sets real, effective and saved user ids to given values
- pwnlib.shellcraft.arm.linux.sh()[source]
Execute a different process.
>>> p = run_assembly(shellcraft.arm.linux.sh()) >>> p.sendline(b'echo Hello') >>> p.recv() b'Hello\n'
- pwnlib.shellcraft.arm.linux.sleep(seconds)[source]
Sleeps for the specified amount of seconds.
Uses SYS_nanosleep under the hood. Doesn’t check for interrupts and doesn’t retry with the remaining time.
- Parameters:
seconds (int,float) – The time to sleep in seconds.
- pwnlib.shellcraft.arm.linux.syscall(syscall=None, arg0=None, arg1=None, arg2=None, arg3=None, arg4=None, arg5=None, arg6=None)[source]
- Args: [syscall_number, *args]
Does a syscall
Any of the arguments can be expressions to be evaluated by
pwnlib.constants.eval().Example
>>> print(shellcraft.arm.linux.syscall(11, 1, 'sp', 2, 0).rstrip()) /* call syscall(0xb, 1, 'sp', 2, 0) */ mov r0, #1 mov r1, sp mov r2, #2 eor r3, r3 /* 0 (#0) */ mov r7, #0xb svc 0 >>> print(shellcraft.arm.linux.syscall('SYS_exit', 0).rstrip()) /* call exit(0) */ eor r0, r0 /* 0 (#0) */ mov r7, #SYS_exit /* 1 */ svc 0 >>> print(pwnlib.shellcraft.open('/home/pwn/flag').rstrip()) /* open(file='/home/pwn/flag', oflag=0, mode=0) */ /* push b'/home/pwn/flag\x00A' */ movw r7, #0x41006761 & 0xffff movt r7, #0x41006761 >> 16 push {r7} movw r7, #0x6c662f6e & 0xffff movt r7, #0x6c662f6e >> 16 push {r7} movw r7, #0x77702f65 & 0xffff movt r7, #0x77702f65 >> 16 push {r7} movw r7, #0x6d6f682f & 0xffff movt r7, #0x6d6f682f >> 16 push {r7} mov r0, sp eor r1, r1 /* 0 (#0) */ eor r2, r2 /* 0 (#0) */ /* call open() */ mov r7, #SYS_open /* 5 */ svc 0