6

It would be very useful to have a pure Python library that could assemble x86, x64, and ARM instructions. Do you have a recommendation?

I don't mind if they are not pure Python, but that'd be preferred.

3 Answers 3

5

Take a look at Gallopsled's pwntools. Does all the things you want it to, and has most of it built in already.

https://github.com/Gallopsled/pwntools

For a few examples of it in use, I put up some writeups from Codegate 2013 and the pwnies do their own writeups as well.

Here's a quick example of "I want to dup file descriptor #4 (e.g. a connected TCP socket) to stdin/stdout/stderr, and pop a shell".

#!/usr/bin/env python
from pwn import *
context.arch = 'amd64' # Default architecture is i386

shellcode = shellcraft.dupio(4) + shellcraft.sh()
print shellcode
print '----'
print enhex(asm(shellcode))
print '----'
print hexdump(asm(shellcode))

Prints out

dup_1:
    push 4
    pop rbp

    push 3
loop_2:
    pop rsi
    dec rsi
    js after_3
    push rsi

    /* call dup2('rbp', 'rsi') */
    push SYS_dup2 /* 0x21 */
    pop rax
    mov rdi, rbp
    syscall

    jmp loop_2
after_3:
    /* execve(path='/bin///sh', argv=['sh'], envp=0) */
    /* push '/bin///sh\x00' */
    push 0x68
    mov rax, 0x732f2f2f6e69622f
    push rax
    mov rdi, rsp
    /* push argument array ['sh\x00'] */
    /* push 'sh\x00' */
    push 0x1010101 ^ 0x6873
    xor dword ptr [rsp], 0x1010101
    xor esi, esi /* 0 */
    push rsi /* null terminate */
    push 8
    pop rsi
    add rsi, rsp
    push rsi /* 'sh\x00' */
    mov rsi, rsp
    xor edx, edx /* 0 */
    /* call execve() */
    push SYS_execve /* 0x3b */
    pop rax
    syscall

----
6a045d6a035e48ffce780b566a21584889ef0f05ebef6a6848b82f62696e2f2f2f73504889e768726901018134240101010131f6566a085e4801e6564889e631d26a3b580f05
----
00000000  6a 04 5d 6a  03 5e 48 ff  ce 78 0b 56  6a 21 58 48  │j·]j│·^H·│·x·V│j!XH│
00000010  89 ef 0f 05  eb ef 6a 68  48 b8 2f 62  69 6e 2f 2f  │····│··jh│H·/b│in//│
00000020  2f 73 50 48  89 e7 68 72  69 01 01 81  34 24 01 01  │/sPH│··hr│i···│4$··│
00000030  01 01 31 f6  56 6a 08 5e  48 01 e6 56  48 89 e6 31  │··1·│Vj·^│H··V│H··1│
00000040  d2 6a 3b 58  0f 05                                  │·j;X│··│
00000046
0490a0e30280a0e30900a0e10810a0e13f0090ef018058e2faffff5a0c008fe20020a0e305002de90d10a0e10b0090ef2f62696e2f736800
0000a0e31eff2fe1

They've also got nifty command-line tools for testing shellcode. For example:

$ pwn shellcraft i386.linux.echo "Hello world"
6801010101813424736d6501686f20776f6848656c6c6a04586a015b89e16a0b5acd80

If you pipe it to a file or another program, raw binary is sent.

$ pwn shellcraft i386.linux.echo "Hello world" | xxd
00000000: 6801 0101 0181 3424 736d 6501 686f 2077  h.....4$sme.ho w
00000010: 6f68 4865 6c6c 6a04 586a 015b 89e1 6a0b  ohHellj.Xj.[..j.
00000020: 5acd 80                                  Z..

You can print out the raw annotated assembly:

$ pwn shellcraft i386.linux.echo "Hello world" -f asm
/* push 'Hello world' */
push 0x1010101
xor dword ptr [esp], 0x1656d73
push 0x6f77206f
push 0x6c6c6548
/* call write('1', 'esp', 0xb) */
push SYS_write /* 4 */
pop eax
push (1) /* 1 */
pop ebx
mov ecx, esp
push 0xb
pop edx
int 0x80

Or generate an ELF:

$ pwn shellcraft i386.linux.echo "Hello world" --format elf > hello
$ file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped 

And even automatically execute or debug it:

$ pwn shellcraft ... --run
$ pwn shellcraft ... --debug

You can also assemble your own shellcode on the command-line:

$ pwn asm nop
90
$ pwn asm nop | xxd
00000000: 90                                       .
6

Some Python assembler libraries:

Pyasm - Python x86 Assembler

Pyasm is a full-featured dynamic assembler written entirely in Python. By dynamic, it means that it can be used to generate and execute machine code in python at runtime without requiring the generation of object files and linkage. It essentially allow 'inline' assembly in Python modules on x86 platforms.

pyasm2

An easy and powerful assembler engine in Python. Although it's called pyasm2, this is not per se a successor of Pyasm or pyASM. pyasm2 aims to be as flexible as possible, it will support x86, SSE and SSE2.

d00ks

d00ks is an ARM assembler and simulator.

AsmJit-Python

AsmJit is a complete JIT and remote assembler for C++ language. It can generate native code for x86 and x64 architectures and supports the whole x86/x64 instruction set - from legacy MMX to the newest AVX2. It has a type-safe API that allows C++ compiler to do a semantic checks at compile-time even before the assembled code is generated or run.

1
  • 1
    None of these assemble x86/x64 and ARM. Commented Jul 14, 2014 at 23:07
2

Today, several years after the original post and answers - There's another noteworthy package for generating machine code from assembly- Keystone.

Keystone is written in C++ but has binding for many languages (Python included), and supports multiple architectures (including x86, amd64 and ARM) so it's a perfect fit!

Quoting the website's highlighted features:

  1. Multi-architecture, with support for Arm, Arm64 (AArch64/Armv8), Ethereum Virtual Machine, Hexagon, Mips, PowerPC, Sparc, SystemZ, & X86 (include 16/32/64bit).
  2. Clean/simple/lightweight/intuitive architecture-neutral API.
  3. Implemented in C/C++ languages, with bindings for Java, Masm, Visual Basic, C#, PowerShell, Perl, Python, NodeJS, Ruby, Go, Rust, Haskell & OCaml available.
  4. Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed).
  5. Thread-safe by design.
  6. Open source.

Keystone is part of a more extensive set of tools together with Capstone (Disassembler) and Unicorn (Emulator).

Additionally, if you just want something quick and easy (and don't mind using an online service) - shell-storm's online dis/assembler is also based on Keystone and Capstone

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.