# `pwnlib.shellcraft.arm` — Shellcode for ARM

## `pwnlib.shellcraft.arm`

Shellcraft module containing generic ARM little endian shellcodes.

pwnlib.shellcraft.arm.crash()

  Crash.

  Example

      >>> run_assembly(shellcraft.crash()).poll(True)
      -11

pwnlib.shellcraft.arm.infloop()

  An infinite loop.

pwnlib.shellcraft.arm.itoa(v, buffer='sp', allocate_stack=True)

  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)

  Copies memory.

  Parameters:

    - dest – Destination address

    - src – Source address

    - n – Number of bytes

pwnlib.shellcraft.arm.mov(dst, src)

  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.nop()

  A nop instruction.

pwnlib.shellcraft.arm.push(word, register='r12')

  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')

  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)

  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)

  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)

  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.to_thumb(reg=None, avoid=[])

  Go from ARM to THUMB mode.

pwnlib.shellcraft.arm.trap()

  A trap instruction.

pwnlib.shellcraft.arm.udiv_10(N)

  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)

  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()

  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)

  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)

  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')

  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)

  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')

  Args: [sock (imm/reg) = r6] Duplicates sock to stdin, stdout and stderr

pwnlib.shellcraft.arm.linux.dupsh(sock='r6')

  Args: [sock (imm/reg) = r6] Duplicates sock to stdin, stdout and stderr and spawns a shell.

pwnlib.shellcraft.arm.linux.echo(string, sock='1')

  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)

  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.forkbomb()

  Performs a forkbomb attack.

pwnlib.shellcraft.arm.linux.forkexit()

  Attempts to fork. If the fork is successful, the parent exits.

pwnlib.shellcraft.arm.linux.kill(pid, sig) → str

  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()

  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)

  Args: [ruid = geteuid(), euid = ruid, suid = ruid] Sets real, effective and saved user ids to given values

pwnlib.shellcraft.arm.linux.sh()

  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)

  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)
  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