Un desensamblador es un programa informático que traduce el lenguaje de máquina al lenguaje ensamblador (la operación inversa a la de un ensamblador ). El desensamblador, la salida de un desensamblador, a menudo se formatea para que sea legible para humanos en lugar de ser adecuado para la entrada a un ensamblador, lo que lo convierte principalmente en una herramienta de ingeniería inversa . Los usos comunes de los desensambladores incluyen el análisis de la salida de compiladores de lenguajes de programación de alto nivel y sus optimizaciones, la recuperación del código fuente de un programa cuya fuente original se perdió, el análisis de malware , la modificación de software (como el hackeo de ROM ) y el crackeo de software .
Un desensamblador se diferencia de un descompilador , que apunta a un lenguaje de alto nivel en lugar de un lenguaje ensamblador.
El código fuente del lenguaje ensamblador generalmente permite el uso de constantes y comentarios del programador . Estos son generalmente eliminados del código de máquina ensamblado por el ensamblador. Si es así, un desensamblador que opera en el código de máquina produciría un desensamblado que carece de estas constantes y comentarios; la salida desensamblada se vuelve más difícil de interpretar para un humano que el código fuente anotado original. Algunos desensambladores proporcionan una función de comentarios de código incorporada donde la salida generada se enriquece con comentarios sobre las funciones de API llamadas o los parámetros de las funciones llamadas. Algunos desensambladores hacen uso de la información de depuración simbólica presente en archivos de objetos como ELF . Por ejemplo, IDA permite al usuario humano inventar símbolos mnemotécnicos para valores o regiones de código en una sesión interactiva: la percepción humana aplicada al proceso de desensamblado a menudo es paralela a la creatividad humana en el proceso de escritura de código.
Es posible escribir un desensamblador que produzca código que, al ensamblarse, produzca exactamente el binario original; sin embargo, a menudo hay diferencias. Esto plantea exigencias a la expresividad del ensamblador. Por ejemplo, un ensamblador x86 toma una elección arbitraria entre dos códigos binarios para algo tan simple como . Si el código original utiliza la otra opción, el código original simplemente no se puede reproducir en ningún momento dado. Sin embargo, incluso cuando se produce un desensamblado completamente correcto, siguen existiendo problemas si el programa requiere modificaciones. Por ejemplo, la misma instrucción de salto en lenguaje de máquina puede ser generada por código ensamblador para saltar a una ubicación específica (por ejemplo, para ejecutar código específico), o para saltar una cantidad específica de bytes (por ejemplo, para saltar una rama no deseada). Un desensamblador no puede saber qué se pretende, y puede utilizar cualquiera de las dos sintaxis para generar un desensamblado que reproduzca el binario original. Sin embargo, si un programador desea agregar instrucciones entre la instrucción de salto y su destino, es necesario comprender el funcionamiento del programa para determinar si el salto debe ser absoluto o relativo, es decir, si su destino debe permanecer en una ubicación fija o moverse para omitir tanto las instrucciones originales como las agregadas.MOV AX,BX
Otro desafío es que no siempre es posible identificar qué partes del binario corresponden al código ejecutable y cuáles corresponden a los datos. Mientras que los formatos ejecutables comunes como ELF y PE dividen el binario en secciones ejecutables y de datos, otros formatos como los binarios planos no lo hacen, por lo que cualquier ubicación dada en el binario puede contener instrucciones ejecutables o datos no ejecutables, lo que dificulta decidir si se debe desensamblar como instrucciones o dejar como datos. Dado que las CPU generalmente permiten saltos dinámicos calculados en tiempo de ejecución, no siempre es posible identificar todas las ubicaciones posibles en el binario a las que se puede saltar y, por lo tanto, contener instrucciones.
En arquitecturas de computadoras con instrucciones de ancho variable , como en muchas arquitecturas de computadoras con conjuntos de instrucciones complejos (CISC) , puede ser válido más de un desensamblaje.
Los desensambladores no manejan código que varía durante la ejecución.
El cifrado se puede utilizar en algunos programas informáticos, en particular como parte de la gestión de derechos digitales para impedir la ingeniería inversa y el descifrado . Esto plantea un desafío adicional para el desensamblaje, ya que el código debe descifrarse antes de desensamblarlo.
Un desensamblador puede ser autónomo o interactivo. Un desensamblador autónomo, cuando se ejecuta, genera un archivo de lenguaje ensamblador que puede examinarse; uno interactivo muestra el efecto de cualquier cambio que realice el usuario inmediatamente. Por ejemplo, el desensamblador puede no saber inicialmente que una sección del programa es en realidad código y tratarlo como datos; si el usuario especifica que es código, el código desensamblado resultante se muestra inmediatamente, lo que permite al usuario examinarlo y realizar otras acciones durante la misma ejecución.
Cualquier depurador interactivo incluirá alguna forma de ver el desensamblado del programa que se está depurando. A menudo, la misma herramienta de desensamblado se empaquetará como un desensamblador independiente que se distribuye junto con el depurador. Por ejemplo, objdump , parte de GNU Binutils , está relacionado con el depurador interactivo gdb . [1]
Se puede incorporar un desensamblador dinámico a la salida de un emulador o hipervisor para "rastrear", línea por línea, la ejecución en tiempo real de cualquier instrucción de máquina ejecutada. En este caso, además de las líneas que contienen el código de máquina desensamblado, se pueden mostrar los cambios de registro y/o datos (o cualquier otro cambio de " estado ", como códigos de condición) que cada instrucción individual causa junto a la instrucción desensamblada o debajo de ella. Esto proporciona información de depuración extremadamente poderosa para la resolución definitiva de problemas, aunque el tamaño de la salida resultante a veces puede ser bastante grande, especialmente si está activa durante la ejecución de un programa completo. OLIVER proporcionó estas funciones desde principios de la década de 1970 como parte de su oferta de productos de depuración CICS y ahora se encuentran incorporadas en el producto XPEDITER de Compuware .
Un desensamblador de longitud , también conocido como motor de desensamblador de longitud ( LDE ), es una herramienta que, dada una secuencia de bytes (instrucciones), genera la cantidad de bytes que ocupa la instrucción analizada. Entre los proyectos de código abierto más destacados para la arquitectura x86 se incluyen ldisasm, [8] Tiny x86 Length Disassembler [9] y Extended Length Disassembler Engine para x86-64. [10]