Protección del software (Parte I)

Iniciado por CronuX, Marzo 21, 2010, 07:03:10 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Aprovechando la proximidad del evento Asegúrat IT III, vamos a iniciar una serie de post (en principio semanales) en los que vamos a tratar la seguridad del software.

Este termino puede albergar dos significados diferentes:
La seguridad desde el punto de vista de que una aplicación mal programada ponga nuestro equipo en peligro y pueda causar denegaciones de servicio o incluso llegar a ejecutar código no deseado.
La seguridad de la propia aplicación ante la copia/modificación de la misma por terceros.
Si el problema es el del primer caso, probablemente nos encontremos ante un déficit en la formación del desarrollador en temas de seguridad, una posible falta de concienciación y una falta de testing/auditoría de la aplicación y código fuente, Por supuesto, también puede ocurrir porque, como cualquier proceso en la industria, el desarrollo del software se realiza con excesivas prisas.

Por ejemplo, no es de recibo que una aplicación que se instala como servicio y corre con permisos de SYSTEM se cree con un ACL a cero y permita que cualquier aplicación inyecte código en el proceso y pueda ejecutar el código que desee con los permisos del servicio. Lamentablemente, esto sucede, y no solo en aplicaciones "amateur" ;)

Pero el segundo caso es el que me interesa analizar en esta serie de post. Antes de nada, veamos en que situación nos encontramos.

Hoy día podemos ver como Internet se encuentra plagado de software privado, software de pago, etc. Pero también podemos observar como para todos estos programas (o casi todos), disponemos del parche o número de serie correspondiente, capaz de eliminar limitaciones y proporcionar un software completo.

Por supuesto, a sabiendas de que la gente va a descargar un fichero y lo va a lanzar, no faltan los regalitos que acompañan a dichos parches, pero esto es ya otro tema.

La primera preguntas que nos pueden surgir son, ¿quién se encarga de realizar estos parches? ¿quién sabe sacar un número de serie de un programa? ¿es fácil? ¿requiere mucho tiempo? ¿qué obtiene a cambio?.

La respuesta a estas preguntas es compleja. Antes que nada, cabe destacar que la dificultad y el tiempo requeridos depende tanto de la protección que tenga el programa como de la habilidad de la persona que realiza al ingeniería inversa, o de si ha podido analizar con anterioridad un esquema de protección similar, etc. Lo que está claro es que puede llegar a ser una tarea muy difícil y requerir mucho tiempo.

Hay quien lo hace por hobby (existe más afición por la ingeniería inversa de la que mucha gente imagina), pero está claro que el que analiza aplicaciones para pasar el rato o aprender cosas nuevas no se dedica a sacar un parche tras otro, sino que por lo general tiende a investigar nuevas protecciones, muchos dan el salto al mundo del exploiting, etc. En definitiva, no son nuestro hombres.

No hay que fijarse demasiado para ver que muchos parches llevan la firma de un "grupo". Generalmente en un grupo dedicado a la distribución de warez. Existen miembros a los que se le proporcionan aplicaciones "recién salidas del horno" y, a cambio de X cracks o números de serie por semana, se le da acceso a un servidor ftp privado desde el que descargar warez.

Por supuesto, y como tiene que haber de todo en este mundo, encontraremos a quien lo haga por dinero. Esto no lo he podido constatar, pero, ¿piensas que no es posible? Por ejemplo, una manera de lucrarse consiste en tener una buena página de warez plagada de publicidad. El disponer software actual pirateado es un muy buen reclamo para los visitantes y, si dicho software tan solo se encuentra pirateado en tu página, te estás asegurando muchas visitas.

En el siguiente post comentaremos algunos esquemas de protección que nos podemos encontrar en el software.

Nota: Puede que la palabra parche (entre otras) no sea la más adecuada, porque si nos ponemos quisquillosos puede no abarcar loaders, etc., pero voy a intentar explicar el tema de una manera llana hasta que no haya más remedio que entrar en tecnicismos ;)

Mikel Gastesi

Fuente: S21sec labs

Una vez visto el panorama actual, vamos a echar un ojo a las protecciones que encontramos en las aplicaciones que podemos descargar de cualquier página o comprar en cualquier tienda.

Protección por número de serie
Protección por keyfile (fichero de registro)
Periodo de prueba de X días
Versión limitada (Demo)
Necesidad de otro dispositivos (CD, llave USB, mochila...)

Además de estas protecciones, hoy casi todos los programas poseen una "capa" más de protección ya que presentan el ejecutable empaquetado, pero esto lo comentaremos más adelante.

Protección por número de serie.

En este tipo de programas, solicita que introduzcamos un número de serie y, si acertamos, el programa quedará registrado y completamente funcional. Por supuesto, no podemos obtener el número de serie a ciegas, pero disponemos de múltiples herramientas para analizar los programas en cuestión.

Existe un problema muy grave en la comprobación del número de serie de muchos programas, y se trata de que las secuencia lógica de comprobación puede ser algo así:

si numero_de_serie = ''5421-546-321-4564-123-134"
entonces llamar registrado
si no
entonces llamar Noregistrado
fin si

Suponiendo que no podemos acceder al descompilado (cosa que hoy día es probable gracias al plug-in Hex-Rays del IDA Pro o herramientas como reflector para aplicaciones .NET), siempre cabe la posibilidad de ver el desensamblado, en el que veremos una ejecución secuencial, que sirve perfectamente para ilustrar este problema.

reg1 <-- numero_de_serie
reg2 <-- ''5421-546-321-4564-123-134"
igual reg1,reg2
si no igual salta NOIGUAL
llamar registrado
salta FIN
NOIGUAL:
llamar Noregistrado
FIN:
terminar

En este pseudocódigo, si conseguimos que la línea 4 no salte a NOIGUAL, podremos conseguir que el programa quede siempre registrado. Podemos cambiarla por una instrucción que no haga nada, o reemplazar el "si no igual" por un "si igual", haciendo que valgan todos los números de serie excepto, precisamente, el válido.

Por supuesto, esto se corresponde a un fallo de diseño. Por ejemplo, NUNCA se debe comparar un número de serie en texto plano, ya que puede ser vista por el atacante. Ante esto, la primera idea puede ser cifrar el número de serie introducido por el usuario con una rutina muy compleja, incluso alguna matemáticamente irreversible y en la que se sabe que no es viable atacarlo por fuerza bruta en un tiempo razonable, pero siempre se deberá tener cuidado con la manera de plasmar la idea de la comprobación, puesto que si no lo hacemos es más que probable que la protección tenga el mismo formato (y el mismo fallo de diseño) de la aplicación anterior.

No existe un método que te pueda garantizar la seguridad de tu algoritmo en estos casos, pero se puede intentar fortificar la comprobación de muchas maneras. Por ejemplo, se puede aplicar conocimiento adquirido en otras áreas para diseñar un algoritmo de autenticación más fuerte, como se hizo en el reto 3 que se propuso en este mismo blog. Esta misma idea, utilizada sobre una red muy profunda (y una buena gestión de recursos :p ) puede ser muy interesante, aunque está claro que no es la solución definitiva.

Como ejemplo de un diseño correcto podemos ver la implementación de la protección por contraseña de un fichero .rar. En este caso no se comprueba la contraseña de un fichero y se procede a descomprimirlo, sino que se utiliza la propia contraseña para descomprimir el fichero, por lo que una clave errónea nunca nos devolverá un fichero correcto. En estos casos, el único ataque factible es la fuerza bruta.

Haciendo una analogía con un programa shareware, una manera de dificultar el parcheado del programa es cifrar la parte del programa que desees con la clave, y descifrarlo con el número de serie introducido. Si haces esto, recuerda gestionar bien los errores de un descifrado incorrecto.

Y con esto terminamos por hoy. Seguimos en dos semanas.

Mikel Gastesi

Fuente: S21sec labs

Seguimos esta ligerísima introducción a la protección del software mencionando diferentes tipos de protección que nos podemos encontrar hoy día en las aplicaciones, tal y como comentamos en el post anterior.

Protección por keyfile.

En este caso, el programa necesita un fichero que cumpla ciertos requisitos para poder registrarse. Se puede considerar que es un caso concreto dentro de una protección por número de serie, pero la entrada de datos es un fichero en lugar del teclado, lo cual permite utilizar claves mucho más complejas.

Periodo de prueba de X días

Esto no se puede considerar una técnica de protección por sí sola, ya que siempre va asociada a alguno de las dos anteriores o asociado a un bloqueo de funcionalidades.

Como caso más genérico y fácil de entender podemos ver los casos en los que el programa suele anotar la fecha en que es instalado y, a medida que pasan los días, comprueba cuantos días han pasado, de tal manera que si han transcurrido los X días permitidos, caduca.

Como muchos habréis pensado, tan sólo cambiar la hora del sistema puede hacer que un programa muy muy mal implementado (desde el punto de vista de la seguridad) no caduque.

Versión limitada (Demo)

Esta vez a la aplicación se le han deshabilitado funcionalidades, y necesitamos tener la versión registrada para poder utilizar todo el potencial del programa.
Muchas de estas versiones de demostración se pueden registrar mediante un número de serie, y es muy común encontrar que el código que implementa la funcionalidad deshabilitada se encuentra en la aplicación pero, por ejemplo, las opciones del menú no se encuentran operativos..

Realmente me resulta curioso que si no pretendes dar una funcionalidad, la distribuyas con la aplicación pero desactivada. ¿No sería mucho más lógico no distribuirla y que cuando el usuario se registre pueda obtener una versión nueva totalmente funcional? Si por el motivo que sea te interesa ser pirateado, eso ya es otra cosa...

Necesidad de otro dispositivo (CD-ROM, USB stick...)

Estas protecciones generalmente tienen un objetivo distinto, que consiste en evitar la copia de un software completo, algo que queda fuera del enfoque de este artículo, pero también les echaremos un vistazo superficial.

En este caso nos encontramos que diferentes aplicaciones, como son los juegos, algunos programas de CAD, etc, que utilizan una técnica de protección mixta, parte software y parte hardware, ya que solicitan la introducción de, por ejemplo, un CD-ROM original, de un stick USB o una mochila conectada al puerto paralelo.

Estas protecciones pueden ser más fuertes que las basadas solamente en software, pero pueden no serlo si no están debidamente implementadas. Si se dispone de un dongle original, se puede intentar emularlo, o se puede intentar engañar a la aplicación para que crea que el dongle está conectado.

Si se va a proteger una aplicación mediante un dongle, es aconsejable que éste ejecute cierta lógica compleja y necesaria para la correcta ejecución de la aplicación. De esta manera evitaremos que el atacante tenga que lidiar únicamente con una comprobación de la conexión de un dispositivo.

En el siguiente post veremos algunas ideas muy genéricas que se deberían respetar al proteger una aplicación, siguiendo con la misma idea del programa que requiere contraseña para su registro.


Mikel Gastesi

Fuente: S21sec e-crime

En las partes anteriores hemos dado un repaso a las protecciones más comunes, por lo que ahora vamos a intentar dar algún consejo a la hora de proteger una aplicación.

Al igual que en las partes anteriores, vamos a tratar la parte lógica de la programación, en la que priorizaremos el no dar facilidades a quien pretende atacar nuestra aplicación, y volveremos a tomar como base de este post una aplicación protegida por contraseña.

En la siguiente parte comenzaremos con temás un poco más técnicos, tomando los packers como base, y tratando diferentes barreras que ponen para tratar de proteger la aplicación.

Volviendo al tema que nos conscierne, en primer lugar deberemos recapacitar sobre lo que un atacante necesita para ponerse manos a la obra. A la hora de atacar una protección, no se analiza el código del programa en su totalidad, sino que interesa ubicar la parte de código en que se encuentra la rutina de comprobación, por lo que la primera labor es encontrarla.

Para ello, muchas veces puede ser suficiente fijarte simplemente en los mensajes que se muestran para indicar que es una versión de prueba, ver qué se necesita para registrar el programa (si un número de serie, keyfile), y buscar en el programa en cuestión cadenas de texto sospechosas, llamadas a APIs relacionadas con la apertura de ficheros, lectura de registro...

Por tanto, un consejo muy importante consiste en no dar más información de la necesaria.

Para el profano en la materia, vamos a ver un pequeño ejemplo de una aplicación que muestre un mensaje "Hola Mundo!" en la que queremos encontrar la zona en la que imprime el mensaje, y vemos cómo existe una diferencia notable entre dos aplicaciones que realizan la misma función.

Hola mundo en MASM32:



Hola mundo en C:



Para empezar podemos ver que la versión en C ocupa el séxtuple que la programada en ensamblador.



Veamos el código que se ejecuta en primera instancia, las cadenas de texto y las APIs importadas en cada uno.

Ensamblador:



C:



En la versión asm el código es muy parecido al escrito más arriba, y tanto las cadenas de texto referenciadas como la llamada a apis se corresponden con las utilizadas en el código fuente. Por el contrario, el compilador de C modfiica el código, y vemos cómo aparecen más cadenas de texto y se importan muchas más APIs.

Con esto comprobamos cómo los compiladores de alto nivel realizan modificaciones en el código, por lo que al analizar un programa, rescatar la idea del programador se convierte en una tarea un poco más complicada. Por supuesto, no se puede confiar en esto como protección. Se puede aconsejar la optimización de código porque puede tener como efecto lateral una pequeña ofuscación del código pero, al ser una transformación de código que no controlamos, ¿no podría afectar negativamente?

Por otra parte, si se debe dar información sobre un evento y no se para a pensar en ello, se puede dar por hecho que la información del evento (¿un registro fallido?) se encontrará cercana a la comprobación, y si se puede seguir la ejecución del programa, vendrá justo detrás de ésta. Es aconsejable separar la comprobación de la decisión y de la información devuelta al usuario (en forma de continuación con la versión de ejecución, por ejemplo).

Un mal hábito que se puede encontrar en más de una ocasión consiste en no mostrar una NAG (ventana de aviso) en caso de fallar el registro, pero a cambio cerrar el programa. Este hecho permite que el atacante pueda detener la ejecución cuando se llama a la API encargada de termina con la aplicación y solamente mirando desde donde es llamada se acercará a tu rutina de comprobación.

Personalmente considero mucho más razonable que una aplicación ante un intento de registro continue una ejecución normal, pero la funcionalidad que se quiere dar a la versión registrada dependa de la clave introducida.

Resumiendo un poco este post, digamos que si no queremos que nuestra protección sea presa fácil, por lo menos no colaboremos a ello ;)

Mikel Gastesi

Fuente: S21sec e-crime

El día de hoy vamos a hablar sobre los packers/protectors.

Definimos packer/protector como un programa que toma como entrada un fichero ejecutable y devuelve otro fichero ejecutable con la misma funcionalidad pero con ciertas protecciones añadidas que dificultan su análisis. Existe también la posibilidad de proteger el programa partiendo desde el código fuente e indicando las zonas calientes.

Se puede decir que los primeros programas de este estilo únicamente pretendían reducir el tamaño del ejecutable, de ahí el nombre de packers, pero se fueron introduciendo técnicas de protección, dando el paso a los protectors. Nosotros utilizaremos el término packer indistintamente para ambos ejemplos.

¿Cómo funciona?

El packer debe cifrar al menos la sección ejecutable del fichero a proteger, y en el momento de ejecutarlo debe ser capaz de descifrarlo y ponerlo en memoria. Existen packers que cifran el fichero completo, pero la mayoría optan por introducir una nueva sección, escribir en ella su rutina de descifrado y redirigir el punto de entrada a la misma.

Por supuesto, existen diferente maneras de implementarlo, ya que nos podemos encontrar con cifrados manuales que cifran una sección con un XOR, introducen la rutina de descifrado en alguna parte del ejecutable no utilizada y modifican la cabecera PE para que apunte a dicha rutina.

Si vemos las secciones de un mismo programa con y sin upx, podemos ver como mientras uno tiene el punto de entrada en la sección de código el otro tiene las secciones renombradas y el punto de entrada no apunta a la primera sección. El código que se ejecute en este segundo caso es el encargado de poner en memoria el programa desempacado antes de ejecutarlo.


EP y secciones de un programa escrito en c.


EP y secciones de un programa con UPX


Una protección de este tipo tiene la ventaja de que el desarrollador se despreocupa de la protección del software, y alguien ducho en el tema es el encargado de protegerla.

Visto el funcionamiento del mismo, se nos ocurren dos formas diferentes de atacar esta protección:
Revertir el cifrado del packer.
Atacar el momento en que el programa queda limpio en memoria antes de ejecutarse, volcar el proceso al disco y reconstruir lo necesario para obtener una copia funcional del original.

Cabe destacar que hoy día también se utiliza la virtualización como protección, ya que añade un grado de complejidad al análisis del programa.

En vista de los dos ataques mencionados, el segundo resulta mucho más asequible, pero para cada fase tenemos algunas contramedidas.
Para intentar evitar que se pueda llegar a detener la ejecución en el punto de entrada original del programa (OEP), se emplean "trucos" anti-debug
Para evitar que del volcado se obtenga un fichero funcional, se emplean técnicas anti-dump.
En próximos post hablaremos de algunas de estas protecciones.

Mikel Gastesi

Fuente: S21sec e-crime

Los trucos anti-debug consisten generalmente en diversas comprobaciones que tratan de detectar ciertos comportamientos que indiquen la presencia de un depurador para poder actuar en consecuencia.

Acostumbro a llamarlos trucos y no técnicas porque la mayoría son unas comprobaciones muy simples que pueden evitar que un novel pueda analizar la aplicación, pero que una vez conocidas por el mismo no suponen una barrera muy importante. De hecho, existen muchos automatismos para evitar las detecciones, como pueden ser diversos plug-ins para OllyDbg.

Existe mucha información sobre los anti-debug, ya que llevan mucho tiempo utilizándose, por lo que solamente comentaremos algunos de ellos. Podemos ver una lista extensa de anti-debug en SecurityFocus, página que referenciaremos cuando nos sirva de ejemplo.
El día de hoy trataremos de detectar la interacción de alguien con nuestro programa mediante un depurador, detectando las tres maneras más comunes de detener una ejecución

Detección de puntos de ruptura:

Si se establece un punto de ruptura sobre cierta instrucción, lo que realmente realiza el depuradore es reemplazar un byte por "CC" (int3), de tal manera que si se ejecuta saltará una excepción que manejará el depurador. En este momento buscará en una lista de puntos de ruptura si la dirección actual se encuentra en ella y repondrá el byte que había reemplazado.

De este modo, si se comprueba que, por ejemplo, en la primera instrucción de una API nos encontramos con un "CC" significará que se ha establecido un punto de ruptura en la misma.
En Securityfocus se habla de esto en el punto "- Uncategorized anti-debug --> (2) CC scanning"

Para completar la definición, veamos a continuación una implementación de la detección de un punto de ruptura en la API MessageBox:



Detección de puntos de ruptura en memoria.

Para establecer un punto de ruptura en memoria sobre alguna acción (lectura, escritura o ejecución), el depurador quita el permiso para ello. Si establecemos un punto de ruptura en escritura, el depurador quitará este permiso, de manera que cuando el programa intente escribir en dicho punto saltará una excepción que manejará el depurador, comprobará que en dicha dirección de memoria se ha establecido un punto de ruptura, restaurará los permisos y mostrará la ejecución detenida.

En estos casos, existe la posibilidad de modificar los permisos, de tal manera que los puntos de rupturan no surjan efecto.

En el siguiente código vemos cómo si establecemos un punto de ruptura en la zona reservada en el momento en que la ejecución llega a la interrupción, el depurador no se detendrá, puesto que la propia aplicación habilita el permiso de escritura antes de escribir en ella.



Detección de puntos de ruptura hardware

Los registros de depuración (Debug Registers) permiten establacer hasta cuatro puntos de ruptura, pero también pueden ser detectados y/o borrados, ya que se puede consultar los valores de dichos registros, alojados en la estructura Context (ESP+C). Se puede encontrar código que implemente el borrado de estos puntos de ruptura en el punto 7 del apartado CPU antidebug del enlace anterior: "Debug registers manipulation".

Mikel Gastesi

Fuente: S21sec e-crime

Siguiendo con las técnicas antidebug, pensemos en qué más cosas podemos tratar de detectar.
Si estamos siendo depurados
Si se está ejecutando una aplicación no deseada
Si se tiene instalada una aplicación no deseada
Tratar de evitar el attach del proceso desde un depurador
Personalmente el uso de las técnicas comentadas en los puntos 2 y 3 no me parece ético en el ámbito del software comercial, ya que el ejecutar ciertas aplicaciones (y aún más el hecho de tener aplicaciones instaladas) no incumbe al creador de software, pero son técnicas muy utilizadas. Veamos algunos ejemplos:

Tratar de saber si estamos siendo depurados:
IsDebuggerPresent, CheckRemoteDebuggerPresent.


Consulta de ciertos valores dependientes de la presencia de un depurador, como NTGlobalFlag, valores devueltos por NtQueryInformationProcess, etc.


Protecciones de tiempo: Esta protección, menos técnica, trata de averiguar el tiempo que se tarda en ejecutar cierto código, ya que si el tiempo es muy elevado se puede suponer que se ha detenido la ejecución y, por tanto, está siendo depurado. Existen varias maneras de obtener el tiempo transcurrido, con GetTickCount, QueryPerformanceCounter, rdtsc o GetProcessTimes.


Excepciones. Si el programa levanta una excepción, el depurador por defecto detiene la ejecución y la maneja, de tal modo que la ejecución continúa en la instrucción siguiente. Por contra, si el propio programa instala un manejador de excepciones, podrá redigir el flujo a donde desee. Podemos utilizar SEH (Structured Exception Handler) o VEH (Vectored Exception Handler).


Comprobar que el proceso padre no sea un depurador (o esperar que sea explorer.exe)


Buscar aplicaciones no deseadas en ejecución:
Por ejemplo, mediante el título de las ventanas


Mediante el nombre del proceso


Mediante un patrón de bytes


Buscar aplicaciones no deseadas instaladas: Existen diveros métodos, como buscar ficheros conocidos en rutas concretas o entradas de registro conocidas. Cualquier característica que identifique el software nos puede servir pero, como hemos comentado al inicio, no es una actitud muy recomendable.

Tratar de evitar el attach del proceso desde un depurador:
Apertura exclusiva: Se realiza una apertura exclusiva del fichero.

Sobreescritura de API. Una manera poco elegante puede consistir en sobreescribir alguna API que sepamos que se va a ejecutar.


Existe además algún truco para intentar cazar al atacante cuando no se lo espera, como puede ser la introducción de código en callbacks TLS, tal y como se puede ver en alguno de los primeros retos publicados, de tal manera que este código se ejecuta antes que la supuesta primera instrucción del programa.

Recordad daros una vuelta por Securityfocus para ver alguno que se me haya escapado ;)

Mikel Gastesi

Fuente: S21sec e-crime

Tras ver diversos trucos para detectar la presencia de un depurador o la de cualquier programa no deseado, en esta ocasión vamos a ver otro tipo de técnicas básicas, enfocadas a tratar de evitar que un volcado del proceso resulte en un ejecutable funcional. Estas técnicas, de las que hablaremos a continuación, son conocidas como anti-dump.

La idea principal es conseguir que el programa no contenga toda la información necesaria en memoria, aunque se tiene la limitación de que la funcionalidad del mismo no puede variar.

Veamos varias formas de evitar un volcado correcto:
Ejecución de código fuera del proceso: Si reservamos memoria y ejecutamos código desde una región externa al proceso, un volcado normal no tendrá este código y no podrá funcionar correctamente.
Destrucción de la cabecera PE: Una vez que no haga falta, se pueden modificar datos de la cabecera, de tal manera que un volcado no nos proporcionará un fichero PE válido y no pordrá ser arrancado.
Destrucción de la IAT: Si, por ejemplo, se añade una redirección intermedia en la tabla de importaciones, el fichero volcado no podrá cargar las APIs llamadas y no se podrá ejecutar.
Robado de bytes: Durante el desempacado y puesta en memoria del proceso, se puede modificar el estado del programa para simular haber ejecutado ciertas instrucciones, de modo que un volcado del proceso resultará en un programa en el que faltan instrucciones y no funcionará.
Estas técnicas han sido y son utilizadas por diversos packers y, una vez más, tras comprender su funcionamiento, han sido rotas, puesto que son protecciones "reversibles". Veamos, de una manera un tanto abstracta, los pasos que se pueden dar ante estas protecciones.

Para el primer caso, se puede volcar dicha sección a disco, añadirla dentro del ejecutable, y corregir las referencias al mismo.
Para el segundo, se puede utilizar la cabecera del fichero empaquetado como base. Existen herramientas que vuelcan el proceso a disco y reconstruyen la cabecera en base al disco original.
En el tercer caso se debe reparar la tabla de importaciones, para lo cual se deberá de localizar el momento en que ésta es destrozada. La automatización mediante alguna herramienta como ImportReconstructor puede ser muy útil.
Por último, el robado de bytes de podrá analizar de diversas maneras:
- Descubriendo qué instrucciones se han podido ejecutar en base al estado de la pila, registros, etc,
- Se puede tratar de localizar las instrucciones (o emulaciones) ejecutadas durante el desempacado.
- Se puede tratar de identificar el lenguaje de programación utlizado y estudiar cómo son las primeras instrucciones de los programas compilados en dicho lenguaje.

Mikel Gastesi

Fuente: S21sec e-crime