diStorm – Rápido y potente desensamblador



Introducción

diStorm es un desensamblador de código abierto desarrollado originalmente por Gil Dabah en el año 2003. Está escrito en C y soporta múltiples conjuntos de instrucciones como arquitecturas (x86 y x64) y plataformas (más características en este enlace). El paquete de Python ha sido diseñado por Mario Vilas. Ambos proyectos se distribuyen bajo los términos de la licencia BSD.

Descarga e instalación

Afortunadamente diStorm (específicamente la versión 3, en la cual se basa este artículo) está disponible en PyPI bajo el nombre distorm3.

pip install distorm3

O bien añadiendo sudo como prefijo en caso de requerir permisos adicionales.

Para usuarios de Microsft Windows provee un sencillo instalador.

Aplicación

La función principal del módulo es Decode(offset, code, mode), la cual requiere de una porción de código binario para descomponer junto con un modo determinado (16, 32, o 64 bits). El primer parámetro simplemente define una dirección virtual dentro del código, por lo que diferentes valores no alterarán más que la numeración del código. El valor de retornado es una lista que incluye tantas tuplas como instrucciones en lenguaje ensamblador.

Ejemplos

Como ilustración de la explicación anterior cito los dos ejemplos brindados en la documentación oficial.

Ejemplo 1

from distorm3 import Decode, Decode16Bits, Decode32Bits, Decode64Bits

l = Decode(0x100,  # Dirección virtual
           open("file.com", "rb").read(),  # Bloque de código binario
           Decode16Bits  # Modo (Decode32Bits, Decode64Bits)
)
for i in l:
    print "0x%08x (%02x) %-20s %s" % (i[0],  i[1],  i[3],  i[2])

Este prototipo de código resultaría en una salida similar a la siguiente.

0x00401000 (01) 53 PUSH EBX
0x00401001 (03) 83EC38 SUB ESP, 0x38
0x00401004 (05) A144304000 MOV EAX, [0x403044]
...

Mucho más extensa y sin tener en cuenta que esta salida ha sido tomada de un código de 32 bits.

Cabe aclarar que no es posible especificar un archivo ejecutable de Windows directamente. Esto resultaría en una descomposición errónea ya que el bloque de código incluye datos adicionales (véase Portable Executable). No así archivos COM, en donde el contenido del fichero es cargado directamente en memoria sin modificaciones.

Ejemplo 2

>>> Decode(0x400000, 'b800000000'.decode('hex'), Decode32Bits)
[(4194304L, 5L, 'MOV EAX, 0x0', 'b800000000')]

Ejemplo 3

Un simple programa escrito en C y su respectiva representación en lenguaje ensamblador en Microsoft Windows.

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int main()
{
    printf("56 + 108 = %d\n", add(56, 108));
    printf("add() at 0x%08x\n", (unsigned int)&add);

    getchar();

    return 0;
}

El código imprime en pantalla el resultado de una simple operación y la dirección de memoria de la función.

56 + 108 = 164
sum() at 0x00401334

Una vez compilado, se obtiene el código binario utilizando un editor hexadecimal, copiando únicamente el bloque ejecutable.

Editor hexadecimal

Se utiliza la siguiente función para convertir hexadecimal a código binario y, por último, se llama a Decode.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import distorm3 as distorm

def hex2code(h):
    return h.replace(" ", "").decode("hex")

def main():
    content = hex2code("""53 83 EC 38 A1 44 30 40 00 85 C0 ...""")
    instructions = distorm.Decode(0x00401000, content, distorm.Decode32Bits)
    
    f = open("output.txt", "ab")
    
    for i in instructions:
        f.write("0x%08x (%02x) %-20s %s" %
                (i[0],  i[1],  i[3].upper(), i[2]))
        f.write("\n")
    
    f.close()

if __name__ == "__main__":
    main()

Dentro de las 930 líneas de resultado se busca la dirección 0x00401334, en donde el programa indica que se encuentra la función add.

0x00401334 (04) 8B442408 MOV EAX, [ESP+0x8]
0x00401338 (04) 03442404 ADD EAX, [ESP+0x4]
0x0040133c (01) C3 RET

Puedes ver el archivo completo en este enlace.

Conclusión

diStorm es una herramienta completa y eficiente, que en particular me ha permitido automatizar variedad de tareas que solía realizar manualmente con editores de memoria. La aplicación y uso que puede darse a esta librería es muy amplia; garantizo que todo programador de Python interesado en ingeniería inversa y lenguaje ensamblador estará muy a gusto con el paquete.



Deja un comentario