# `pwnlib.asm` — Assembler functions

Utilities for assembling and disassembling code.

## Architecture Selection

> Architecture, endianness, and word size are selected by using `pwnlib.context`.

> Any parameters which can be specified to `context` can also be specified as keyword arguments to either `asm()` or `disasm()`.

## Assembly

> To assemble code, simply invoke `asm()` on the code to assemble.

>     >>> asm('mov eax, 0')
>     b'\xb8\x00\x00\x00\x00'

> Additionally, you can use constants as defined in the `pwnlib.constants` module.

>     >>> asm('mov eax, SYS_execve')
>     b'\xb8\x0b\x00\x00\x00'

> Finally, `asm()` is used to assemble shellcode provided by `pwntools` in the `shellcraft` module.

>     >>> asm(shellcraft.nop())
>     b'\x90'

## Disassembly

> To disassemble code, simply invoke `disasm()` on the bytes to disassemble.

>     >>> disasm(b'\xb8\x0b\x00\x00\x00')
>     '   0:   b8 0b 00 00 00          mov    eax, 0xb'

pwnlib.asm.asm(code, vma = 0, extract = True, shared = False, ...) → str

  Runs `cpp()` over a given shellcode and then assembles it into bytes.

  To see which architectures or operating systems are supported, look in `pwnlib.context`.

  Assembling shellcode requires that the GNU assembler is installed for the target architecture. See Installing Binutils for more information.

  Parameters:

    - shellcode (str) – Assembler code to assemble.

    - vma (int) – Virtual memory address of the beginning of assembly

    - extract (bool) – Extract the raw assembly bytes from the assembled file. If `False`, returns the path to an ELF file with the assembly embedded.

    - shared (bool) – Create a shared object.

    - kwargs (dict) – Any attributes on `context` can be set, e.g.set `arch='arm'`.

  Examples

      >>> asm("mov eax, SYS_select", arch = 'i386', os = 'freebsd')
      b'\xb8]\x00\x00\x00'
      >>> asm("mov eax, SYS_select", arch = 'amd64', os = 'linux')
      b'\xb8\x17\x00\x00\x00'
      >>> asm("mov rax, SYS_select", arch = 'amd64', os = 'linux')
      b'H\xc7\xc0\x17\x00\x00\x00'
      >>> asm("mov r0, #SYS_select", arch = 'arm', os = 'linux', bits=32)
      b'R\x00\xa0\xe3'
      >>> asm("mov #42, r0", arch = 'msp430')
      b'0@*\x00'
      >>> asm("la %r0, 42", arch = 's390', bits=64)
      b'A\x00\x00*'

pwnlib.asm.cpp(shellcode, ...) → str

  Runs CPP over the given shellcode.

  The output will always contain exactly one newline at the end.

  Parameters:

    shellcode (str) – Shellcode to preprocess

  Kwargs:

    Any arguments/properties that can be set on `context`

  Examples

      >>> cpp("mov al, SYS_setresuid", arch = "i386", os = "linux")
      'mov al, 164\n'
      >>> cpp("weee SYS_setresuid", arch = "arm", os = "linux")
      'weee (0+164)\n'
      >>> cpp("SYS_setresuid", arch = "thumb", os = "linux")
      '(0+164)\n'
      >>> cpp("SYS_setresuid", os = "freebsd")
      '311\n'

pwnlib.asm.disasm(data, ...) → str

  Disassembles a bytestring into human readable assembler.

  To see which architectures are supported, look in `pwnlib.contex`.

  Parameters:

    - data (str) – Bytestring to disassemble.

    - vma (int) – Passed through to the –adjust-vma argument of objdump

    - byte (bool) – Include the hex-printed bytes in the disassembly

    - offset (bool) – Include the virtual memory address in the disassembly

  Kwargs:

    Any arguments/properties that can be set on `context`

  Examples

      >>> print(disasm(unhex('b85d000000'), arch = 'i386'))
         0:   b8 5d 00 00 00          mov    eax, 0x5d
      >>> print(disasm(unhex('b85d000000'), arch = 'i386', byte = 0))
         0:   mov    eax, 0x5d
      >>> print(disasm(unhex('b85d000000'), arch = 'i386', byte = 0, offset = 0))
      mov    eax, 0x5d
      >>> print(disasm(unhex('b817000000'), arch = 'amd64'))
         0:   b8 17 00 00 00          mov    eax, 0x17
      >>> print(disasm(unhex('48c7c017000000'), arch = 'amd64'))
         0:   48 c7 c0 17 00 00 00    mov    rax, 0x17
      >>> print(disasm(unhex('04001fe552009000'), arch = 'arm'))
         0:   e51f0004        ldr     r0, [pc, #-4]   ; 0x4
         4:   00900052        addseq  r0, r0, r2, asr r0
      >>> print(disasm(unhex('4ff00500'), arch = 'thumb', bits=32))
         0:   f04f 0005       mov.w   r0, #5
      >>> print(disasm(unhex('656664676665400F18A4000000000051'), byte=0, arch='amd64'))
         0:   gs data16 fs rex nop WORD PTR gs:[eax+eax*1+0x0]
         f:   push   rcx
      >>> print(disasm(unhex('01000000'), arch='sparc64'))
         0:   01 00 00 00     nop
      >>> print(disasm(unhex('60000000'), arch='powerpc64'))
         0:   60 00 00 00     nop
      >>> print(disasm(unhex('00000000'), arch='mips64'))
         0:   00000000        nop
      >>> print(disasm(unhex('48b84141414141414100c3'), arch='amd64'))
         0:   48 b8 41 41 41 41 41 41 41 00   movabs rax, 0x41414141414141
         a:   c3                      ret
      >>> print(disasm(unhex('00000000'), vma=0x80000000, arch='mips'))
      80000000:       00000000        nop

pwnlib.asm.make_elf(data, vma=None, strip=True, extract=True, shared=False, **kwargs) → str

  Builds an ELF file with the specified binary data as its executable code.

  Parameters:

    - data (str) – Assembled code

    - vma (int) – Load address for the ELF file

    - strip (bool) – Strip the resulting ELF file. Only matters if `extract=False`. (Default: `True`)

    - extract (bool) – Extract the assembly from the ELF file. If `False`, the path of the ELF file is returned. (Default: `True`)

    - shared (bool) – Create a Dynamic Shared Object (DSO, i.e. a `.so`) which can be loaded via `dlopen` or `LD_PRELOAD`.

  Examples

  This example creates an i386 ELF that just does execve(‘/bin/sh’,…).

      >>> context.clear(arch='i386')
      >>> bin_sh = unhex('6a68682f2f2f73682f62696e89e331c96a0b5899cd80')
      >>> filename = make_elf(bin_sh, extract=False)
      >>> p = process(filename)
      >>> p.sendline(b'echo Hello; exit')
      >>> p.recvline()
      b'Hello\n'

pwnlib.asm.make_elf_from_assembly(assembly, vma=None, extract=None, shared=False, strip=False, **kwargs) → str

  Builds an ELF file with the specified assembly as its executable code.

  This differs from `make_elf()` in that all ELF symbols are preserved, such as labels and local variables. Use `make_elf()` if size matters. Additionally, the default value for `extract` in `make_elf()` is different.

  Note

  This is effectively a wrapper around `asm()`. with setting `extract=False`, `vma=0x10000000`, and marking the resulting file as executable (`chmod +x`).

  Note

  ELF files created with arch=thumb will prepend an ARM stub which switches to Thumb mode.

  Parameters:

    - assembly (str) – Assembly code to build into an ELF

    - vma (int) – Load address of the binary (Default: `0x10000000`, or `0` if `shared=True`)

    - extract (bool) – Extract the full ELF data from the file. (Default: `False`)

    - shared (bool) – Create a shared library (Default: `False`)

    - kwargs (dict) – Arguments to pass to `asm()`.

  Returns:

    The path to the assembled ELF (extract=False), or the data of the assembled ELF.

  Example

  This example shows how to create a shared library, and load it via `LD_PRELOAD`.

      >>> context.clear()
      >>> context.arch = 'amd64'
      >>> sc = 'push rbp; mov rbp, rsp;'
      >>> sc += shellcraft.echo('Hello\n')
      >>> sc += 'mov rsp, rbp; pop rbp; ret'
      >>> solib = make_elf_from_assembly(sc, shared=1)
      >>> subprocess.check_output(['echo', 'World'], env={'LD_PRELOAD': solib}, universal_newlines = True)
      'Hello\nWorld\n'

  The same thing can be done with `make_elf()`, though the sizes are different. They both

      >>> file_a = make_elf(asm('nop'), extract=True)
      >>> file_b = make_elf_from_assembly('nop', extract=True)
      >>> file_a[:4] == file_b[:4]
      True
      >>> len(file_a) < len(file_b)
      True

## Internal Functions

These are only included so that their tests are run.

You should never need these.

pwnlib.asm.dpkg_search_for_binutils(arch, util)

  Use dpkg to search for any available assemblers which will work.

  Returns:

    A list of candidate package names.

      >>> pwnlib.asm.dpkg_search_for_binutils('aarch64', 'as')
      ['binutils-aarch64-linux-gnu']

pwnlib.asm.print_binutils_instructions(util, context)

  On failure to find a binutils utility, inform the user of a way they can get it easily.

  Doctest:

      >>> context.clear(arch = 'amd64')
      >>> pwnlib.asm.print_binutils_instructions('as', context)
      Traceback (most recent call last):
      ...
      PwnlibException: Could not find 'as' installed for ContextType(arch = 'amd64', bits = 64, endian = 'little')
      Try installing binutils for this architecture:
      $ sudo apt-get install binutils