Reverse Engineering
Reverse Engineering
engineering
PID_00277609
Ninguna parte de esta publicación, incluido el diseño general y la cubierta, puede ser copiada,
reproducida, almacenada o transmitida de ninguna forma, ni por ningún medio, sea este eléctrico,
mecánico, óptico, grabación, fotocopia, o cualquier otro, sin la previa autorización escrita
del titular de los derechos.
© FUOC • PID_00277609 Reverse engineering
Índice
Introducción............................................................................................... 5
1. Reverse engineering............................................................................. 7
2. Lenguaje ensamblador...................................................................... 8
3. Código de ejemplo............................................................................. 9
4. Información general......................................................................... 12
5. Strings................................................................................................... 14
6. Variables............................................................................................... 15
7. Pila o Stack.......................................................................................... 17
8. MOV y LEA........................................................................................... 18
9. Registros............................................................................................... 19
10. Bucles..................................................................................................... 21
11. Condicionales...................................................................................... 27
11.1. Registro de estado (FLAGS) ......................................................... 27
12. Subrutinas............................................................................................ 32
Introducción
1. Reverse engineering
Análisis
Pero la ingeniería inversa también tiene sus riesgos en caso de usarse para mo- Contenido
dificar código con fines malintencionados; de esta forma, los profesionales en complementario
desarrollo de software deben ser conscientes de estos riesgos y, por lo tanto, Existe una gran diversidad de
investigar cómo desarrollar software seguro –tanto las funciones a implemen- herramientas en el mercado
para realizar reverse engineering
tar como la lógica y el flujo del software– ya que si está colocando código con- a partir de desensambladores y
debugadores. Para realizar es-
fidencial en un entorno en el que un atacante puede obtener acceso, debería te módulo se han utilizado dos
herramientas gratuitas, IDA y
preocuparse por los riesgos de la ingeniería inversa o la modificación no au-
Ghidra.
torizada del código. IDA <https://www.hex-
rays.com/products/ida/sup-
port/download_freeware/>
Ghidra <https://ghi-
dra-sre.org/>
© FUOC • PID_00277609 8 Reverse engineering
Así pues, para poder llevar a cabo reverse engineering e investigar el desensam-
blado y deducir cómo se ha desarrollado el código fuente que lo ha generado,
se deben tener unos conocimientos básicos del lenguaje ensamblador (assem-
bler).
Este módulo no pretende ser una guía de aprendizaje del lenguaje ensambla-
dor, pero sí que se recomienda su lectura acompañada con la del módulo «Pro-
gramación en ensamblador (x86-64)», ya que en ese módulo se puede profun-
dizar en este lenguaje; además, podréis encontrar ejemplos ilustrativos de có-
mo se convierte el código fuente en lenguaje ensamblador. En cambio, en este
módulo el proceso es a la inversa, es decir, a partir del lenguaje ensamblador,
se deduce cómo se ha desarrollado el código fuente.
if (a > b) {
maxA = 1;
maxB = 0;
}
3. Código de ejemplo
• main
– Entrada principal del programa
• introducirPassword
– Introducción de la contraseña por teclado del usuario
• validationPassword
– Genera el password a través de un bucle con códigos ASCII generando
el password ABCD
– Comprueba si el password introducido por el usuario es correcto
• accesoValido
– Acceso en caso de que la contraseña introducida por el usuario sea
correcta
Hay que tener en cuenta que este código contiene funciones vulnerables como
strcpy y strcmp; permite introducir un password de una longitud superior a la
longitud máxima de la contraseña y tampoco lo comprueba; todos estos ele-
mentos se han incluido expresamente para detectarlos en el momento de rea-
lizar la ingeniería inversa y observar las consecuencias que conlleva no aplicar
un desarrollo de programación de código seguro.
© FUOC • PID_00277609 12 Reverse engineering
4. Información general
5. Strings
Esto nos da la posibilidad de poder observar los mensajes y otros textos; por
ejemplo, si se hubiera asignado una contraseña de tipo puerta trasera, o una
contraseña preestablecida a un String, nos aparecería visualizada; esto no quie-
re decir que una contraseña no se pueda asignar a una variable de otro modo;
de hecho, en el programa de ejemplo se ha asignado una contraseña a una
variable, pero a base de códigos ASCII, de forma que se puede llegar a deducir
realizando reversing.
6. Variables
Para poder observar los valores de las variables, se puede obtener la vista de la
pila de las variables haciendo doble clic en cualquiera de ellas; recordad que,
normalmente, estas variables se utilizan como valor de desplazamiento en la
memoria, como se ha podido observar en el ejemplo.
7. Pila o Stack
Para el manejo de los datos de la pila existen dos operaciones, apilar o PUSH,
que coloca un objeto en la pila, y su operación inversa, recoger o POP, que
retira el último elemento apilado.
8. MOV y LEA
9. Registros
• 16 registros de datos RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP y R8-R15.
• La denominación de ocho primeros registros es parecida a los 8 registros
de propósito general de 32 bits (EAX, EBX, ECX, EDX, ESI, EDI, EBP y ESP).
Un operando puede ser de los tipos: byte, word, double word y quad word. Hay
que tener en cuenta que lo hace en formato little-endian.
10. Bucles
En primer lugar, debemos tener en cuenta que IDA asigna nombres a las va-
riables en función de su ubicación en relación con la dirección de retorno. Las
variables locales se encuentran por encima de la dirección de retorno, mien-
tras que los parámetros de la función se encuentran debajo de la dirección
de retorno. Los nombres de las variables locales se derivan usando el prefijo
var_ unido con un sufijo hexadecimal; eso indica la distancia, en bytes: que
la variable se encuentra por encima del puntero. Por ejemplo, la variable local
var_C, en este caso, es una variable de 4 bytes (dword) que se encuentra -12 by-
tes (-0Ch tiene el valor -12 en decimal) por debajo del puntero ([ebp-0Ch]).
Los nombres de los parámetros de las funciones se generan utilizando el pre-
fijo arg_ combinado con un sufijo hexadecimal que representa la distancia
relativa desde el parámetro superior.
En primer lugar, observamos el flujo general del diagrama para localizar los
bucles implementados en la aplicación.
© FUOC • PID_00277609 22 Reverse engineering
El resto del código se puede deducir; por ejemplo, nuestra variable i es [ebp
+var_C]; por ejemplo, i++ corresponde a: add [ebp+var_C], 1 a conti-
nuación de esta línea vuelve al principio del bucle loc_401537.
© FUOC • PID_00277609 24 Reverse engineering
En la parte final del bucle podemos observar el condicional JNZ, que en reali-
dad comprueba el valor del resultado del retorno de la función validationPass-
word; tampoco existe un contador sobre el cual haya ninguna condición de
seguir en el bucle; por lo tanto, podemos deducir que se trata de una instruc-
ción do While.
11. Condicionales
• Salto�incondicional:
– JMP: salta de manera incondicional
• Saltos�condicionales, saltos que consultan el valor del flag una vez reali-
zada una operación:
– JA: salta si CF=0 y ZF=0 (jump if above).
– JAE: salta si CF=0 (jump if above or equal).
© FUOC • PID_00277609 28 Reverse engineering
Cabe destacar que en el modo gráfico de la herramienta IDA, en los saltos con-
dicionales muestra en color verde la línea del flujo en caso de que se cumpla
la condición, y en rojo en caso contrario.
© FUOC • PID_00277609 31 Reverse engineering
12. Subrutinas
Para conocer la relación entre los nombres de las etiquetas y las direcciones de
memoria abriremos el panel Names Window.
© FUOC • PID_00277609 33 Reverse engineering
Que además se puede comprobar en la vista del código en modo texto y tam-
bién en la opción Edit Function.
Una vez detenido podemos observar, por ejemplo, los valores de los registros;
en la siguiente imagen observamos el valor del registro eax, en el que pode-
mos observar que contiene el valor que se ha introducido por teclado.
Existen dos opciones para seguir con la ejecución del programa paso a paso
por cada instrucción.
Observemos también los valores de los registros; el valor de ebp o rsp conti-
núa siendo la dirección del puntero prevista donde se debía almacenar la di-
rección de retorno.
char buffer[10];
strcpy(buffer, password);
© FUOC • PID_00277609 42 Reverse engineering
En este ejemplo:
A través de esta ventana hemos observado que se utilizan las funciones vul-
nerables strcpy y strcmp.
Con el botón derecho accedemos a diversas opciones, entre las cuales se en-
cuentra Rename.
Este proceso se puede realizar para otros elementos, por ejemplo, las variables.
En este caso se ha detectado que var_17 es un array o el puntero de un array en
el que se almacena el valor que ha introducido el usuario por teclado; así pues,
renombraremos el nombre de la variable y le pondremos de nombre buffer.
strcpy(buffer, password);
Así pues, la llamada call strcmp comparará el valor 123456 con ABCD.
Donde
Corresponde a
Otra opción también posible es, en lugar de cambiar la instrucción JZ por JNZ,
cambiar la dirección de memoria a la que debe dirigirse el flujo de la ejecución
del programa en caso de que el flag ZF tenga el valor 1.
Una vez realizados los cambios podemos exportar el programa como un pro-
grama ejecutable.
© FUOC • PID_00277609 57 Reverse engineering