# `pwnlib.shellcraft.aarch64` — Shellcode for AArch64

## `pwnlib.shellcraft.aarch64`

pwnlib.shellcraft.aarch64.breakpoint()

  Inserts a debugger breakpoint (raises SIGTRAP).

  Example

      >>> run_assembly(shellcraft.breakpoint()).poll(True)
      -5

pwnlib.shellcraft.aarch64.crash()

  Crashes the process.

  Example

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

pwnlib.shellcraft.aarch64.infloop()

  An infinite loop.

  Example

      >>> io = run_assembly(shellcraft.infloop())
      >>> io.recvall(timeout=1)
      b''
      >>> io.close()

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

  Copies memory.

  Parameters:

    - dest – Destination address

    - src – Source address

    - n – Number of bytes

pwnlib.shellcraft.aarch64.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.mov('x0','x1').rstrip())
          mov  x0, x1
      >>> print(shellcraft.mov('x0','0').rstrip())
          mov  x0, xzr
      >>> print(shellcraft.mov('x0', 9).rstrip())
          mov  x0, #9
      >>> print(shellcraft.mov('x0', 0x94532).rstrip())
          /* Set x0 = 607538 = 0x94532 */
          mov  x0, #17714
          movk x0, #9, lsl #16

  Parameters:

    - dest (str) – The destination register.

    - src (str) – Either the input register, or an immediate value.

pwnlib.shellcraft.aarch64.push(value, register1='x14', register2='x15')

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

  If src is a string, then we try to evaluate 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.

  Note

  AArch64 requires that the stack remain 16-byte aligned at all times, so this alignment is preserved.

  Parameters:

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

    - register1 (str) – Scratch register to use

    - register2 (str) – Second scratch register to use

  Example

      >>> print(pwnlib.shellcraft.push(0).rstrip())
          /* push 0 */
          mov  x14, xzr
          str x14, [sp, #-16]!
      >>> print(pwnlib.shellcraft.push(9).rstrip())
          /* push 9 */
          mov  x14, #9
          str x14, [sp, #-16]!
      >>> print(pwnlib.shellcraft.push(256).rstrip())
          /* push 0x100 */
          mov  x14, #256
          str x14, [sp, #-16]!
      >>> print(pwnlib.shellcraft.push('SYS_execve').rstrip())
          /* push SYS_execve (0xdd) */
          mov  x14, #221
          str x14, [sp, #-16]!
      >>> print(pwnlib.shellcraft.push('SYS_sendfile').rstrip())
          /* push SYS_sendfile (0x47) */
          mov  x14, #71
          str x14, [sp, #-16]!
      >>> with context.local(os = 'freebsd'):
      ...     print(pwnlib.shellcraft.push('SYS_execve').rstrip())
      ...
          /* push SYS_execve (0x3b) */
          mov  x14, #59
          str x14, [sp, #-16]!

pwnlib.shellcraft.aarch64.pushstr(string, append_null=True, register1='x14', register2='x15', pretty=None)

  Pushes a string onto the stack.

  r12 is defined as the inter-procedural scratch register ($ip), so this should not interfere with most usage.

  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

      >>> string = "Hello, world!"
      >>> assembly = shellcraft.pushstr(string)
      >>> assembly += shellcraft.write(1, 'sp', len(string))
      >>> assembly += shellcraft.exit()
      >>> ELF.from_assembly(assembly).process().recvall()
      b'Hello, world!'

      >>> string = "Hello, world! This is a long string! Wow!"
      >>> assembly = shellcraft.pushstr(string)
      >>> assembly += shellcraft.write(1, 'sp', len(string))
      >>> assembly += shellcraft.exit()
      >>> ELF.from_assembly(assembly).process().recvall()
      b'Hello, world! This is a long string! Wow!'

pwnlib.shellcraft.aarch64.pushstr_array(reg, array, register1='x14', register2='x15')

  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.

  Example

      >>> assembly = shellcraft.execve("/bin/sh", ["sh", "-c", "echo Hello string $WORLD"], {"WORLD": "World!"})
      >>> ELF.from_assembly(assembly).process().recvall()
      b'Hello string World!\n'

pwnlib.shellcraft.aarch64.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({'x0':9, 'x2':'x3'}).rstrip())
          mov  x0, #9
          mov  x2, x3
      >>> print(shellcraft.setregs({'x0':'x1', 'x1':'x0', 'x2':'x3'}).rstrip())
          mov  x2, x3
          eor  x0, x0, x1 /* xchg x0, x1 */
          eor  x1, x0, x1
          eor  x0, x0, x1

pwnlib.shellcraft.aarch64.trap()

  Inserts a debugger breakpoint (raises SIGTRAP).

  Example

      >>> run_assembly(shellcraft.breakpoint()).poll(True)
      -5

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

pwnlib.shellcraft.aarch64.linux.cat(filename, fd=1)

  Opens a file and writes its contents to the specified file descriptor.

  Example

      >>> f = tempfile.mktemp()
      >>> write(f, 'This is the flag\n')
      >>> shellcode = shellcraft.cat(f) + shellcraft.exit(0)
      >>> run_assembly(shellcode).recvline()
      b'This is the flag\n'

pwnlib.shellcraft.aarch64.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, 'This is the flag\n')
      >>> shellcode = shellcraft.cat2(f) + shellcraft.exit(0)
      >>> run_assembly(shellcode).recvline()
      b'This is the flag\n'

pwnlib.shellcraft.aarch64.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 x12.

pwnlib.shellcraft.aarch64.linux.dupio(sock='x12')

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

pwnlib.shellcraft.aarch64.linux.dupsh(sock='x12')

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

pwnlib.shellcraft.aarch64.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.aarch64.linux.forkexit()

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

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

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

pwnlib.shellcraft.aarch64.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.aarch64.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)
      >>> loader = shellcraft.loader_append(payloadELF.data)
      >>> loaderELF = ELF.from_assembly(loader, vma=0, shared=True)
      >>> loaderELF.process().recvall()
      b'Hello, world!\n'

pwnlib.shellcraft.aarch64.linux.open(filename, flags='O_RDONLY', mode='x3')

  Opens a file

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

  Execute a different process.

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

pwnlib.shellcraft.aarch64.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.aarch64.linux.socket(network='ipv4', proto='tcp')

  Creates a new socket

pwnlib.shellcraft.aarch64.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.aarch64.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.aarch64.linux.syscall(11, 9, 'sp', 8, 0).rstrip())
          /* call syscall(0xb, 9, 'sp', 8, 0) */
          mov  x0, #9
          add  x1, sp, xzr
          mov  x2, #8
          mov  x3, xzr
          mov  x8, #11
          svc 0
      >>> print(shellcraft.aarch64.linux.syscall('SYS_exit', 0).rstrip())
          /* call exit(0) */
          mov  x0, xzr
          mov  x8, #SYS_exit
          svc 0
      >>> print(pwnlib.shellcraft.openat(-2, '/home/pwn/flag').rstrip())
          /* openat(fd=-2, file='/home/pwn/flag', oflag=0) */
          /* push b'/home/pwn/flag\x00' */
          /* Set x14 = 8606431000579237935 = 0x77702f656d6f682f */
          mov  x14, #26671
          movk x14, #28015, lsl #16
          movk x14, #12133, lsl #0x20
          movk x14, #30576, lsl #0x30
          /* Set x15 = 113668128124782 = 0x67616c662f6e */
          mov  x15, #12142
          movk x15, #27750, lsl #16
          movk x15, #26465, lsl #0x20
          stp x14, x15, [sp, #-16]!
          add  x1, sp, xzr
          /* Set x0 = -2 = -2 */
          mov  x0, #65534
          movk x0, #65535, lsl #16
          movk x0, #65535, lsl #0x20
          movk x0, #65535, lsl #0x30
          mov  x2, xzr
          /* call openat() */
          mov  x8, #SYS_openat
          svc 0