Código Muerto ASM x86

En un grupo de Facebook el cual frecuento, un miembro solicitó ayuda de cómo traducir el siguiente código ensamblador:

Obteniendo información

Podemos observar que es un ELF (Linux) y que al parecer el código fue copiado desde el depurador GDB con el comando:

disas main

Otra forma de obtener el código ensamblador de un archivo ELF es por medio del comando:

objdump -d ./archivo

Se puede destacar que las direcciones no poseen una base (base address), la explicación a esto es que probablemente el ejecutable fue compilado con la protección PIE.

Sin más preámbulos comentemos las instrucciones:

Como es posible observar, lo que hace este programa es: multiplicar cada carácter de la string 3jd9cjfk98hnd por el tamaño de esta misma e ir sumando el resultado.

Programación en MASM

Pongamos lo teórico a lo práctico, para ello realizamos el mismo programa pero en MASM, aun cuando el sistema operativo será distinto, la arquitectura, set de instrucciones y librerías serán similares.

El código queda de la siguiente forma:
Ensamblamos y enlazamos (link), para luego depurar el ejecutable y ver el valor que retorna printf():

Dando como resultado el valor: 15015

Programación en C

Una forma de corroborar el resultado obtenido es que, una vez entendida la lógica del programa podemos intentar replicarlo en lenguaje C y ejecutar este dentro de un sistema GNU/Linux:

Compilamos el código y lo ejecutamos:

El código generado es el mismo.

A continuación se lista el contenido de la función main en lenguaje ensamblador:

El resultado es similar al código publicado por el miembro del grupo, aunque no hay protección PIE (utilicé una versión de gcc más antigua), la cantidad de instrucciones difieren y se utilizan algunas instrucciones distintas como repnz scas y not.

Otra cosa que podemos observar, es la ineficiencia dentro del BUCLE, pues cada vez que pasa por él, obtiene el tamaño de la string:

Por lo general, como buena práctica de programación, se recomienda usar variables en vez de constantes pues facilita futuras modificaciones de código, irónicamente a nivel de lenguaje ensamblador, esta buena práctica (en este caso) hizo al programa menos eficiente.

Se recomienda escribir el FOR de esta manera:

En vez de:

Lo más probable, es que el compilador al momento de leer el código de fuente, encontró que la variable code no era una constante y por ello la necesidad de insertar una instrucción que verificara en cada ciclo del bucle su tamaño por si esta fuese alterada.

Conclusiones

Como conclusión fue posible entender el comportamiento de un binario por medio de la lectura de su código muerto, recreamos el programa tanto en lenguaje ensamblador como en C, logramos visualizar el proceso de transcripción de un lenguaje de alto nivel (conocido también como lenguaje intermedio) y cómo este podría degradar el rendimiento en ciertas circunstancias. Cualquier persona que se está iniciando en programación pensaría que lo mejor sería programar todo en lenguaje ensamblador, pero se debe tener en cuenta que el tiempo necesario para programar es mayor que en los lenguajes de alto nivel, es por ello que se tiende a utilizar este magnifico lenguaje sólo en circunstancias específicas, como por ejemplo: en proyectos en donde lo primordial es la eficiencia y calidad de la programación (micro-controladores, drivers, sistemas embebidos) por sobre el tiempo que esto requiera.

 

Compartir

5 Comentarios

Jesus 26/09/2019 Responder

Hola,

Se que el post tiene un tiempo, pero a lo mejor puedes ayudarme.

En ese mismo código assembly, ¿Como podria identificar los Basic Blocks?

Muchas gracias

Victor Gutiérrez 26/09/2019 Responder

Hola Jesus, para identificar los bloques de código ensamblador, debes separar este código cada vez que encuentres instrucciones de salto (JMP y JB en este caso), saludos

Jesus 02/10/2019 Responder

Muchas gracias por responderme 🙂

Indicas JMP y JB. Pero en el código original (el del inicio de la página) ¿habría que tener encuenta el JL? es decir, ¿habría 3 bloques de código?

Gracias de nuevo!

Matias 11/09/2020 Responder

es posible que al ser como dice Jesús el bucle sea un DO-WHILE en vez de un FOR?

Matias 15/09/2020 Responder

Hola Victor,

porque deberiamos utilizar un bucle for y no un DO WHILE?

Responder a Jesus Cancelar respuesta