Articulo de referencia

Descompilador

Un descompilador es un programa informático que convierte un archivo ejecutable en código fuente de alto nivel . A diferencia de un compilador , que convierte el código de alto ...

Un descompilador es un programa informático que convierte un archivo ejecutable en código fuente de alto nivel . A diferencia de un compilador , que convierte el código de alto nivel en código máquina , un descompilador realiza el proceso inverso. Mientras que los desensambladores traducen los ejecutables a lenguaje ensamblador , los descompiladores van un paso más allá al reconstruir el desensamblaje en lenguajes de nivel superior como C. Debido a la naturaleza unidireccional del proceso de compilación, los descompiladores generalmente no pueden recrear a la perfección el código fuente original. A menudo producen código ofuscado y menos legible.

Introducción

La descompilación es el proceso de transformar código ejecutable en un formato de alto nivel legible por humanos mediante un descompilador. Este proceso se utiliza comúnmente para tareas que implican la ingeniería inversa de la lógica subyacente al código ejecutable, como la recuperación de código fuente perdido o no disponible. Los descompiladores se enfrentan a desafíos inherentes debido a la pérdida de información crítica durante el proceso de compilación, como nombres de variables, comentarios y la estructura del código.

Ciertos factores pueden influir en el éxito de la descompilación. Los ejecutables que contienen metadatos detallados , como los que utilizan Java y .NET , son más fáciles de descompilar, ya que suelen conservar estructuras de clases , firmas de métodos e información de depuración . Los archivos ejecutables que carecen de este contexto son mucho más difíciles de convertir en código fuente comprensible.

Algunos desarrolladores de software pueden ofuscar , empaquetar o cifrar partes de sus programas ejecutables, lo que dificulta considerablemente la interpretación del código descompilado. Estas técnicas suelen emplearse para disuadir la ingeniería inversa, haciendo que el proceso sea más complejo y requiera más tiempo.

Diseño

Los descompiladores pueden considerarse compuestos por una serie de fases, cada una de las cuales contribuye con aspectos específicos del proceso general de descompilación.

Cargador

La primera fase de descompilación carga y analiza el código máquina de entrada o el formato de archivo binario del programa en lenguaje intermedio . Debe ser capaz de descubrir información básica sobre el programa de entrada, como la arquitectura (Pentium, PowerPC, etc.) y el punto de entrada. En muchos casos, debe ser capaz de encontrar el equivalente de la función de un programa en C , que es el inicio del código escrito por el usuario . Esto excluye el código de inicialización en tiempo de ejecución , que no debe descompilarse si es posible. Si están disponibles, también se cargan las tablas de símbolos y los datos de depuración. El front-end puede identificar las bibliotecas utilizadas, incluso si están enlazadas con el código, lo que proporcionará interfaces de biblioteca. Si puede determinar el compilador o compiladores utilizados, puede proporcionar información útil para identificar patrones de código. [ 1 ]main

Desmontaje

La siguiente fase lógica es el desensamblaje de las instrucciones del código máquina en una representación intermedia independiente de la máquina (IR). Por ejemplo, la instrucción de la máquina Pentium.

mov eax , [ ebx + 0x04 ]

podría traducirse al IR

eax : = m [ ebx + 4 ] ;

Modismos

Las secuencias de código máquina idiomáticas son secuencias de código cuya semántica combinada no resulta inmediatamente evidente a partir de la semántica individual de las instrucciones. Ya sea como parte de la fase de desensamblaje o como parte de análisis posteriores, estas secuencias idiomáticas deben traducirse a una representación intermedia (IR) equivalente conocida. Por ejemplo, el código ensamblador x86 :

cdq eax ; edx se establece en la extensión de signo≠edi,edi +(tex)push xor eax , edx sub eax , edx

podría traducirse a

eax := abs(eax);

Algunas secuencias idiomáticas son independientes de la máquina; otras implican solo una instrucción. Por ejemplo, borra el registro (lo pone a cero). Esto se puede implementar con una regla de simplificación independiente de la máquina, como .xoreax,eaxeaxa = 0

En general, conviene retrasar la detección de secuencias idiomáticas, si es posible, a etapas posteriores menos afectadas por el orden de las instrucciones. Por ejemplo, la fase de planificación de instrucciones de un compilador puede insertar otras instrucciones en una secuencia idiomática o modificar el orden de las instrucciones dentro de la secuencia. Un proceso de comparación de patrones en la fase de desensamblaje probablemente no reconocería el patrón modificado. Las fases posteriores agrupan las expresiones de instrucciones en expresiones más complejas y las modifican a una forma canónica (estandarizada), lo que aumenta la probabilidad de que incluso la secuencia idiomática modificada coincida con un patrón de nivel superior más adelante en la descompilación.

Es particularmente importante reconocer las convenciones del compilador para llamadas a subrutinas , manejo de excepciones y sentencias switch . Algunos lenguajes también ofrecen un amplio soporte para cadenas o números enteros largos .

Análisis del programa

Se pueden aplicar varios análisis de programas al IR. En particular, la propagación de expresiones combina la semántica de varias instrucciones en expresiones más complejas. Por ejemplo,

mov eax ,[ ebx + 0x04 ] add eax ,[ ebx + 0x08 ] sub [ ebx + 0x0C ], eax

podría resultar en la siguiente IR después de la propagación de la expresión:

m[ebx+12] := m[ebx+12] - (m[ebx+4] + m[ebx+8]);

La expresión resultante se asemeja más a un lenguaje de alto nivel y, además, ha eliminado el uso del registro de máquina eax. Análisis posteriores podrían eliminar dicho ebxregistro.

Análisis del flujo de datos

Los lugares donde se definen y utilizan los contenidos de los registros deben rastrearse mediante análisis de flujo de datos . El mismo análisis puede aplicarse a las ubicaciones utilizadas para variables temporales y datos locales. A continuación, se puede generar un nombre diferente para cada conjunto conectado de definiciones y usos de valores. Es posible que la misma ubicación de variable local se haya utilizado para más de una variable en diferentes partes del programa original. Peor aún, el análisis de flujo de datos puede identificar una ruta por la cual un valor puede fluir entre dos usos de este tipo, aunque esto nunca ocurra ni tenga relevancia en la realidad. En casos extremos, esto puede llevar a la necesidad de definir una ubicación como una unión de tipos. El descompilador puede permitir al usuario romper explícitamente estas dependencias no naturales, lo que dará como resultado un código más claro. Esto, por supuesto, significa que una variable se utiliza potencialmente sin estar inicializada, lo que indica un problema en el programa original.

Análisis de tipos

Un buen descompilador de código máquina realizará un análisis de tipos. En este análisis, la forma en que se utilizan los registros o las ubicaciones de memoria impone restricciones sobre el tipo posible de la ubicación. Por ejemplo, una andinstrucción implica que el operando es un entero; los programas no utilizan dicha operación con valores de punto flotante (excepto en código de biblioteca especial) ni con punteros . Una addinstrucción da como resultado tres restricciones, ya que los operandos pueden ser enteros, o uno entero y un puntero (con resultados enteros y punteros respectivamente; la tercera restricción proviene del orden de los dos operandos cuando los tipos son diferentes). [ 2 ]

Se pueden reconocer diversas expresiones de alto nivel que activan el reconocimiento de estructuras o matrices. Sin embargo, resulta difícil distinguir muchas de las posibilidades debido a la libertad que ofrece el código máquina, e incluso algunos lenguajes de alto nivel como C, con las conversiones de tipo y la aritmética de punteros.

El ejemplo de la sección anterior podría dar como resultado el siguiente código de alto nivel:

struct T1 { int v0004 ; int v0008 ; int v000C ; }; struct T1 * ebx ; ebx -> v000C -= ebx -> v0004 + ebx -> v0008 ;

Estructuración

La penúltima fase de descompilación implica la estructuración del IR en construcciones de nivel superior, como whilebucles y if/then/elsesentencias condicionales. Por ejemplo, el código máquina.

xor eax , eax l0002: o ebx , ebx jge l0003 add eax , [ ebx ] mov ebx , [ ebx + 0x4 ] jmp l0002 l0003: mov [ 0x10040000 ], eax

podría traducirse como:

eax = 0 ; mientras ( ebx < 0 ) { eax += ebx- > v0000 ; ebx = ebx- > v0004 ; } v10040000 = eax ;

El código no estructurado es más difícil de convertir en código estructurado que el código ya estructurado. Las soluciones incluyen replicar parte del código o agregar variables booleanas. [ 3 ]

Generación de código

La fase final consiste en la generación del código de alto nivel en la parte posterior del descompilador. Del mismo modo que un compilador puede tener varias partes posteriores para generar código máquina para diferentes arquitecturas, un descompilador puede tener varias partes posteriores para generar código de alto nivel en diferentes lenguajes de alto nivel.

Justo antes de la generación del código, puede ser conveniente permitir la edición interactiva del IR, quizás mediante una interfaz gráfica de usuario . Esto permitiría al usuario introducir comentarios y nombres de variables y funciones no genéricos. Sin embargo, estos se pueden introducir casi con la misma facilidad en una edición posterior a la descompilación. El usuario podría querer modificar aspectos estructurales, como convertir un whilebucle en forotro. Estos cambios son más difíciles de realizar con un editor de texto simple, aunque las herramientas de refactorización de código fuente pueden facilitar este proceso. El usuario podría necesitar introducir información que no se identificó durante la fase de análisis de tipos, por ejemplo, modificar una expresión de memoria a una expresión de matriz o estructura. Finalmente, podría ser necesario corregir un IR incorrecto o realizar cambios para que el código de salida sea más legible.

Otras técnicas

Se han desarrollado descompiladores que utilizan redes neuronales . Dicho descompilador puede entrenarse mediante aprendizaje automático para mejorar su precisión con el tiempo. [ 4 ]

Legalidad

La mayoría de los programas informáticos están protegidos por derechos de autor . Si bien el alcance exacto de lo que abarcan los derechos de autor varía según la región, la ley generalmente otorga al autor (el programador o el empleador) un conjunto de derechos exclusivos sobre el programa. [ 5 ] Estos derechos incluyen el derecho a realizar copias , incluso en la memoria RAM del ordenador (a menos que la creación de dicha copia sea esencial para el uso del programa). [ 6 ] Dado que el proceso de descompilación implica realizar múltiples copias, generalmente está prohibido sin la autorización del titular de los derechos de autor. Sin embargo, debido a que la descompilación suele ser un paso necesario para lograr la interoperabilidad del software , las leyes de derechos de autor tanto en Estados Unidos como en Europa permiten la descompilación hasta cierto punto.

En Estados Unidos, la defensa del uso legítimo de derechos de autor se ha invocado con éxito en casos de descompilación. Por ejemplo, en Sega v. Accolade , el tribunal dictaminó que Accolade podía realizar legalmente la descompilación para eludir el mecanismo de bloqueo de software utilizado por las consolas de videojuegos de Sega. [ 7 ] Además, la Ley de Derechos de Autor del Milenio Digital (Ley Pública 105-304 [ 8 ] ) contempla exenciones adecuadas tanto para las pruebas y evaluaciones de seguridad en el §1201(i) como para la ingeniería inversa en el §1201(f). [ 9 ]

En Europa, la Directiva de Software de 1991 prevé explícitamente el derecho a descompilar para lograr la interoperabilidad. Fruto de un acalorado debate entre, por un lado, los defensores del software y, por otro, los académicos y los desarrolladores de software independientes, el artículo 6 permite la descompilación solo si se cumplen una serie de condiciones:

  • En primer lugar, la persona o entidad debe tener una licencia para usar el programa que se va a descompilar.
  • En segundo lugar, la descompilación debe ser necesaria para lograr la interoperabilidad con el programa objetivo u otros programas. Por lo tanto, la información de interoperabilidad no debe estar fácilmente disponible, por ejemplo, a través de manuales o documentación de API . Esta es una limitación importante. El descompilador debe demostrar la necesidad. El propósito de esta importante limitación es principalmente incentivar a los desarrolladores a documentar y divulgar la información de interoperabilidad de sus productos. [ 10 ]
  • En tercer lugar, el proceso de descompilación debe, de ser posible, limitarse a las partes del programa objetivo relevantes para la interoperabilidad. Dado que uno de los objetivos de la descompilación es comprender la estructura del programa, esta tercera limitación puede ser difícil de cumplir. Una vez más, la carga de la prueba recae sobre el descompilador.

Además, el artículo 6 estipula que la información obtenida mediante la descompilación no podrá utilizarse para otros fines ni podrá divulgarse a terceros.

En general, el derecho de descompilación previsto en el artículo 6 codifica lo que se considera práctica común en la industria del software. Se conocen pocos litigios europeos derivados de este derecho. Esto podría interpretarse de tres maneras:

  1. El derecho de descompilación no se utiliza con frecuencia y, por lo tanto, puede que haya sido innecesario.
  2. El derecho de descompilación funciona bien y proporciona suficiente seguridad jurídica para no dar lugar a disputas legales o
  3. La descompilación ilegal pasa en gran medida desapercibida.

En un informe de 2000 sobre la aplicación de la Directiva de Software por los Estados miembros europeos, la Comisión Europea pareció apoyar la segunda interpretación. [ 11 ]

Véase también

descompiladores de Java

Otros descompiladores

Referencias

  1. Cifuentes, Cristina; Gough, K. John (julio de 1995). "Descompilación de programas binarios". Software: Practice and Experience . 25 (7): 811– 829. CiteSeerX 10.1.1.14.8073 . doi : 10.1002/spe.4380250706 . S2CID 8229401 .  
  2. Mycroft, Alan (1999). "Descompilación basada en tipos". En Swierstra, S. Doaitse (ed.). Lenguajes y sistemas de programación: 8.º Simposio Europeo sobre Lenguajes y Sistemas de Programación . Springer-Verlag . pp. 208–223 . ISBN  3-540-65699-5.
  3. Cifuentes, Cristina (1994). "Capítulo 6". Técnicas de compilación inversa (PDF) (tesis doctoral). Universidad Tecnológica de Queensland . Archivado (PDF) del original el 22 de noviembre de 2016. Recuperado el 21 de diciembre de 2019 .)
  4. Tian, ​​Yuandong; Fu, Cheng (27 de enero de 2021). "Presentación de N-Bref: un marco de descompilación basado en redes neuronales" . Recuperado el 30 de diciembre de 2022 .
  5. Rowland, Diane (2005). Derecho de las tecnologías de la información (3.ª ed.). Cavendish. ISBN  1-85941-756-6.
  6. "Oficina de Derechos de Autor de EE. UU. - Ley de Derechos de Autor: Capítulo 1" . Archivado del original el 25/12/2017 . Consultado el 10/04/2014 .
  7. "La legalidad de la descompilación" . Program-transformation.org. 3 de diciembre de 2004. Archivado del original el 22 de septiembre de 2010. Consultado el 15 de septiembre de 2010 .
  8. "Ley de Derechos de Autor del Milenio Digital" (PDF) . Congreso de los Estados Unidos . 28 de octubre de 1998. Archivado (PDF) del original el 10 de diciembre de 2013. Consultado el 15 de noviembre de 2013 .
  9. "Registro Federal :: Solicitar Acceso" . 26 de octubre de 2018. Archivado del original el 25 de enero de 2022. Consultado el 31 de enero de 2021 . 
  10. Czarnota, Bridget; Hart, Robert J. (1991). Protección jurídica de los programas informáticos en Europa: una guía de la directiva CE . Londres: Butterworths Tolley . ISBN 0-40600542-7.
  11. «Informe de la Comisión al Consejo, al Parlamento Europeo y al Comité Económico y Social sobre la aplicación y los efectos de la Directiva 91/250/CEE relativa a la protección jurídica de los programas informáticos» . Archivado del original el 4 de diciembre de 2020. Consultado el 26 de diciembre de 2020 .