Assembler

14
1 Introducción El ensamblador es el lenguaje de programación que ustedes pueden ver al desensamblar un archivo en Olly. En este curso aprenderemos las bases de este lenguaje. Es posible que les parezca algo tedioso y largo como lo es igualmente para mí a la hora que lo escribo, pero sin duda les ayudará mucho a comprender nuestros tutoriales así mismo que es fundamental tener conocimientos básicos sobre este lenguaje sobre todo para todo aquel que tiene pretensiones serias de llegar a ser un buen cracker. Tabla de contenidos: 1 El procesador y los registros 1.1 Los registros generales y de trabajo 1.2 Los registros de Offset y punteros 1.3 Los registros de segmentos 1.4 El registro Flag 2 La Pila y sus instrucciones 2.1 Funcionamiento de la Pila 2.2 La instrucción PUSH 2.3 La instrucción POP 3 Los saltos condicionales y el CMP 3.1 Los saltos condicionales 3.2 La instrucción CMP 4 Las operaciones matemáticas 4.1 Adición y Sustracción : ADD y SUB 4.2 Multiplicación : MUL/IMUL 4.3 División : DIV/IVID 4.4 Otros : SHR y SHL 4.5 Lo opuesto de un número : NEG 5 Los puntos decimales y los negativos 5.1 Los puntos decimales 5.2 Negativos 6 Las instrucciones lógicas 6.1 Y lógico : AND 6.2 O lógico inclusivo : OR 6.3 O lógico exclusivo: XOR 6.4 No lógico : NOT 6.5 TEST 7 La Memoria y sus instrucciones 7.1 LEA 7.2 MOVSx 7.3 STOSx

description

Assembler

Transcript of Assembler

Page 1: Assembler

1

Introducción El ensamblador es el lenguaje de programación que ustedes pueden ver al desensamblar un archivo en Olly. En este curso aprenderemos las bases de este lenguaje. Es posible que les parezca algo tedioso y largo como lo es igualmente para mí a la hora que lo escribo, pero sin duda les ayudará mucho a comprender nuestros tutoriales así mismo que es fundamental tener conocimientos básicos sobre este lenguaje sobre todo para todo aquel que tiene pretensiones serias de llegar a ser un buen cracker. Tabla de contenidos: 1 El procesador y los registros

1.1 Los registros generales y de trabajo 1.2 Los registros de Offset y punteros 1.3 Los registros de segmentos 1.4 El registro Flag 2 La Pila y sus instrucciones

2.1 Funcionamiento de la Pila 2.2 La instrucción PUSH 2.3 La instrucción POP 3 Los saltos condicionales y el CMP

3.1 Los saltos condicionales 3.2 La instrucción CMP 4 Las operaciones matemáticas

4.1 Adición y Sustracción : ADD y SUB 4.2 Multiplicación : MUL/IMUL 4.3 División : DIV/IVID 4.4 Otros : SHR y SHL 4.5 Lo opuesto de un número : NEG 5 Los puntos decimales y los negativos

5.1 Los puntos decimales 5.2 Negativos 6 Las instrucciones lógicas

6.1 Y lógico : AND 6.2 O lógico inclusivo : OR 6.3 O lógico exclusivo: XOR 6.4 No lógico : NOT 6.5 TEST 7 La Memoria y sus instrucciones

7.1 LEA 7.2 MOVSx 7.3 STOSx

Page 2: Assembler

2

1- El procesador y los registros Los datos que el procesador necesita son guardados en lo que llamamos registros. Existen varios tipos de registros y cada uno tiene su propia utilidad. Ø registros generales o de trabajo Sirven para manipular datos, transferir parámetros cuando se llama a funciones DOS y para guardar resultados intermediaros. Ø registros de Offset o punteros Contienen un valor que representa un Offset que se combinara con una dirección de segmento. Ø registros de segmento Son utilizados para guardar la dirección del inicio de un segmento. Puede tratarse de la dirección el inicio de las instrucciones de un programa, del inicio de datos o del inicio de la pila. Ø registros de Flag Contienen bytes de los cuales cada uno tiene un rol indicador. 3

1.1 Los registros generales o de trabajo Los 4 registros generales más utilizados son (en 16 bits): AX, BX, CX y DX Ø AX: acumulador: sirve para efectuar cálculos aritméticos o para enviar un parámetro a una interrupción. Ø BX: registro auxiliar de base : sirve para efectuar cálculos aritméticos o bien para realizar cálculos sobre las direcciones Ø CX: registro auxiliar (contador): sirve como contador en los ciclos (loops) Ø DX: registro auxiliar de datos: sirve para almacenar los datos destinados a funciones. Los correspondientes a 8 bits son: AL, BL, CL, DL Esta es su utilización teórica, pero en la práctica pueden ser utilizados como bien se le plazca al programador. Estos registros son de 16 bits. Para obtener los de 8 y 32 debe seguirse la tabla indicativa para AX: EAX (32 bits) AX (16 bits) AH (8 bits) – AL (8 bits) E : “Extended” H : High L: Low 1.2 Los registros de offset o punteros Ø IP : puntero de instrucción: asociado al registro de segmento CS (CS:IP) para indicar la próxima instrucción que se va a ejecutar. Este registro no puede modificarse nunca directamente; será modificado indirectamente por las instrucciones de salto, por los subprogramas y por las instrucciones. Ø SI : índex de fuente : principalmente utilizado en las operaciones en cadenas de caracteres; es asociado al registro de segmento DS. Ø DI: índex de destinación: utilizado principalmente en las operaciones sobre cadenas de caracteres, asociado normalmente al registro de segmento DS. En el

Page 3: Assembler

3

caso de manipulación de cadenas de caracteres, será asociado a ES. Ø SP: puntero de pila: asociado al registro de segmento SS (SS:SP) para indicar el último elemento de la pila. Ø BP: puntero de base : asociado al registro de segmento SS (SS:BP) para acceder a los datos de la pila durante las llamadas de subprogramas (CALL)

4

Como los registros generales, éstos pueden ser extendidos a 32 bits agregándoles la “E” (EIP, ESI, EDI, ESP, EBP). En cambio no tienen parte en 8 bits. Los registros SI y DI son frecuentemente utilizados para las instrucciones de cadena y para acceder a los bloques de memoria. 1.3 Los registros de segmento El procesador utiliza direcciones para almacenar o recuperar datos. La dirección esta compuesta de 2 partes de 32 bits (o 16 bits según el modo utilizado). La primera es el segmento y la 2da. es el Offset. La dirección es presentada como sigue: segmento: Offset (por ejemplo: 0A000h:0000h). He aquí los diferentes segmentos: Ø CS: registro segmento de código: indica la dirección del inicio de las instrucciones de un programa o de una subrutina. Ø DS: registro segmento de datos: contiene la dirección del inicio de los datos de tus programas. Si tu programa utiliza varios segmentos de datos, este valor tendrá que modificarse durante su ejecución. Ø SS: registro segmento de pila: apunta sobre una zona llamada pila. Ø ES: registro segmento suplementario (extra segmento): utilizado, por defecto, por ciertas instrucciones de copia de bloque. Ø FS: registro segmento suplementario : parecido a ES Ø GS: registro segmento suplementario: parecido a ES 1.4 Los registros Flag Este registro es un ensamble de 16 bits. Pero este ensamble no significa nada, ya que los bits son modificados uno por uno y la modificación de un solo bit puede modificar el comportamiento del programa. Los bits de este conjunto son llamados “indicadores”. Bit 1 : CF Bit 2 : 1 Bit 3 : PF Bit 4 : 0 Bit 5 : AF Bit 6 : 0 Bit 7 : ZF Bit 8 : SF Bit 9 : TF Bit 10 : IF Bit 11 : DF Bit 12 : OF Bit 13 : IOPL Bit 14 : NT Bit 15 : 0 Bit 16 : RF

Page 4: Assembler

4

Bit 17 : VM Los bits 1,5,12,13,14,15 de este registro Flag de 16 bits no son utilizados. Las instrucciones aritméticas, lógicas y de comparación modifican el valor de los indicadores. Las instrucciones condicionales testean el valor de los indicadores y actúan en función del resultado. Los principales indicadores y su uso: CF: Carry Flag – Indicador de retención Luego de una operación, si el resultado es codificado en un número superior de bits, el bit de más será puesto en CF. Varias instrucciones pueden modificar su estado: CLC para ponerlo a 0, STC a 1 y CMC invierte su valor. PF: Parity Flag – Indicador de paridad Igual a 1 si el número de bits de un operando (parámetro de una instrucción) es par. AF: Auxiliary carry Flag: Indicador de retención auxiliar Parecido a CF ZF: Zero Flag – Indicador Cero Si el valor de una operación es nulo (igual a 0) ZF pasará a 1. Este indicador es frecuentemente utilizado para saber si 2 valores son iguales (sustrayéndolos) SF: Sing Flag – Indicador de signo SF pasa a 1 cuando el resultado es con signo (negativo o positivo) IF: Interruption Flag – Indicador de interrupción Permite quitarle la posibilidad al procesador de controlar las interrupciones. Si IF = 1 las interrupciones son tomadas en cuenta y si IF = 0 son ignoradas. La instrucción STI pone IF a 1 y CLI la pone a 0. DF: Direction Flag- Indicador de dirección Indica la manera de desplazar los punteros (referencias) durante las instrucciones de cadenas (sea positivamente, sea negativamente). STD lo pone a 1 y CLD a 0. OF: Overflow Flag – Indicador de desbordamiento. Permite encontrar y corregir ciertos errores producidos por instrucciones matemáticas. Muy útil para evitar plantones. Si OF=1 entonces se produce un Overflow Los otros indicadores no son más importantes por lo que no los abordaremos. Pequeño ejemplo de estos indicadores con una operación en binario: 0110 +0101 - 1011 Ø ZF=0 (resultado 1011 no es nulo) Ø SF=1 (el signo del resultado es negativo) Ø CF=0 (no hay retención)

2- La Pila y sus instrucciones 2.1 Funcionamiento de la Pila La Pila (“stack” en inglés) es un sitio que sirve para almacenar pequeños datos. Esta memoria temporal funciona como una pila de platos: el último plato que pondrás será el primero en ser tomado y el primer plato puesto (el último de abajo) será el último en ser tomado. Espero que la metáfora esté clara. Tomemos un ejemplo real: si pongo el valor A en la pila y luego pongo B y después C. Para recuperar estos valores el procesador tomará C primero, luego B y por último A.

Page 5: Assembler

5

Para la API GetDlgItemText, Windows necesita de estas informaciones: HWND hDlg, // (1) handle de la ventana de diálogo int nIDDlgItem, // (2) identificador de la ventana de diálogo LPTSTR lpString, // (3) apunta hacia el buffer para el texto int nMaxCount // (4) tamaño máximo de la cadena Podemos entonces poner, antes de llamar a esta función: MOV EDI, [ESP+00000220] pone el handle de la ventana de diálogo en EDI PUSH 00000100 push (4) tamaño máximo de la cadena PUSH 00406130 push (3) dirección del buffer para el texto PUSH 00000405 push (2) identificador del control PUSH EDI push (1) hanlde de la ventana de diálogo CALL GetDlgItemText llama la función

7

2.2 La instrucción PUSH Arriba mismo la hemos visto. Push significa “empujar” en español. Con esta instrucción podemos poner un valor en la pila. El valor “empujado” debe ser de 16 o 32 bits (a menudo un registro) o un valor inmediato. Ejemplo: PUSH AX PUSH BX PUSH 560 AX es puesto de primero en lo alto de la pila pero 560 será el que saldrá primero. 2.3 La instrucción POP Es lo opuesto de PUSH con lo que queda claro que sirve para recuperar los valores puestos en la pila. Ejemplo (continuación del anterior): POP CX POP BX POP AX Estas instrucciones pondrán la primera instrucción de arriba de la pila en CX, es decir 560 y luego BX volverá a BX y AX a AX. La pila es muy utilizada para encontrar los valores intactos de los registros y como que el número de registros es ilimitado, se utiliza la pila cuando ya no queda espacio. Sin embargo la pila es más lenta que los registros.

3- Los saltos condicionales y el CMP 2.1 Los saltos condicionales Entre los diferentes saltos tenemos los incondicionales (que saltan sin condición) como el JMP (Jump) y los condicionales que saltan únicamente si la condición es verificada. En este último grupo hay muchos individuos ;) Los valores de los indicadores son necesarios para la verificación de la condición. He aquí los principales saltos condicionales: Indicador (Flag) Valor Salto Significado CF

Page 6: Assembler

6

1 JB Below- Inferior JBE Below or Equal – Inferior o Igual JC Carry – Retención JNAE Not Above or Equal – No superior o igual 0 JA Above- Superior JAE Above or Equal- Superior o igual JNB Not Below –No inferior JNC Not Carry- No retención ZF 1 JE Equal- Igual JNA Not Above- No superior JZ Zero- Cero (salta en caso de igualdad) 0 JNBE Not Below or Equal- No superior o Igual JNE Not Equal- No igual JNZ Not Zero- No Cero (salta si diferente) PF 1 JP Parity – Par JPE Parity Even- Par 0 JNP Not Parity- Impar JPO Parity Odd- Impar OF 1 JO Overflow- Desbordamiento 0 JNO Not Overflow- No desbordamiento SF 1 JS Signed- Con signo 0 JNS Not Signed- Sin signo Otros: JG – JNLE Greater (superior aritméticamente) – Not Less or Equal (aritméticamente no inferior o igual) ZF=0 y SF=OF JGE – JNL Greater or Equal (aritméticamente superior o igual) – Not Less (No inferior aritméticamente) SF=OF JL – JNGE Less (aritméticamente inferior) – Not Greater or Equal (artiméticamente no superior o igual) SF (con signo) = OF JLE – JNG Less or Equal (aritméticamente inferior o igual) – Not Greater (no superior aritméticamente) ZF=1 o SF (con signo)=OF 3.2 La instrucción CMP Esta instrucción permite efectuar tests entre valores y modificar los flags según el

Page 7: Assembler

7

resultado. El funcionamiento del CMP es parecido al SUB (que veremos más adelante y que sirve para la sustracción). Se utiliza de esta manera: CMP AX, BX. Este comando permite verificar si estos valores son iguales ya que hará la operación AX-BX, si el resultado es igual a 0 entonces ZF=1 si no ZF=0. A menudo es seguido de estos saltos y su inverso (que agrega una “N” después de la “J”, por ejemplo JNE para JE…): JA: más grande que (números sin signo) JB: más pequeño que (número sin signo) JG: más grande que (números con signo) JL: más pequeño que (números con signo) JE o JZ: igual a (con y sin signo)

4- Las operaciones matemáticas 4.1 Adición y Sustracción: ADD y SUB Estas dos instrucciones necesitan 2 operandos: la fuente y la destinación. Lo que dará: Destinación=Fuente+Destinación. En ensamblador: ADD Destinación, Fuente. Ejemplo con AX=4 y BX=6 ADD AX, BX (Donde AX es la destinación y BX la fuente) Después de esta operación: AX= 4+6 = 10 y BX = 6 El funcionamiento de SUB es idéntico. Es imposible adicionar o sustraer un 16bits con un 8bits por ejemplo. ADD BX, AL será imposible! 4.2 Multiplicación: MUL / IMUL MUL es utilizada para los números sin signo e IMUL para los con signo (recuerda que: los números con signo pueden ser negativos lo que no es el caso de los números sin signo. Por ejemplo en 16 bits y sin signo, los números van de 0 a 65535 y en los con signo van de -32768 a 32767). En contraste con las operaciones precedentes, la operación necesita únicamente un operando: la fuente. La10 destinación o sea el nombre que deberá multiplicarse se encontrará siempre obligatoriamente en AX. La fuente es un registro. Ejemplo con AX=4 y BX=6 MUL BX Resultados: AX=4*6 = 24 y BX = 6 IMUL funciona del mismo modo, salvo que hay que utilizar la instrucción CWD (convert Word to doubleword), que permite extender el signo de AX en DX. Si se salta esto, los resultados pueden ser erróneos. 4.3 División: DIV / IDIV Al igual que MUL e IMUL, DIV sirve para los números sin signo y IDIV para los con

Page 8: Assembler

8

signo. Esta instrucción divide el valor de AX entre la fuente. Ejemplo con AX= 18 y BX = 5 IDIV BX Resultados: AX = 3 y DX = 3 (siendo DX el resto de la operación) 4.4 Otra división y multiplicación: SHR y SHL Estas instrucciones permiten dividir registros con SHR y multiplicarlos con SHL. Se necesitan dos operandos: el dividendo y el divisor para SHR y el multiplicando y multiplicador para SHL. Funcionan en potencia de 2. Por lo que si queremos dividir AX entre 4 pondremos: SHR AX, 2 (ya que 22= 4). Para dividir BX entre 16 pondremos: SHR BX, 4 (ya que 24= 16) Para SHL es igual: para multiplicar CX por 256 pondremos: SHL CX,8 (28=256). Para multiplicar o dividir números que no son potencias de 2 habrá que combinar SHR o SHL. Recuerda: x0 dará siempre 1 sea cual sea el valor de x! Ejemplo: queremos multiplicar 5 por 384. Vemos que 384 = 256+128, lo que nos va bien porque 256 y 128 son potencias de 2. · MOV AX, 5 >ponemos 5 en AX > AX=5 · MOV BX, AX >ponemos AX en BX > BX=AX · SHL AX, 8 >multiplicamos AX por 256 (28) > AX = AX*256 = 5*256 = 1280 · SHL BX, 7 >multiplicamos BX por 128 (27) > BX = BX*128 = 5*128 = 640 · ADD AX, BX >agregamos BX a AX > AX= AX+BX = 1280 + 640 = 1920 Verifiquen! 5*384 = 1920

Bueno, ustedes dirán: y porqué no utilizar un MUL simplemente? Pues porque SHL se ejecuta mucho más rápido pero claro que para números que tienen una descomposición demasiado larga es mejor utilizar un MUL. 4.5 Lo opuesto de un número: NEG La instrucción que yo creo que es la más simple es la NEG que sirve à transformar un número positivo en negativo e inversamente. Solo se necesita un operando: la destinación. Si AX=5, entonces un NEG AX pondrá AX=-5. O si BX=-2 entonces después de NEG BX, BX=2.

5- Los puntos decimales y los números negativos 5.1 Los puntos decimales El problema en ensamblador es que no podemos utilizar directamente los números con puntos decimales. Se utilizan números decimales fijos. Se trata de efectuar cálculos con valores bastante grandes que enseguida son re-divididos para encontrar un resultado dentro de un cierto intervalo. Por ejemplo: queremos multiplicar 20 por 0.25. Como no podemos poner 0.25 en un registro entonces le pondremos un número entero multiplicándolo por ejemplo por 256. 0.25*256=64. Este resultado lo multiplicamos por 20 y siendo el resultado 256 veces más grande, entonces lo dividiremos entre 256: · MOV AX, 64 >ponemos 0.25*256 en AX >AX=64 · MOV BX, 20 >ponemos 20 en BX >BX=20 · MUL BX >multiplicamos AX por BX >AX=AX*BX=64*20=1280 · SHR AX, 0 >dividimos AX por 256 (28) >AX=AX/256=1280/256=5 Y el resultado de 20*0.25 es efectivamente igual a 5. Pongan atención a no provocar desbordamiento, sobretodo con los números con signo o los grandes números. Utilizando SHR o SHL, mientras más grande sea el

Page 9: Assembler

9

operando más preciso será el resultado ya que habrán más decimales disponibles. 5.2 Los números negativos Otro problema es que en decimal debemos poner un “-“ antes del número si es negativo, pero en binario sólo podemos poner 0 ó 1. Por lo tanto para poder poner un número en negativo se utiliza el método del complemento de 2. He aquí en qué consiste: · Convertir el número en binario si no está ya hecho · Invertir los bits del número (invertir los 0 en 1 y los 1 en 0) · Agregar 1 al número obtenido Aquí un ejemplo con el número decimal 5 en formato 8 bits (octeto): · Lo convertimos en binario : 5(d) = 00000101 (b) · Invertimos: 00000101 à 11111010 (aquí el formato, 8 bits, es importante ya que en 4 bits por ejemplo da: 1010) · Agregamos 1 à 11111010 + 0000001= 11111011 -5 es igual a 11111011 en binario Para que el número sea negativo éste debe ser con signo. En 8 bits los sin signo van de 0 a 255 y los con singo van de -128 a 127. Cuando el número es con signo y en 8 bits, podemos saber si es negativo, viendo el octavo bit (partiendo de la derecha, claro). Si éste es igual a 1 entonces el número es negativo. Para los números de 4 bits es el cuarto que cuenta. Para transformar -5 en hexadecimal, descomponemos el número binario en medioocteto (11111011 en 1111 y 1011). 1111b= 15d = Fh y 1011b = 11d = Ah. Entonces -5d = FAh. (d= decimal, b= binario, h= hexadecimal, para aquellos que aún no hayan comprendido).

6- Las instrucciones lógicas Las operaciones de estas instrucciones se realizan bit a bit y los operandos o posicionamientos de memoria que utilizan son en 8 o 16 bits. Recuerda: para convertir de memoria un número binario en decimal: cada rango de un número binario es un múltiplo de 2. 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^1 128 64 32 16 8 4 2 1 Así por ejemplo 10110110 dará 128+32+16+4+2 = 182: 1 0 1 1 0 1 1 0 128 64 32 16 8 4 2 1 6.1 Y lógico: AND AND (Y) efectúa un Y LOGICO sobre dos operandos y el resultado se recuperará en el primer operando. El Y LOGICO da el resultado 1 únicamente cuando los 2 operandos son 1, si no pone 0. Operando 1 Operando 2 AND 0 0 0 0 1 0 1 0 0 1 1 1 Ejemplo con AX=15 y BX = 26: ADN AX, BX

Page 10: Assembler

10

Resultado: 0000 1111 (AX=15) AND 0001 1010 (BX=26) --------------------------------- 0000 1010 (AX=10) 6.2 O Lógico inclusivo: OR OR efectúa un O LOGICO INCLUSIVO sobre 2 operandos y el resultado se recuperará en el primer operando. El O LOGICO INCLUSIVO da el resultado 0 únicamente si ambos operando son 0, si no pone 1. Operando 1 Operando 2 OR 0 0 0 0 1 1 1 0 1 1 1 1 Ejemplo con AX=15 y BX = 26 OR AX, BX Resultado: 0000 1111 (AX=15) OR 0001 1010 (BX=26) ------------------------- 0001 1111 (AX= 31)

6.3 O Lógico exclusivo: XOR XOR efectúa un O LOGICO EXCLUSIVO sobre dos operandos y el resultado se recuperará en el primer operando. El O LOGICO EXCLUSIVO da el resultado 1 cuando los 2 operandos son diferentes, sino pone 0. Operando 1 Operando 2 XOR 0 0 0 0 1 1 1 0 1 1 1 0 Ejemplo con AX = 15 y BX = 26 XOR AX, BX Resultado: 0000 1111 (AX= 15) XOR 0001 1010 (BX = 26) -------------------------- 0001 0101 (AX=21) 6.4 No lógico: NOT NOT efectúa un NO LOGICO sobre un operando y el resultado se recuperará en el operando. El NO LOGICO invierte el valor de cada bit. Operando NOT 0 1 1 0 Ejemplo con AX=15 NOT AX Resultado: NOT 0000 1111 (AX=15)

Page 11: Assembler

11

------------------------- 1111 0000 (AX = -16 con signo y 240 sin signo)

6.5 TEST Esta instrucción testea el valor de uno o más bits efectuando un Y LOGICO sobre los operandos. El resultado no modifica los operandos pero sí los indicadores (flags). Ejemplo: TEST AX, 1 >efectúa un Y LOGICO sobre el primer bit de AX con 1, si es igual a 1, ZF pasará a 1 e inversamente (si 0 entonces ZF=0) Un TEST AX, AX (a menudo utilizado) permite verificar si AX es igual a 0 ó no.

7- La memoria y sus instrucciones 7.1 LEA Para poner por ejemplo el valor de l’offset de MESSAGE en SI basta con poner: MOV SI, Offset-Messsage. Pero no se puede proceder de este modo con los registros DS, FS, ES, GS ya que éstos no aceptan valores numéricos sino únicamente los valores de los registros. Razón por la cual tendremos que pasar por: MOV AX, Seg-Message luego MOV DS, AX. Existe otra instrucción que permite poner el Offset de un registro pero de forma más corta. Se trata de LEA. Por ejemplo: LEA SI, MESSAGE pondrá en SI el Offset de Message. La utilización de LEA en lugar de MOV hace que el código sea más claro y más compacto. 7.2 MOVSx Para desplazar bloques enteros de memorias hay que utilizar las instrucciones: MOVSB, MOVSW o MOVSD según el número de bits à desplazar. · MOVSB : (B) = Byte (octetos: 8 bits) (Cuidado!! Que en Inglés “byte”= un octeto y “bit”= un bit) · MOVSW: (W) = Word (palabra: 8 bits) · MOVSD: (D) = DWord (doble palabra : 32 bits) Si queremos desplazar 1000 octetos (bytes) utilizando el comando MOVSB éste tendrá que repetirse 1000 veces. Por lo que la instrucción REP es utilizada como loop (ciclo). Hay que poner antes el número de loops a efectuar en el registro de contador (CX): MOV CX, 1000 >número de loops a efectuar en el contador CX REP MOVSB >desplaza un octeto Para ir más rápidos podemos desplazarlos por palabra (Word): MOV CX, 500 >1000 bytes = 500 words REP MOVSW >desplaza un word O en doble palabra (DWord) MOV CX, 250 >1000 bytes = 500 words = 250 dwords REP MOVSD >desplaza una doble palabra A cada MOVSx, DI augmenta de 1, 2 ó 4 bytes. 7.4 STOSx Para guardar datos o ponerlos en un lugar de la memoria, utilizamos las instrucciones STOSB, STOSW, STOSD. Igual que los MOVSx, estas instrucciones sirven respectivamente para almacenar un

Page 12: Assembler

12

byte, un Word o un dword. En cambio utilizan AL, AX (EAX 32bits) como valor a almacenar. El valor AL, AX, EAX será almacenado en ES:DI. A cada STOSx, DI augmenta de 1, 2 ó 4 bytes. Ejemplo: MOV CX, 10 >número de repeticiones puestas en CX, aquí 10 MOV AX, 0 >valor a mover, aquí 0 REP STOSB >almacenar AX en ES:DI Así tendremos 10 bytes de 0 en ES:DI.

ANEXO: Lo que más utilizamos en el cracking ;) Antes que nada, felicitar a todos aquellos que se leyeron sistemáticamente las 15 páginas anteriores. Significa que están motivados y seguramente aprenderán mucho. A aquellos que se vinieron a leer directamente esta parte, solo decirles que es una ilusión creer que esta parte será suficiente para aprender a crackear. Se necesita muuuchísima lectura y práctica para ser capaz de crackear incluso el programa más sencillo que exista (aunque estos están ya casi extintos razón de más para invertir tiempo en la lectura ;). Lo que sigue supone que crackeamos haciendo uso de Olly Dbg .

A- De las instrucciones Ø CALL y RET Lo básico en el cracking. Si no comprendemos esto pues no podremos tracear un evento y como consecuencia no podremos crackear nada. La siguiente imagen (extraída de uno de mis tutoriales) muestras las CALL’s en blanco y los RET en azul claro: Tomemos por ejemplo la primera: CALL Notes. 00523728 Qué significa? Pues que cuando el programa ejecuta esa línea (004827BA) éste irá a ejecutar una subrutina que comienza en la línea 00523728 que es el valor del operando CALL Notes. Cada rutina o subrutina se termina a su vez en uno o más RET. El RET (o RETN) marca el punto de salida de la subrutina y al mismo tiempo el retorno (RETURN) a la siguiente instrucción del CALL que “llamó” a dicha subrutina. En nuestro ejemplo, cuando se llegue al RENT de la subrutina que comienza en 00523728 éste nos traerá de vuelta a la línea 004827BF. Más claro no lo puedo explicar. Ø NOP (No Operation) Su uso se conoce en el cracking como “nopear” y como su nombre lo indica consiste en “no hacer nada”. Es muy utilizado sobre todo cuando nos iniciamos en el cracking aunque en determinadas circunstancias puede ser la única alternativa. En hexadecimal NOP = 90. En el precedente ejemplo, si quisiéramos evitar que el programa ejecute la CALL Notes. 00523728 basta con reemplazar su código hexadecimal E8690F0A00 por 9090909090. Ø MOV Mueve el segundo operando al primero. Ejemplos: MOV EAX, ECX >pondrá el valor de ECX en el registro EAX MOV AL, 1 >pondrá 1 en AL (los 2 últimos números de EAX) Ø XOR La forma más utilizada es cuando se necesita poner 0 en alguno de los registros. Para ello basta con que los dos operandos sean el mismo registro. Ejemplo: EAX = 1

Page 13: Assembler

13

XOR EAX, EAX >resultado EAX= 0 ya que el valor de los dos operandos es el mismo. Ø INC y DEC INC = incrementar de 1 el operando; DEC= decrementar de 1 el operando. Ejemplo: EAX=00000000 INC EAX >EAX= 00000001 DEC EAX >EAX= FFFFFFFF (-1) B- De los registros Aunque todos pueden ser útiles, el más utilizado es EAX. Y la razón es simple: el “resultado” de un CALL se almacena en general en EAX y cuando se estudia por ejemplo el sistema de activación de un programa, la mayor parte de casos puede representarse con el siguiente esquema: CALL xy MOV x, y CMP EAX, xy ó TEST AL, xy ó TEST/CMP xy, EAX/AL JE xy ó JNZ xy …… CALL xy -> ventana de registro/ mensaje OK ó no OK, por ejemplo. En este esquema extremamente simplificado (pero que a menudo encontramos en este noble arte ;) vemos que la condición del salto está determinado en parte por el valor de EAX o AL que a su vez está dado por la CALL que precede.

Nota: Si EAX = 12345678 Si EBX= 12345678 AL = 78 BL = 78 De esto recordemos que: EAX : (32bits) AX: (16bits) AL: (8bits) Y así consecutivamente en todos los registros (ECX > CL; EDX >DL) C- De los saltos, condiciones y Flags Los saltos más comúnmente utilizados son JE, JNZ y a veces JG y otros… Para modificar virtualmente estos saltos, por ejemplo si queremos ver cómo reacciona el programa si se modifica el salto, usamos el Flag Z ya que cambiando el valor de éste (entre 0 y 1) podemos variar el comportamiento del programa. Muy útil para testear rápidamente nuestras hipótesis sobre el funcionamiento de algún evento en el programa. Las condiciones que más se asocian a estos saltos condicionales son CMP y TEST descritas más arriba. Este es el fin de este curso. Uuf! Me pasé casi 8 horas escribiéndolo por lo que espero que les sea de ayuda y que enriquezca el repertorio de material que estoy seguro, los más motivados, ya tienen. Quiero agradecer a mis amigos de siempre: POP, JONNY, JJBB y D!OxDe2k por su colaboración en el Blog y por su apoyo así como también a todos aquellos que nos apoyan y que nos visitan en el blog. Un saludo igualmente a todos nuestros compañeros (aunque lamentablemente no amigos cercanos) de diferentes Team’s, grupos o independientes que con su labor mantienen viva la escena del cracking y de quienes seguramente mucho he aprendido.

Page 14: Assembler

14

Este curso ha sido de teoría pura pero no se desmotiven si hay cosas que quedaron en la sombra ya que pueden contactarme desde el blog o simplemente dejar un comentario en el minichat y probablemente otras personas podrán ayudar. De más está decir que cualquier observación o sugerencia a propósito de lo que hacemos, es bienvenida siempre y cuando sea constructiva ;) Por último, invitarlos a que ojeen nuestros tutoriales que yo espero con esta contribución, serán más fáciles de seguir y de leer. JUNLA MPT34M www.mpt34m.net