# `pwnlib.shellcraft.thumb` — Shellcode for Thumb Mode

## `pwnlib.shellcraft.thumb`

Shellcraft module containing generic thumb little endian shellcodes.

pwnlib.shellcraft.thumb.crash()

  Crash.

  Example

      >>> run_assembly(shellcraft.crash()).poll(True) < 0
      True

pwnlib.shellcraft.thumb.infloop()

  An infinite loop.

pwnlib.shellcraft.thumb.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.thumb.mov('r0', 0xdeadbeef)
      >>> sc += shellcraft.thumb.itoa('r0')
      >>> sc += shellcraft.thumb.linux.write(1, 'sp', 32)
      >>> run_assembly(sc).recvuntil(b'\x00')
      b'3735928559\x00'

pwnlib.shellcraft.thumb.memcpy(dest, src, n)

  Copies memory.

  Parameters:

    - dest – Destination address

    - src – Source address

    - n – Number of bytes

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

  > Returns THUMB code for moving the specified source value into the specified destination register.

  > If src is a string that is not a register, then it will locally set context.arch to ‘thumb’ 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.

  Example

      >>> print(shellcraft.thumb.mov('r1','r2').rstrip())
          mov r1, r2
      >>> print(shellcraft.thumb.mov('r1', 0).rstrip())
          eor r1, r1
      >>> print(shellcraft.thumb.mov('r1', 10).rstrip())
          mov r1, #0xa + 1
          sub r1, r1, 1
      >>> print(shellcraft.thumb.mov('r1', 17).rstrip())
          mov r1, #0x11
      >>> print(shellcraft.thumb.mov('r1', 'r1').rstrip())
          /* moving r1 into r1, but this is a no-op */
      >>> print(shellcraft.thumb.mov('r1', 512).rstrip())
          mov r1, #0x200
      >>> print(shellcraft.thumb.mov('r1', 0x10000001).rstrip())
          mov r1, #(0x10000001 >> 28)
          lsl r1, #28
          add r1, #(0x10000001 & 0xff)
      >>> print(shellcraft.thumb.mov('r1', 0xdead0000).rstrip())
          mov r1, #(0xdead0000 >> 25)
          lsl r1, #(25 - 16)
          add r1, #((0xdead0000 >> 16) & 0xff)
          lsl r1, #16
      >>> print(shellcraft.thumb.mov('r1', 0xdead00ff).rstrip())
          ldr r1, value_...
          b value_..._after
      value_...: .word 0xdead00ff
      value_..._after:
      >>> with context.local(os = 'linux'):
      ...     print(shellcraft.thumb.mov('r1', 'SYS_execve').rstrip())
          mov r1, #SYS_execve /* 0xb */
      >>> with context.local(os = 'freebsd'):
      ...     print(shellcraft.thumb.mov('r1', 'SYS_execve').rstrip())
          mov r1, #SYS_execve /* 0x3b */
      >>> with context.local(os = 'linux'):
      ...     print(shellcraft.thumb.mov('r1', 'PROT_READ | PROT_WRITE | PROT_EXEC').rstrip())
          mov r1, #(PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */

pwnlib.shellcraft.thumb.nop()

  A nop instruction.

pwnlib.shellcraft.thumb.popad()

  Pop all of the registers onto the stack which i386 popad does, in the same order.

pwnlib.shellcraft.thumb.push(value)

  Pushes a value onto the stack without using null bytes or newline characters.

  If src is a string, then we try to evaluate with context.arch = ‘thumb’ using `pwnlib.constants.eval()` before determining how to push it. Note that this means that this shellcode can change behavior depending on the value of context.os.

  Parameters:

    value (int,str) – The value or register to push

  Example

      >>> print(pwnlib.shellcraft.thumb.push('r0').rstrip())
          push {r0}
      >>> print(pwnlib.shellcraft.thumb.push(0).rstrip())
          /* push 0 */
          eor r7, r7
          push {r7}
      >>> print(pwnlib.shellcraft.thumb.push(1).rstrip())
          /* push 1 */
          mov r7, #1
          push {r7}
      >>> print(pwnlib.shellcraft.thumb.push(256).rstrip())
          /* push 0x100 */
          mov r7, #0x100
          push {r7}
      >>> print(pwnlib.shellcraft.thumb.push('SYS_execve').rstrip())
          /* push 'SYS_execve' */
          mov r7, #0xb
          push {r7}
      >>> with context.local(os = 'freebsd'):
      ...     print(pwnlib.shellcraft.thumb.push('SYS_execve').rstrip())
          /* push 'SYS_execve' */
          mov r7, #0x3b
          push {r7}

pwnlib.shellcraft.thumb.pushad()

  Push all of the registers onto the stack which i386 pushad does, in the same order.

pwnlib.shellcraft.thumb.pushstr(string, append_null=True, register='r7')

  Pushes a string onto the stack without using null bytes or newline characters.

  Parameters:

    - string (str) – The string to push.

    - append_null (bool) – Whether to append a single NULL-byte before pushing.

  Examples:

  Note that this doctest has two possibilities for the first result, depending on your version of binutils.

      >>> enhex(asm(shellcraft.pushstr('Hello\nWorld!', True))) in [
      ... '87ea070780b4dff8047001e0726c642180b4dff8047001e06f0a576f80b4dff8047001e048656c6c80b4',
      ... '87ea070780b4dff8047001e0726c642180b4dff8047001e06f0a576f80b4dff8047001e048656c6c80b400bf',
      ... '87ea070780b4dff8067000f002b8726c642180b4dff8047000f002b86f0a576f80b4014f00f002b848656c6c80b4']
      True
      >>> print(shellcraft.pushstr('abc').rstrip())
          /* push b'abc\x00' */
          ldr r7, value_...
          b value_..._after
      value_...: .word 0xff636261
      value_..._after:
          lsl r7, #8
          lsr r7, #8
          push {r7}
      >>> print(enhex(asm(shellcraft.pushstr('\x00', False)).rstrip(b'\x00\xbf')))
      87ea070780b4

pwnlib.shellcraft.thumb.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.thumb.ret(return_value=None)

  A single-byte RET instruction.

  Parameters:

    return_value – Value to return

pwnlib.shellcraft.thumb.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.thumb.to_arm(reg=None, avoid=[])

  Go from THUMB to ARM mode.

pwnlib.shellcraft.thumb.trap()

  A trap instruction.

pwnlib.shellcraft.thumb.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.thumb.linux`

Shellcraft module containing THUMB shellcodes for Linux.

pwnlib.shellcraft.thumb.linux.bindsh(port, network)

  Listens on a TCP port and spawns a shell for the first to connect. Port is the TCP port to listen on, network is either ‘ipv4’ or ‘ipv6’.

pwnlib.shellcraft.thumb.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.to_thumb()+shellcraft.thumb.linux.cat(f)).recvline()
      b'FLAG\n'

pwnlib.shellcraft.thumb.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.to_thumb()+shellcraft.thumb.linux.cat2(f)).recvline()
      b'FLAG\n'

pwnlib.shellcraft.thumb.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.thumb.linux.connectstager(host, port, network='ipv4')

  connect recvsize stager :param host: :param where to connect to: :param port: :param which port to connect to: :param network: ipv4) :param ipv4 or ipv6? (default: ipv4)

pwnlib.shellcraft.thumb.linux.dupio(sock='r6')

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

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

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

pwnlib.shellcraft.thumb.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.thumb.linux.findpeer(port)

  Finds a connected socket. If port is specified it is checked against the peer port. Resulting socket is left in r6.

  Example

      >>> enhex(asm(shellcraft.findpeer(1337)))
      '6ff00006ee4606f101064ff001074fea072707f11f07f54630461fb401a96a4601df0130efdd01994fea11414ff039024fea022202f105029142e4d1'

pwnlib.shellcraft.thumb.linux.findpeersh(port)

  Finds a connected socket. If port is specified it is checked against the peer port. A dup2 shell is spawned on it.

pwnlib.shellcraft.thumb.linux.findpeerstager(port=None)

  Findpeer recvsize stager :param port: :type port: defaults to any :param the port given to findpeer: :type the port given to findpeer: defaults to any

pwnlib.shellcraft.thumb.linux.forkbomb()

  Performs a forkbomb attack.

pwnlib.shellcraft.thumb.linux.forkexit()

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

pwnlib.shellcraft.thumb.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.thumb.linux.killparent()

  Kills its parent process until whatever the parent is (probably init) cannot be killed any longer.

pwnlib.shellcraft.thumb.linux.listen(port, network)

  Listens on a TCP port, accept a client and leave his socket in r6. Port is the TCP port to listen on, network is either ‘ipv4’ or ‘ipv6’.

  Example

      >>> enhex(asm(shellcraft.listen(1337, 'ipv4')))
      '4ff001074fea072707f119074ff002004ff0010182ea020201df0646004901e00200053906b469464ff0100207f1010701df30464ff0010107f1020701df304681ea010182ea020207f1010701df0646'

pwnlib.shellcraft.thumb.linux.loader(address)

  Loads a statically-linked ELF into memory and transfers control.

  Parameters:

    address (int) – Address of the ELF as a register or integer.

pwnlib.shellcraft.thumb.linux.loader_append(data=None)

  Loads a statically-linked ELF into memory and transfers control.

  Similar to loader.asm but loads an appended ELF.

  Parameters:

    data (str) – If a valid filename, the data is loaded from the named file. Otherwise, this is treated as raw ELF data to append. If `None`, it is ignored.

  Example:

  The following doctest is commented out because it doesn’t work on Travis for reasons I cannot diagnose. However, it should work just fine :-)

      >>> payload = shellcraft.echo(b'Hello, world!\n') + shellcraft.exit(0)
      >>> payloadELF = ELF.from_assembly(payload)
      >>> payloadELF.arch
      'arm'
      >>> loader = shellcraft.loader_append(payloadELF.data)
      >>> loaderELF = ELF.from_assembly(loader, vma=0, shared=True)
      >>> loaderELF.process().recvall()
      b'Hello, world!\n'

pwnlib.shellcraft.thumb.linux.readfile(path, dst='r6')

  Args: [path, dst (imm/reg) = r6 ] Opens the specified file path and sends its content to the specified file descriptor. Leaves the destination file descriptor in r6 and the input file descriptor in r5.

pwnlib.shellcraft.thumb.linux.readn(fd, buf, nbytes)

  Reads exactly nbytes bytes from file descriptor fd into the buffer buf.

  Parameters:

    - fd (int) – fd

    - buf (void) – buf

    - nbytes (size_t) – nbytes

pwnlib.shellcraft.thumb.linux.recvsize(sock, reg='r1')

  Recives 4 bytes size field Useful in conjuncion with findpeer and stager :param sock: :param the socket to read the payload from.: :param reg: :type reg: default ecx :param the place to put the size: :type the place to put the size: default ecx

  Leaves socket in ebx

pwnlib.shellcraft.thumb.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.thumb.linux.sh()

  Execute a different process.

      >>> p = run_assembly(shellcraft.thumb.linux.sh())
      >>> p.sendline(b'echo Hello')
      >>> p.recv()
      b'Hello\n'

pwnlib.shellcraft.thumb.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.thumb.linux.stage(fd=0, length=None)

  Migrates shellcode to a new buffer.

  Parameters:

    - fd (int) – Integer file descriptor to recv data from. Default is stdin (0).

    - length (int) – Optional buffer length. If None, the first pointer-width of data received is the length.

  Example

      >>> p = run_assembly(shellcraft.stage())
      >>> sc = asm(shellcraft.echo("Hello\n", constants.STDOUT_FILENO))
      >>> p.pack(len(sc))
      >>> p.send(sc)
      >>> p.recvline()
      b'Hello\n'

pwnlib.shellcraft.thumb.linux.stager(sock, size)

  Read ‘size’ bytes from ‘sock’ and place them in an executable buffer and jump to it. The socket will be left in r6.

pwnlib.shellcraft.thumb.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.thumb.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
          mov r7, #0xb
          svc 0x41
      >>> print(shellcraft.thumb.linux.syscall('SYS_exit', 0).rstrip())
          /* call exit(0) */
          eor r0, r0
          mov r7, #SYS_exit /* 1 */
          svc 0x41
      >>> print(pwnlib.shellcraft.open('/home/pwn/flag').rstrip())
          /* open(file='/home/pwn/flag', oflag=0, mode=0) */
          /* push b'/home/pwn/flag\x00' */
          mov r7, #(0x6761 >> 8)
          lsl r7, #8
          add r7, #(0x6761 & 0xff)
          push {r7}
          ldr r7, value_...
          b value_..._after
      value_...: .word 0x6c662f6e
      value_..._after:
          push {r7}
          ldr r7, value_...
          b value_..._after
      value_...: .word 0x77702f65
      value_..._after:
          push {r7}
          ldr r7, value_...
          b value_..._after
      value_...: .word 0x6d6f682f
      value_..._after:
          push {r7}
          mov r0, sp
          eor r1, r1
          eor r2, r2
          /* call open() */
          mov r7, #SYS_open /* 5 */
          svc 0x41