Está en la página 1de 8

ENSAMBLADOR

Principios en ensamblador
en 18:13 | | Etiquetas: ASM, PFC, Reversing

Introduccin
El objetivo de esta entrada no es otro que dar unas nociones bsicas de ASM para tener una base con la que
empezar a realizar reversing para los menos avezados.
Qu es?
Una entrada donde se condensen los principios bsicos a conocer y tener en cuenta para introducirnos un
poco en el mundo del reversing. Tmalo como una pequea gua de referencia, nada ms.
Para un buen aprendizaje de ASM consulta el libro The art of assembly language.
Qu no es?
No se trata de un tutorial sobre programacin en ASM, ni se trata de explicar conceptos avanzados en la
materia ni lenguaje.

Prerrequisitos

Sistema binario.
Sistema hexadecimal.
Conocer el funcionamiento de una CPU.
Conocer cmo se estructura un sistema operativo.
Conocer como se procesan y almacenan los datos en memoria.

Qu es la ingeniera inversa?
Wikipedia (El objetivo de la ingeniera inversa (reversing) es obtener informacin a partir de un producto
accesible al pblico, con el fin de determinar de qu est hecho, qu lo hace funcionar y cmo fue fabricado.

El mtodo se denomina as porque avanza en direccin opuesta a las tareas habituales de ingeniera, que
consisten en utilizar datos tcnicos para elaborar un producto determinado.

La ingeniera inversa es un mtodo de resolucin. Aplicar ingeniera inversa a algo supone profundizar en el
estudio de su funcionamiento, hasta el punto de que podamos llegar a entender,modificar y mejorar dicho
modo de funcionamiento.)

Adentrndonos en ASM
Obtener unas nociones bsicas de ensamblador es fundamental para comenzar nuestra incursin en el
mundo del reversing, hazte a la idea de que tendrs que manejarte al dedo con l.

Olvdate de las facilidades que podas gozar en python, C, C++, perl, etc. Esto es otra historia, aqu usaremos
abreviaturas y nmeros, y probablemente al comienzo todo te parezca bastante lioso e incluso frustrante.

Bits, Bytes, Words DWords

BIT Unidad mnima de informacin. Su valor puede oscilar entre el 0 o 1. El sistema binario se
forma por la unin de varios bits.
BYTE Un byte est formado por 8 bits. Su valor puede oscilar entre 0-255. Es un sistema en base
2. Nosotros para facilitar la lectura de los nmeros binarios, usaremos el sistema hexadecimal (sistema en
base 16) por la rapidez y facilidad para leer.
WORD Son dos bytes o lo que es lo mismo 16 bits. Su valor oscila entre 0-65535d (0h 0FFFFh)
DWORD Son dos words o lo que es lo mismo 32 bits. Su valor oscila entre 0-4294967295d(0h0FFFFFFFFh)

Registros
Similar a las variables. Un registro es una zona especial en la memoria de nuestro procesador donde
podemos almacenar y consultar un valor nico. Con la salvedad de que existen un nmero limitado de
ellos y cada uno tiene un cometido especfico.
En arquitecturas Intel (que ser la elegida por nosotros) podemos distinguir un total de 8 registros:

EAX (Extended Accumulator Register) Destacamos dos funcionalidades de uso comn para este
tipo de registro: Almacenar el valor de retorno de una funcin y utilizarlo como contenedor para resolver
sencillas operaciones matemticas.

Es un registro voltil, dado que su valor no es almacenado. A pesar de que se establezca el valor de retorno
de una funcin al contenido del mismo.
EBX (Extended Base Register) - Suele utilizarse como apoyo para acelerar el clculo de
operaciones. Es un registro no voltil.
ECX (Extended Counter Register) Registro voltil que puede ser utilizado como contador de bucle
o contenedor de parmetros que sean pasado a funciones
EDX (Extended Data Register) Registro voltil usado mayormente como parmetro para funciones.
Normalmente se usa tambin para almacenar variables a corto plazo dentro de una funcin.

ESI (Extended Source Index) Registro no voltil que normalmente es usado como puntero. Es
utilizado por aquellas funciones que requieren un origen y un destino para los datos que se utilizan.
Apuntando este al origen en todo momento.
EDI (Extended Destination Index) - Al igual que el registro ESI, es no voltil y usado como puntero, a
diferencia de que este apunta al destino siempre.
EBP (Extended Base Pointer) Registro no voltil con dos usos comunes segn el compilador que
utilicemos, as puede desempear el papel de un registro como otro cualquiera o ser el puntero al marco de
pila.
ESP (Extended Stack Pointer) Almacena un puntero a la parte inferior de la pila. Tras ejecutar una
funcin el valor que tena el registro al principio debe de coincidir con el asociado tras la funcin
EIP (Extended Instruction Pointer)

Estos registros de 32 bits a su vez pueden ser divididos en registros de menor tamao (16 bits, y 8 bits,
distinguiendo la parte superior e inferior).
Por tanto tenemos:

8 registros de 32 bits: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP EIP

8 registros de 16 bits: AX, BX, CX, DX, SI, DI, BP, SP, IP

8 registros de 8 bits: AH, AL, BH, BL, CH, CL, DH, DL

Donde H hace referencia a Higher (Bits ms significantes de la direccin) y L a Lower(Bits menos


significantes de la direccin).

De esta forma ECX = 0x24101989, quedara como CX = 0x1989, CH = 0x19 y CL = 0x89, y de paso ya
sabis cundo hacerme un regalo (rubias por favor ;D).

Ahora mismo debemos de quedarnos con una idea ligeramente similar a esta:

Las banderas (Flags)


Se tratan de simples bits que nos indican el estado de algo. En arquitecturas de 32bits tenemos un total de 32
banderas, pero nosotros slo vamos a utilizar tres de ellas:

Z-Flag (Zero flag) Ser el flag que ms acabaremos usando, cuando su valor es 1 nos indica que
el resultado de una operacin fue 0. Su valor puede ser cambiado por todas aquellas instrucciones que
realicen operaciones matemticas y por la instruccin cmp
C-Flag (Carry flag) Su valor va ligado al uso de acarreo en operaciones de suma y resta.
O-Flag (Overflow flag) Su valor cambia a disposicin del valor que adopte el bit ms significativo. Si
queremos realizar la suma de 127 consigo mismo, este es representado como 0111 1111, en este momento
el MSB es 0, pero al realizar la operacin (0111 1111 + 0111 1111) obtenemos 1111 1110, siendo 1 ahora el
valor del MSB.

Segmentos (Segments) y desplazamientos


(Offsets)
El concepto de segmento podemos definirlo como la zona de memoria donde
las instrucciones(CS), datos (DS) o pila (SS) son almacenadas.
A su vez cada segmento es dividido en 'offsets'. As en aplicaciones de 32-bits estos offsets estos van
numerados desde 00000000 a FFFFFFFF, o lo que es lo mismo 65536 zonas de memoria.
Por tanto podemos aceptar el concepto de offset como un valor indicativo de desplazamiento desde el punto
de inicio del objeto hasta un punto dado, presumiblemente siempre dentro del mismo objeto.
Un ejemplo real de esto podemos ponerlo como un libro en el caso de un segmento, y una lnea especfica de
una pgina como un offset.

La pila
Podemos ver el concepto de pila como una estructura de datos, en la que el modo de acceso a sus elementos
es de tipo LIFO (Last Input First Output Ultimo en entrar, primero en salir).

Distinguimos dos comandos para interactuar con ella:


Push (apilar) Coloca un objeto en la pila.
Pop (desapilar) Saca un objeto de la pila.

Cuando llamamos a una funcin, todos sus parmetros son almacenados en sentido inverso en la pila antes
de hacer de pasar el flujo de ejecucin a la funcin.
NuestraFuncion(int param1, int param2, char param3, float param4)

Esto en ensamblador quedara:


push param4

push param3
push param2
push param1
call NuestraFuncion
add esp, 10h

Como comentabamos vamos pasando los parmetros a nuestra pila para posteriormente realizar la llamada.
Despus de acabar la ejecucin de nuestra funcin el puntero a pila sigue teniendo 16 bytes por delante de
lo que tena en un principio. Con la intencin de restaurar el estado original de la misma, debemos aadir al
puntero el valor 10h que corresponde a los 4 elementos que hemos introducido en la pila (4bytes por cada
instruccin push ejecutada).

Operaciones lgicas
A lo largo de nuestro recorrido deberemos conocer cmo funcionan las operaciones lgicas a nivel de bits:

Operacin AND Realiza la funcin booleana de producto lgico.


Operacin OR Realiza la funcin booleana de suma lgica.
Operacin XOR - Realiza la funcin booleana de AB+AB.
Operacin NOT Realiza la funcin booleana de inversin o negacin de una variable lgica.

Instrucciones
Instruccin NOP Es una abreviatura de No operation y su uso es de simple relleno.

Desplazando datos:
'mov' Instruccin anloga a '=', puede mover datos entre un registro y memoria, dos registros o
incluso entre una constante y memoria.

'movsx' Versin especializada para usar con registros de diferentes tamaos y con signo.

'movzx' Versin especializada para usar con registros de diferentes tamaos y sin signo.

lea (Load Effective Address) Uso similar a mov y utilizado para calcular desplazamientos en
vectores, dado que podemos hacer uso de [direccin comienzo + offset*datasize] para encontrar la
direccin de un elemento en concreto del vector. Su uso tambin se basa para clculos de multiplicaciones y
sumas.

Operaciones lgicas y matemticas


add, sub Permiten sumar o restar respectivamente a un registro, un valor constante, un registro
o un puntero.

add eax, 5
sub ecx, 5
add ebx, eax

inc, dec Permiten incrementar o decrementar respectivamente un registro.

inc ebx
dec eax

and, or, xor, neg Instrucciones encargadas de realizar las operaciones lgicas a nivel de bits,
que hemos explicado anteriormente.

and eax, 5 ; eax = eax & 7


xor eax, 0 ; eax = eax ^ 0
or eax, 19 ; eax = eax | 19
neg eax ; eax = !eax
xor eax, eax ; eax = 0

mul, imul, div, idiv, cdq Correspondientes a las operaciones de multiplicacin y divisin,
ambas hacen uso de los registros de 64 bits edx:eax. mul multiplica el valor sin signo almacenado en el
registro eax con el operando y almacena el resultado en el registro de edx:eax. Por otro lado imul realizad
la misma operacin a excepcin de que el valor es con signo.

mul ecx ; edx:eax =eax * ecx (Sin signo)


imul ecx ; edx:eax = eax * ecx (Con signo)

Cuando se usan dos parmetros, el comportamiento es el esperado, multiplica el primero por el segundo y
almacena el resultado en el primer parmetro.

div divide el valor almacenado en el registro edx:eax por el operando y el cociente lo almacena en eax. El
resto o mdulo es almacenado en edx. Al igual que suceda con imul la operacin idiv permite utilizar
valores con signo.

div ecx ; eax = edx:eax / ecx (Sin signo)


; edx = edx:eax % ecx (Sin signo)
idiv ecx ; eax = edx:eax / ecx (Con signo)
; edx = edx:eax % ecx (Con signo)

Por otro lado la operacin cdq es usada antes que idiv y su cometido es convertir el valor de 32bit
almacenado en eax en un valor de 64 bit para almacenarlo en edx:eax sobreescribiendo cualquier valor que
haya en edx con ceros en caso de ser eax positivo o con F en caso de ser eax negativo.
shl, shr Shift Left y Shift Right respectivamente, nos permiten realizar desplazamiento a nivel de
bits hacia la derecha e izquierda, al igual que los operadores << y >> usados en C.

Saltos Estas instrucciones son utilizadas en caso de bucles y condiciones de comprobacin. Realizando una
comprobacin del valor que almacena el registro, direccin o constante asociada a la instruccin.

jmp Enva la ejecucin del programa a la direccin especificada

jmp 2420h ; Saltamos a la direccin 0x2420

call, ret call tiene un uso similar a jmp a excepcin de que adems de realizar el salto a la
direccin solicitada, almacena en la pila la direccin de la instruccin ejecutada.

Por otro lado ret obtiene el tope de la pila y desplaza el flujo de ejecucin de nuestra aplicacin hasta la
direccin de memoria asociada. Si el registro SP apunta a una direccin errnea o esta ha sido sobreescrita
desencadenar que nuestra aplicacin se cierre inesperadamente. Con estas instrucciones jugaremos ms
adelante.
cmp, test cmp compara los dos operandos y establece una serie de flags como resultado de la
operacin realizada.

Por otro lado test realiza una operacin and a nivel de bit entre las dos variables y posteriormente realiza
una comparacin con 0.

o
o
o

Los flags ms comunes:


Cero (Zero) Lo establece nicamente si los dos elementos son iguales.
Mayor que (Greater than) Lo establece si el primer elemento es mayor que el segundo.
Menor que (Less than) Lo establece si el primer elemento es menor que el segundo.

cmp eax, ebx ; Compara EAX y EBX y establece el flag Zero si son iguales
cmp EAX, [404000] ; Compara EAX con el contenido de 404000
test eax, eax

Otras instrucciones relacionadas con los saltos


ja - Salta si es mayor - CF=0 y ZF=0
jae Salta si es mayor o igual - CF=0
jb (el whisky no) Salta si es menor - CF=1
jbe - Salta si es menor o igual - CF=1 o ZF=1
jc Salta si el flag de acarreo est establecido - CF=1
jcxz Salta si CX es 0 - CX=0
je Salta si la comprobacin es igual - ZF=1

jecxz Salta si ECX es 0 - ECX=0


jg - Salta si es mayor (Con signo) - ZF=0 y SF=OF
jge Salta si es mayor o igual (CS) - SF=OF
jl Salta si es menor (CS) - SF != OF
jle Salta si es menor o igual (CS) - ZF=1 y OF != OF
jmp - Salta - Siempre salta
jna Salta si no es mayor (Sin signo) - CF=1 o ZF=1
jnae - Salta si no es mayor o igual (SS) - CF=1
jnb - Salta si no es menor (SS) - CF=0
jnbe - Salta si no es menor o igual (SS) - CF=0 y ZF=0
jnc - Salta si el flag de acarreo no est establecido - CF=0
jne - Salta si no es igual - ZF=0
jng - Salta si no es mayor (CS) - ZF=1 o SF!=OF
jnge - Salta si no es mayor o igual (CS) - SF!=OF
jnl - Salta si no es menor (CS) - SF=OF
jnle - Salta si no es menor o igual (CS) - ZF=0 y SF=OF
jno - Salta si el flag de overflow no est establecido - OF=0
jnp - Salta si el bit de paridad no est establecido - PF=0
jns - Salta si el flag de signo no est establecido - SF=0
jnz - Salta si no es cero - ZF=0
jo - Salta si el flag de overflow est establecido - OF=1<7li>
jp - Salta si el bit de paridad est establecido - PF=1
jpe - Salta si el bit de paridad es igual - PF=1
jpo - Salta si el bit de paridad es impar - PF=0
js - Salta si el bit de signo est establecido - SF=1
jz - Salta si es cero - ZF=1