Miasm es un marco de ingeniería inversa gratuito y de código abierto (GPLv2). Miasm tiene como objetivo analizar/modificar/generar programas binarios. Aquí hay una lista no exhaustiva de características:
Consulte el blog oficial para obtener más ejemplos y demostraciones.
Importar arquitectura Miasm x86:
>>> from miasm.arch.x86.arch import mn_x86
>>> from miasm.core.locationdb import LocationDB
Obtener una base de datos de ubicación:
>>> loc_db = LocationDB()
Armar una línea:
>>> l = mn_x86.fromstring( ' XOR ECX, ECX ' , loc_db, 32 )
>>> print (l)
XOR ECX, ECX
>>> mn_x86.asm(l)
['1xc9', '3xc9', 'g1xc9', 'g3xc9']
Modificar un operando:
>>> l.args[ 0 ] = mn_x86.regs. EAX
>>> print (l)
XOR EAX, ECX
>>> a = mn_x86.asm(l)
>>> print (a)
['1xc8', '3xc1', 'g1xc8', 'g3xc1']
Desmontar el resultado:
>>> print (mn_x86.dis(a[ 0 ], 32 ))
XOR EAX, ECX
Usando la abstracción Machine
:
>>> from miasm.analysis.machine import Machine
>>> mn = Machine( ' x86_32 ' ).mn
>>> print (mn.dis( ' x33x30 ' , 32 ))
XOR ESI, DWORD PTR [EAX]
Para MIPS:
>>> mn = Machine( ' mips32b ' ).mn
>>> print (mn.dis( b ' x97xa3x00 ' , " b " ))
LHU V1, 0x20(SP)
Crea una instrucción:
>>> machine = Machine( ' arml ' )
>>> instr = machine.mn.dis( ' x00 x88xe0 ' , ' l ' )
>>> print (instr)
ADD R2, R8, R0
Cree un objeto de representación intermedio:
>>> lifter = machine.lifter_model_call(loc_db)
Crea un ircfg vacío:
>>> ircfg = lifter.new_ircfg()
Agregue instrucciones al grupo:
>>> lifter.add_instr_to_ircfg(instr, ircfg)
Imprimir grupo actual:
>>> for lbl, irblock in ircfg.blocks.items():
... print (irblock)
loc_0:
R2 = R8 + R0
IRDst = loc_4
Trabajar con IR, por ejemplo, obteniendo efectos secundarios:
>>> for lbl, irblock in ircfg.blocks.items():
... for assignblk in irblock:
... rw = assignblk.get_rw()
... for dst, reads in rw.items():
... print ( ' read: ' , [ str (x) for x in reads])
... print ( ' written: ' , dst)
... print ()
...
read: ['R8', 'R0']
written: R2
read: []
written: IRDst
Más información sobre Miasm IR está en el Jupyter Notebook correspondiente.
Dando un código shell:
00000000 8d4904 lea ecx, [ecx+0x4]
00000003 8d5b01 lea ebx, [ebx+0x1]
00000006 80f901 cmp cl, 0x1
00000009 7405 jz 0x10
0000000b 8d5bff lea ebx, [ebx-1]
0000000e eb03 jmp 0x13
00000010 8d5b01 lea ebx, [ebx+0x1]
00000013 89d8 mov eax, ebx
00000015 c3 ret
>>> s = b ' x8d I x04x8d [ x01x80xf9x01 t x05x8d [ xffxebx03x8d [ x01x89xd8xc3 '
Importa el shellcode gracias a la abstracción Container
:
>>> from miasm.analysis.binary import Container
>>> c = Container.from_string(s, loc_db)
>>> c
Desmontando el código shell en la dirección 0
:
>>> from miasm.analysis.machine import Machine
>>> machine = Machine( ' x86_32 ' )
>>> mdis = machine.dis_engine(c.bin_stream, loc_db = loc_db)
>>> asmcfg = mdis.dis_multiblock( 0 )
>>> for block in asmcfg.blocks:
... print (block)
...
loc_0
LEA ECX, DWORD PTR [ECX + 0x4]
LEA EBX, DWORD PTR [EBX + 0x1]
CMP CL, 0x1
JZ loc_10
-> c_next:loc_b c_to:loc_10
loc_10
LEA EBX, DWORD PTR [EBX + 0x1]
-> c_next:loc_13
loc_b
LEA EBX, DWORD PTR [EBX + 0xFFFFFFFF]
JMP loc_13
-> c_to:loc_13
loc_13
MOV EAX, EBX
RET
Inicializando el motor JIT con una pila:
>>> jitter = machine.jitter(loc_db, jit_type = ' python ' )
>>> jitter.init_stack()
Agregue el código shell en una ubicación de memoria arbitraria:
>>> run_addr = 0x 40000000
>>> from miasm.jitter.csts import PAGE_READ , PAGE_WRITE
>>> jitter.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE , s)
Cree un centinela para detectar el retorno del código shell:
def code_sentinelle ( jitter ):
jitter . running = False
jitter . pc = 0
return True
> >> jitter . add_breakpoint ( 0x1337beef , code_sentinelle )
> >> jitter . push_uint32_t ( 0x1337beef )
Registros activos:
>>> jitter.set_trace_log()
Ejecutar en una dirección arbitraria:
>>> jitter.init_run(run_addr)
>>> jitter.continue_run()
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000000 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
RIP 0000000040000000
40000000 LEA ECX, DWORD PTR [ECX+0x4]
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
....
4000000e JMP loc_0000000040000013:0x40000013
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
RIP 0000000040000013
40000013 MOV EAX, EBX
RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000
RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000
zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000
RIP 0000000040000013
40000015 RET
>>>
Interactuando con el jitter:
>>> jitter.vm
ad 1230000 size 10000 RW_ hpad 0x2854b40
ad 40000000 size 16 RW_ hpad 0x25e0ed0
>>> hex (jitter.cpu. EAX )
'0x0L'
>>> jitter.cpu. ESI = 12
Inicializando el grupo de IR:
>>> lifter = machine.lifter_model_call(loc_db)
>>> ircfg = lifter.new_ircfg_from_asmcfg(asmcfg)
Inicializando el motor con valores simbólicos predeterminados:
>>> from miasm.ir.symbexec import SymbolicExecutionEngine
>>> sb = SymbolicExecutionEngine(lifter)
Lanzando la ejecución:
>>> symbolic_pc = sb.run_at(ircfg, 0 )
>>> print (symbolic_pc)
((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
Lo mismo, con los registros de pasos (solo se muestran los cambios):
>>> sb = SymbolicExecutionEngine(lifter, machine.mn.regs.regs_init)
>>> symbolic_pc = sb.run_at(ircfg, 0 , step = True )
Instr LEA ECX, DWORD PTR [ECX + 0x4]
Assignblk:
ECX = ECX + 0x4
________________________________________________________________________________
ECX = ECX + 0x4
________________________________________________________________________________
Instr LEA EBX, DWORD PTR [EBX + 0x1]
Assignblk:
EBX = EBX + 0x1
________________________________________________________________________________
EBX = EBX + 0x1
ECX = ECX + 0x4
________________________________________________________________________________
Instr CMP CL, 0x1
Assignblk:
zf = (ECX[0:8] + -0x1)?(0x0,0x1)
nf = (ECX[0:8] + -0x1)[7:8]
pf = parity((ECX[0:8] + -0x1) & 0xFF)
of = ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1))[7:8]
cf = (((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1)) ^ ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1)))[7:8]
af = ((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1))[4:5]
________________________________________________________________________________
af = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5]
pf = parity((ECX + 0x4)[0:8] + 0xFF)
zf = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1)
ECX = ECX + 0x4
of = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8]
nf = ((ECX + 0x4)[0:8] + 0xFF)[7:8]
cf = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8]
EBX = EBX + 0x1
________________________________________________________________________________
Instr JZ loc_key_1
Assignblk:
IRDst = zf?(loc_key_1,loc_key_2)
EIP = zf?(loc_key_1,loc_key_2)
________________________________________________________________________________
af = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5]
EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
pf = parity((ECX + 0x4)[0:8] + 0xFF)
IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
zf = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1)
ECX = ECX + 0x4
of = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8]
nf = ((ECX + 0x4)[0:8] + 0xFF)[7:8]
cf = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8]
EBX = EBX + 0x1
________________________________________________________________________________
>>>
Reintente la ejecución con un ECX concreto. Aquí, la ejecución simbólica/concólica llega al final del shellcode:
>>> from miasm.expression.expression import ExprInt
>>> sb.symbols[machine.mn.regs. ECX ] = ExprInt( - 3 , 32 )
>>> symbolic_pc = sb.run_at(ircfg, 0 , step = True )
Instr LEA ECX, DWORD PTR [ECX + 0x4]
Assignblk:
ECX = ECX + 0x4
________________________________________________________________________________
af = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5]
EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
pf = parity((ECX + 0x4)[0:8] + 0xFF)
IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
zf = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1)
ECX = 0x1
of = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8]
nf = ((ECX + 0x4)[0:8] + 0xFF)[7:8]
cf = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8]
EBX = EBX + 0x1
________________________________________________________________________________
Instr LEA EBX, DWORD PTR [EBX + 0x1]
Assignblk:
EBX = EBX + 0x1
________________________________________________________________________________
af = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5]
EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
pf = parity((ECX + 0x4)[0:8] + 0xFF)
IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
zf = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1)
ECX = 0x1
of = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8]
nf = ((ECX + 0x4)[0:8] + 0xFF)[7:8]
cf = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8]
EBX = EBX + 0x2
________________________________________________________________________________
Instr CMP CL, 0x1
Assignblk:
zf = (ECX[0:8] + -0x1)?(0x0,0x1)
nf = (ECX[0:8] + -0x1)[7:8]
pf = parity((ECX[0:8] + -0x1) & 0xFF)
of = ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1))[7:8]
cf = (((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1)) ^ ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1)))[7:8]
af = ((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1))[4:5]
________________________________________________________________________________
af = 0x0
EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
pf = 0x1
IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
zf = 0x1
ECX = 0x1
of = 0x0
nf = 0x0
cf = 0x0
EBX = EBX + 0x2
________________________________________________________________________________
Instr JZ loc_key_1
Assignblk:
IRDst = zf?(loc_key_1,loc_key_2)
EIP = zf?(loc_key_1,loc_key_2)
________________________________________________________________________________
af = 0x0
EIP = 0x10
pf = 0x1
IRDst = 0x10
zf = 0x1
ECX = 0x1
of = 0x0
nf = 0x0
cf = 0x0
EBX = EBX + 0x2
________________________________________________________________________________
Instr LEA EBX, DWORD PTR [EBX + 0x1]
Assignblk:
EBX = EBX + 0x1
________________________________________________________________________________
af = 0x0
EIP = 0x10
pf = 0x1
IRDst = 0x10
zf = 0x1
ECX = 0x1
of = 0x0
nf = 0x0
cf = 0x0
EBX = EBX + 0x3
________________________________________________________________________________
Instr LEA EBX, DWORD PTR [EBX + 0x1]
Assignblk:
IRDst = loc_key_3
________________________________________________________________________________
af = 0x0
EIP = 0x10
pf = 0x1
IRDst = 0x13
zf = 0x1
ECX = 0x1
of = 0x0
nf = 0x0
cf = 0x0
EBX = EBX + 0x3
________________________________________________________________________________
Instr MOV EAX, EBX
Assignblk:
EAX = EBX
________________________________________________________________________________
af = 0x0
EIP = 0x10
pf = 0x1
IRDst = 0x13
zf = 0x1
ECX = 0x1
of = 0x0
nf = 0x0
cf = 0x0
EBX = EBX + 0x3
EAX = EBX + 0x3
________________________________________________________________________________
Instr RET
Assignblk:
IRDst = @32[ESP[0:32]]
ESP = {ESP[0:32] + 0x4 0 32}
EIP = @32[ESP[0:32]]
________________________________________________________________________________
af = 0x0
EIP = @32[ESP]
pf = 0x1
IRDst = @32[ESP]
zf = 0x1
ECX = 0x1
of = 0x0
nf = 0x0
cf = 0x0
EBX = EBX + 0x3
ESP = ESP + 0x4
EAX = EBX + 0x3
________________________________________________________________________________
>>>
Miasm incorpora su propio desensamblador, lenguaje intermedio y semántica de instrucción. Está escrito en Python.
Para emular código, utiliza LLVM, GCC, Clang o Python para JIT la representación intermedia. Puede emular códigos shell y todo o parte de binarios. Las devoluciones de llamada de Python se pueden ejecutar para interactuar con la ejecución, por ejemplo, para emular efectos de funciones de biblioteca.
Algunos recursos de documentación están disponibles en la carpeta doc.
Hay disponible una documentación generada automáticamente:
Usos del miasma:
Para habilitar el código JIT, uno de los siguientes módulos es obligatorio:
Miasm 'opcional' también puede usar:
Para utilizar el jitter, se recomienda GCC o LLVM
pip install llvmlite
o instala desde llvmlite$ cd miasm_directory
$ python setup.py build
$ sudo python setup.py install
Si algo sale mal durante la compilación de uno de los módulos de jitter, Miasm omitirá el error y desactivará el módulo correspondiente (consulte el resultado de la compilación).
La mayoría de los complementos IDA de Miasm utilizan un subconjunto de funciones de Miasm. Una forma rápida de hacer que funcionen es agregar:
pyparsing.py
a C:...IDApython
o pip install pyparsing
miasm/miasm
en C:...IDApython
Todas las funciones, excepto las relacionadas con JITter, estarán disponibles. Para una instalación más completa, consulte los párrafos anteriores.
Miasm viene con un conjunto de pruebas de regresión. Para ejecutarlos todos:
cd miasm_directory/test
# Run tests using our own test runner
python test_all.py
# Run tests using standard frameworks (slower, require 'parameterized')
python -m unittest test_all.py # sequential, requires 'unittest'
python -m pytest test_all.py # sequential, requires 'pytest'
python -m pytest -n auto test_all.py # parallel, requires 'pytest' and 'pytest-xdist'
Se pueden especificar algunas opciones:
-m
-c
-t long
(excluye las pruebas largas)