iasm
is an interactive assembler for x86, arm, mips,
and sparc.
$ iasm -a arm -m arm # byexample: +stop-on-silence=1 +term=ansi +stop-signal=eof
Mapping memory region [0x1000000-0x11fffff] (sz 0x200000)
------ - ------ - ------ - ------ -----
r0 0 r1 0 r2 0 r3 0
r4 0 r5 0 r6 0 r7 0
r8 0 r9/sb 0 r10 0 r11/fp 0
r12/ip 0 r13/sp 0 r14/lr 0 r15/pc 100:0
------ - ------ - ------ - ------ -----
---- -------------------------------------
cpsr 010000 0000 01110 10011 00000000 0000
NZCVQJ GE EAIFT M IT ....
---- -------------------------------------
100:0>
Then, type the instructions. Under the hood what your type is parsed by keystone and emulated in a virtual CPU by unicorn.
Just install iasm
with pip
:
$ pip install iasm # byexample: +skip
It has syntax highlighting as you write (using pygments), autocompletion and command line history (using python-prompt-toolkit)
An enhanced replacement for Python's input
for sure.
By default what you type is assembly code. If you prefix your input with
;!
you can enter Python code and access to the registers and memory
easier.
iasm
allows you to map, initialize and read memory pages
from the Python shell:
:> ;! M[0x1000:0x2000] = 0 # map and initialize
Mapping memory region [0x1000-0x1fff] (sz 0x1000)
:> ;! M[0x1050:0x1055] = 0x41 # write like 'memset'
:> ;! M[0x1055:0x105a] = b'B' * 5 # write like 'memcpy'
:> ;! M[0x1050:0x105a] # read
[AAAAABBBBB]
:> ;! M # list mapped pages
[0x1000-0x1fff] (sz 0x1000)
[0x1000000-0x11fffff] (sz 0x200000)
:> ;! M[0x1000:0x2000].load("test/ds/foo") # load from a file
Loaded 60 bytes
:> ;! M[0x1000:0x2000].save("test/ds/dump") # save a dump in a file
Saved 4096 bytes
:> ;! M[0x1000:0x1000+45].hex() # display in hexdump
00001000 31 36 30 34 31 35 31 33 30 38 39 34 37 09 67 65 |1604151308947.ge|
00001010 63 6b 6f 64 72 69 76 65 72 09 49 4e 46 4f 09 4c |ckodriver.INFO.L|
00001020 69 73 74 65 6e 69 6e 67 20 6f 6e 20 31 |istening on 1 |
:> ;! M[0x1000:0x1000+8].disass() # disassembly
00001000 ldrtlo r3, [r0], #-0x631
00001004 teqlo r1, #0xc400000
:> ;! del M[0x1000:0x2000] # unmap
To allocate the stack and setup the (Arm) registers just run:
:> ;! M[0x1000:0x2000] = 0
Mapping memory region [0x1000-0x1fff] (sz 0x1000)
:> ;! fp = sp = 0x2000
Now, play with it and practice your (Arm) assembly:
:> mov r0, #4
:> mov r1, #8
:> push {r0, r1}
And check the stack (was r0
pushed before r1
or not? Check it!)
:> ;! M[sp:] # from sp to the end of the mapped page
[\x04\x00\x00\x00\x08\x00\x00\x00]
Write in a file all the initialization like the stack allocation and
load it from the command line with -i
.
$ echo ';! r0 = r1 = r2 = 8' > init
$ iasm -a arm -m arm -i init # byexample: +stop-on-silence=1 +term=ansi +stop-signal=eof
Mapping memory region [0x1000000-0x11fffff] (sz 0x200000)
------ - ------ - ------ - ------ -----
r0 8 r1 8 r2 8 r3 0
<...>
Following the tradition of Python, iasm
includes documentation for the
assembly instructions.
After the mnemonic type ?
and enter to show it:
:> mul ? ; byexample: +skip
# C6.2.197 - MUL
Multiply : Rd = Rn * Rm This instruction is an alias of the MADD
instruction. This means that:
- The encodings in this description are named to match the
encodings of MADD.
- The description of MADD gives the operational pseudocode for
this instruction.
<...>
Basically what I did was to convert to text the manual of reference of the ISA (typically it is a PDF file) and then parse the text.
I only focused in the documentation of the instructions, the rest is up to the user to search the complete story in the official documentation.
Currently only Armv8 is supported. Pull requests are welcome!!
iasm
allows to select which registers to show using globs,
Unix like pattern expressions defined by
fnmatch.
$ iasm -a arm -m arm -r 'r[0-9]' # byexample: +stop-on-silence=1 +term=ansi +stop-signal=eof
Mapping memory region [0x1000000-0x11fffff] (sz 0x200000)
-- - ----- - -- - -- -
r0 0 r1 0 r2 0 r3 0
r4 0 r5 0 r6 0 r7 0
r8 0 r9/sb 0
-- - ----- - -- - -- -
<...>
So the expression r[0-9]
selects all the Arm registers from r0
to
r15
.
You can change the set of registers to display from iasm
with the
show()
function:
:> ;! show('r[0-3]')
-- - -- - -- - -- -
r0 4 r1 8 r2 0 r3 0
-- - -- - -- - -- -
If you want to change the register set permanently add stick=True
:
:> ;! show('r[0-3]', stick=True)
-- - -- - -- - -- -
r0 4 r1 8 r2 0 r3 0
-- - -- - -- - -- -
:> mov r2, r1
-- - -- - -- - -- -
r0 4 r1 8 r2 8 r3 0
-- - -- - -- - -- -
Call show(stick=True)
to restore the defaults:
:> ;! show(stick=True)
32 bit numbers are too large to display (and 64 bit address are worse!).
Instead, iasm
shows them as compressed hexadecimal numbers.
They are like hexadecimals but the number is split into 4-digits groups
divided by a :
.
The leading zeros of each group are omitted and if the group is full of
zeros only a single 0
is put and if the group is on the left (more
significant digits), the whole group is omitted.
Here are some examples:
0x00000000 0
0x000000ab ab
0x00ab00cd ab:cd
0x00ab0000 ab:0
You can write posts or documents and write examples of iasm
just like
the README that you are reading right now.
Then you can run byexample to take these examples and turn them into regression tests.
$ byexample -l iasm README.md # byexample: +skip
File README.md, 17/17 test ran in 1.06 seconds
[PASS] Pass: 16 Fail: 0 Skip: 1
See byexample's support of iasm for the details.
$ pip install iasm # byexample: +skip
$ iasm -V # byexample: +norm-ws
iasm 0.1.3 (Python <...>, Keystone <...>, Unicorn <...>) - GNU GPLv3
Interactive Assembler
Copyright (C) Di Paola Martin - https://github.com/bad-address/iasm
<...>