Sunteți pe pagina 1din 75

APRENDIENDO LO BASICO 1 CURSO BREVE DE LENGhttp://eidanyoshttp://eidanyosonhttp://eidanyoson.8k.com/xclave.htm.8k.com/xclave .htmon.8k.com/xclave.

htmUAJE ASSEMBLY E INGENIERIA INVERSA BASICA


Conceptos_bsicos (4 pginas)
1. Operacin binaria 2. Modelo X86 3. Instrucciones X86 4. Debug Mod 1: Interrupciones Mod 2: Manejo de strings Mod 3: Paso de parmetros (2 pginas) Glosario de la ECCE Assembly, leccin_1 Assembli, leccin_2 Assembly, leccin_3 Assembly, leccin_4 Assembly, leccin_5 Assembly, leccin_6 Assembly, leccin_7 eidan yoson

eidan yoson eidan yoson eidan yoson eidan yoson greythorne+ greythorne+ greythorne+ greythorne+ greythorne+ greythorne+ greythorne+

TOMADO DE http://eidanyoson.8k.com/xclave.htm

CAPITULO 1
Modulo 1
Operacin binaria

Cuando termine de leer esta pgina deber conocer:


y y Sistemas de numeracin Operaciones binarias

Sistema de numeracin
Estamos habituados al sistema de numeracin decimal y nos parece lgico usarlo en todo momento. Pero hay ocasiones en donde no es el ms apropiado. Uno de esos mundos en los que existen sistemas ms descriptivos de los fenmenos que el decimal es el de los procesadores. Por su naturaleza digital, los procesadores son mquinas esencialmente binarias. Utilizan el sistema de numeracin llamado binario, en el que slo se disponen dos signos: 0 y 1. Contando correlativamente de manera binaria, diramos: 0, 1, 10, 11, 100, 101, 110, 111, ... complicado? Pero es muy fcil!. Tanto el sistema binario, como el decimal y el hexadecimal, son sistemas en los que la posicin de cada dgito representa informacin de mucha importancia. Veamos un ejemplo de cmo se descompone posicionalmente un numero decimal: El nmero 7935 = 1000 * 7 + 100 * 9 + 10 * 3 + 1 * 5 Elemental no?. Sin embargo, la numeracin romana no goza de tan buenas propiedades y por eso hace ya tiempo se lo reemplaz por el sistema decimal (a excepcin de la numeracin de las pginas del prefacio en los libros y del numero de serie de las pelculas de Rocky :=) Como hay diez smbolos (del 0 al 9), una decena representa 10 unidades, una centena representa 10 decenas, etc. Diez unidades de una posicin, valen una unidad en la posicin contigua a la izquierda. En el sistema binario, con dos smbolos solamente, cada posicin a la izquierda vale el doble de la que le sigue a la derecha. O lo que es lo mismo decir, la relacin entre las sucesivas posiciones se da segn la sucesin
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 .....

la que a su vez puede expresarse como potencias crecientes de 2:


20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 210 , 211 , 212 , 213 , 214 , 215 , 216 .....

Para el sistema de numeracin binaria, valen las dos reglas prcticas siguientes:
y y

Un nmero de n bits puede representar a un decimal de un valor de hasta 2n - 1 El multiplicador del bit de posicin n vale 2n

Ejemplos: un nmero de 8 bits cuenta desde 0 hasta 255. El multiplicador del bit 7 es 128. Notar que siempre se comienza a contar desde cero. En un nmero binario, al igual que en un decimal, el bit menos significativo (correspondiente al multiplicador 20, o sea 1) es el que se escribe ms a la derecha:
bit# mult 15 14 13 12 4096 11 2078 10 1024 9 512 8 256 7 128 6 64 5 32 4 16 3 8 2 4 1 2 0 1

32768 16384 8192

Veamos como ejemplo prctico un nmero de 7 bits cualquiera como 1001101 (notar que los bits se ordenan 6...0) 1001101 = 64 * 1 + 32 * 0 + 16 * 0 + 8 * 1 + 4 * 1 + 2 * 0 + 1 * 1 Esto nos proporciona una forma de traducir (cambiar de base) un nmero binario a decimal. Basta sumar aquellos multiplicadores cuyos bits estn en 1 e ignorar aquellos cuyo bit es 0. En nuestro anterior ejemplo es: 1001101 = 64 + 8 + 4 + 1 = 77 decimal Para el traspaso de decimal a binario, hay que dividir siempre por 2 y contar slo los restos, de atrs hacia adelante. Observese que el resto no es otra cosa que el multiplicador de las potencias de dos en las anteriores igualdades, las que pueden ser definidas como la sumatoria de los productos de los restos por sus potencias de dos respectivas Por ejemplo, para el 77 decimal obtenemos los restos:
opreracin 77 / 2 = 38 38 / 2 = 19 19 / 2 = 9 9/2=4 4/2=2 2/2=1 1/2=0 resto r=1 r=0 r=1 r=1 r=0 r=0 r=1 pot.de 2 1 2 4 8 16 32 64

Ordenando los restos segn las potencias decrecientes de 2, obtenemos nuevamente 1001101. Los nmeros binarios son los que efectivamente fluyen dentro del procesador en una PC, se guardan en memoria o disco, o se transmiten (modulados) por modem. Pero un humano no puede manipular con facilidad nmeros como: 1101 0011 0101 0110 1010 0101 1100 0011 que es de 32 bits (hay 32 smbolos en el nmero, desde el bit 31 a la izquierda hasta el bit 0, a la derecha) y se ha ordenado ex-profeso en grupos de a cuatro por cuestiones de comodidad que sern evidentes algo ms adelante. El procesador 80386 hace ya ms de una dcada manipulaba sin problemas nmeros de 32 bits. Un humano necesita manejarlo de otra manera y por eso se invent el sistema hexadecimal, con 16 smbolos, ya

que si uno agrupa cuatro bits obtiene 16 combinaciones posibles (24 = 16). Esto tiene una razn. Nuestro sistema decimal no se corresponde en la cantidad de dgitos con el binario en cambio, el hexadecimal si, porque cada cuatro bits representan un dgito hexadecimal exacto. De tal manera, el anterior nmero de 32 bits se traduce al hexadecimal como uno de 8 dgitos (32 bits agrupados de a 4). Para la conversin podemos usar la tabla binario-decima-hexa qe est algo ms adelante. En un sistema hexadecimal, necesitamos 16 smbolos. Ya que somos muy buenos manejando nmeros decimales, adoptamos esos diez smbolos (0, 1, 2, 3, 4, 5, 6, 7, 8 y 9) para empezar, pero hay que agregar otros seis. Mmh ! por qu no A, B, C, D, E y F ? De esta forma, si me toca contar jugando a las escondidas y quiero hacerlo en hexadecimal (de puro tonto, porque voy a contar un 60% ms:=), tengo que decir: 0, 1,.......8, 9, A, B, C, D, E, F, 10, 11.........18, 19, 1A, 1B, 1C, 1D, 1E, 1F, 20, 21........29, 2A,.........2E, 2F, 30, 31 ... El anterior e impronunciable numero binario de 32 bits pasa a ser: 0xD356A5C3 hexa, es igual a 3.545.671.107 en decimal

Por cierto que no hice la conversin de binario a decimal a mano con la frmula anterior, sino que us la calculadora de Windows en modo cientfico, que permite operar o convertir nmeros entre bases binaria, octal, decimal y hexadecimal. Otra base de numeracin posible con traduccin de dgitos exacta al binario es la octal que tiene slo 8 smbolos (del 0 al 7), con lo cual cada dgito representa a 3 dgitos binarios, pero est casi en desuso. Note el lector el "0x" del comienzo, para significar que lo que sigue es un nmero hexadecimal. Otro estilo es poner una "h" final, con la precaucin de colocar un cero adelante si el nmero comienza con A, B, C, D, E o F. Para aqul nmero de 32 bit utilizado como ejemplo, adoptamos como notacin : 0D356A5C3h Cada trozo de informacin recibe un nombre propio segn la cantidad de bits que posea:
y y y y y

un bit es la unidad de informacin binaria y con l se puede contar desde 0 hasta 1 un nibble son cuatro bits y se puede contar desde 0 hasta 15 (0xF en hexa) con un byte (8 bits) puedo contar desde 0 hasta 255 0xFF hexa una word tiene 16 bits y permite contar desde 0 hasta 65535 0xFFFF una double-word (32 bits) permite contar desde 0 hasta 4.294.967.295 0xFFFFFFFF

Cuando usted escuche hablar de direcciones de 32 bits, sepa que hay un espacio de almacenamiento de 4.294 ... millones de bytes o 4 Gigabytes (o de colores, si estamos hablando de color de 32 bits). Para finalizar con este tema, aqui hay una tabla que convierte el primer nibble (los primeros 4 bits) a decimal y a hexa. Usted con ella debe poder convertir cualquier numero binario en hexa y viceversa:
binario 0000 0001 0010 0011 0100 decimal 0 1 2 3 4 hexa 0 1 2 3 4 binario 1000 1001 1010 1011 1100 decimal 8 9 10 11 12 hexa 8 9 A B C

0101 0110 0111

5 6 7

5 6 7

1101 1110 1111

13 14 15

D E F

Le extra el resultado de la suma? Sin embargo es lo que hacemos en la suma decimal 5+5=10 (nos llevamos "1" para la operacin del dgito siguiente). Este llevarse "1" es vastamente usado entre los procesadores digitales y tiene un nombre especial: carry (lo ver abreviado como CY, C o CF-por carry flag), lo que en castellano se traduce como "acarreo" (que suena muy mal, asi que le seguiremos llamando carry). Estas operaciones tambin se llaman "booleanas" ya que se basan en el lgebra de Boole (invito al lector a rememorar cuando en la escuela secundaria se preguntaba, igual que yo, si el lgebra de Boole le servira alguna vez para algo).

Cuando termine de leer esta pgina deber conocer:


y y y y

Modelo de procesador X86 Modos de direccionamiento Modelo de memoria de una PC Segmentos

Modelo de procesador X86


Los ancestros del bienamado Pentium III no fueron tan poderoso como l (por las dudas alguien lea esto all por el 2005 y le arranque una sonrisa el poder del Pentium III, debo decir que hoy, mediados de 1999 es el procesador ms potente disponible para PCs y acaba de salir a la venta). Todo comenz hace dos dcadas con un oscuro (aunque revolucionario para la poca) 8086, con registros de 16 bits, que para colmo debi por cuestiones monetarias sufrir un "downsizing" hasta el ridculo 8088 -motor de las renombradas IBM PC, con las mismas instrucciones pero con un bus de 8 bits. Cuando hablamos de registros de 16 bits queremos decir que el procesador tiene posiciones de almacenamiento especiales llamadas registros cuyo ancho de palabra es de 16 bits. Y cuando nos referimos a bus, trmino de amplia aplicacin queremos decir bus de procesador (no el de la placa madre, ni el de I/O, ni el de los canales IDE). El procesador tiene dos buses pro uno saca direcciones y por el otro entra instrucciones o entra y saca datos. En el 8088 el bus de datos era de 8 bits, aunque internamente sus registros manipulaban palabras de 16 bits. Unos aos despus apareci el legendario 80386 DX, con arquitectura y bus de 32 bits y su hermano menor, ese engendro con bus de 16 bits que fue el 386SX tan promocionado por las revistas de vulgarizacin tipo PCmierdazine, quin sabe con qu oscuro y comercial designio. Varios aos ms adelante quisieron darle auge a otro castrado, el no menos nombrado "celeron", un Pentium II sin cach L2, que es precisamente aquello que hace muy veloz al original. Todos estos procesadores (y algunos ms como el 486) comparten el mismo juego de instrucciones bsico del 8086, al que cada generacin le introdujo mejoras, alguna instruccin ms, ms registros, multi-thread, prediccin de saltos y hasta un fabuloso nmero de serie nico en el Pentium III con el que Intel no quiere perdernos pisada y al que puede accederse por instrucciones comunes que permitiran a cualquier servidor Internet saber qu nmero de procesador tiene el hacker que se acaba de conectar y con lo cual se acabara toda diversin en la red (y toda privacidad!!!!!!!). Pero tal vez el salto tecnolgico ms revolucionario lo inici el 80386 al permitir un modo de funcionamiento con cualidades especiales al que se lo llam "modo protegido". Debido a las caractersticas de este modo, se podan generar "mquinas virtuales", cada una con su propio espacio de memoria virtual, al que se acceden a travs de vectores de 32 bits ubicados en dos tablas conocidas como GDT y LDT. Este mecanismo permite que a partir del 386 los procesadores Intel direccionen una memoria virtual de 64 Terabytes (o sea 16.384 espacios de direccionamiento reales de 4 GB).

Programas

Todo programa fuente assembly, tienen la forma de una lista de instrucciones, rtulos (labels) y decisiones parecida al siguiente pseudocdigo:
ORG 100h label1: instruccin 1 label2: instruccin 2 si (comparacin) verdadera ir a label 2 instruccin 3 end ;esta es otra instruccin ms ;comentario ;Directiva de Ensamblador

En lenguaje assembly, cada instruccin se compone de un nombre mnemnico que determina el tipo de operacin (por ejemplo MOV, PUSH, etc) y un campo de datos que especifica los operandos sobre los que dicha operacin se debe llevar a cabo. Una lnea de programa assembly tiene a su vez tres campos: el de rtulos (labels), el de la instruccin y un campo de comentarios que siempre comienza con ";" (punto y coma). El compilador assembly -llamado Assembler o Ensamblador- traduce las instrucciones en cdigos de operacin del procesador segn comandos especiales que se llaman Directivas de Ensamblador, para producir un mdulo de programa ejecutable. En los programas ejecutables estos cdigos de operacin son valores binarios de uno o ms bytes por cada mnemnico. De haber un dato, tambin ser compilado como binario, que es en definitiva la nica base de numeracin que pueden interpretar los procesadores. Sin embargo, cuando un programador escribe un programa mediante un editor, puede indicarle al compilador si un nmero es binario, decimal o hexa. Al correr el programa, el procesador va ejecutando las instrucciones almacenadas en memoria e incrementando el registro IP secuencialmente. Tanto CS (Code Segment) como IP (Instruction Pointer) son los registros del procesador que direccionan el cdigo ejecutable . La direccin de la prxima instruccin a ejecutarse est dada por el vector CS:IP Cuando se encuentra una instruccin de bifurcacin, si se verifica la condicin expresada por el tipo de instruccin, el puntero de instrucciones (IP) cambia con un salto en lugar de incrementarse. En el ejemplo de pseudo-programa anterior, en la instruccin de comparacin el IP tomar el valor de la direccin "label 2" toda vez que la comparacin haya resultado verdadera o incrementar su valor a la instruccin siguiente (instruccin 3) si la comparacin resulta falsa. Hay que tener presente que cada una de las instrucciones anteriores est almacenada en uno o varios bytes en la memoria. El valor de label2 es en el caso anterior la direccin en donde esta almacenado el primer byte de la instruccin 2.

Abramos las ventanas


Inicie usted una sesin DOS, teclee la orden DEBUG y cuando le aparezca el anodino prompt "-", pulse "r" y enter. Los datos que usted ve desplegarse son los registros bsicos y el contenido de los mismos, del procesador de su PC: (Notar que Debug supone que la notacin es hexadecimal y que los registros son de 16 bits aunque su PC sea Pentium)
AX=0000 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1332 ES=1332 SS=1332 CS=1332 IP=0100 NV UP EI PL NZ NA PO NC

1332:0100 C3 RET .

Esto significa que su Pentium con corazn de 8086 tiene al menos:


o o o o o

cuatro registros generales: AX, BX, CX y DX cuatro registros ndices: SP, BP, SI y DI cuatro registros de segmento: DS, ES, SS y CS un registro que apunta a la prxima instruccin a ejecutar: IP un registro de banderas de uso general: F (banderas V, D, I, P, Z, A, S y C)

Todos los registros mencionados son de 16 bits y usted se preguntar no es que a partir del 80386 los registros son de 32 bits?. Y est en lo cierto, los nuevos registros se llaman EAX, EBX, etc... pero todo a su tiempo. Recuerde que estamos viendo por el momento slo lo ms bsico y esto nos remite al modelo del 8086. En este procesador, a su vez los registros AX, BX, CX y DX pueden dividirse en dos registros de 8 bits (por ejemplo el AX en AH (bits 8 a 15) y AL (bits 0 a 7). Cada registro tiene sus funciones especficas (aunque hay muchas que son compartidas):
y y y y y y y y y y y y

AX: Acumulador, principalmente usado para operaciones aritmticas BX: Base. Se usa para indicar un desplazamiento (offset) sobre una posicin de memoria CX: Contador. Se usa para lazos y operaciones repetitivas DX: Dato. De uso general CS: Segmento de cdigo. Indica el segmento donde residen las instrucciones SS: Segmento de Stack. Indica el segmento que utiliza el Stack DS y ES: Segmentos Data y Extra, segmentos donde residen los datos SP: Puntero de Stack. Indica el offset actual del Stack BP: Puntero de base, para operaciones de indexacin SI: Indice de origen. Offset en segmento de datos de origen DI: Indice de destino: Offset en segmento de datos de destino F: Flags (hay nueve banderas importantes entre las 16)

Las flags (banderas) a tener en cuenta son:


y y y y y y y y y

C: carry - indica si la operacin anterior gener un carry Z: zero - indica si en la operacin anterior se gener una igualdad S: sign - indica si en la operacin anterior el resultado fue negativo AC: auxiliar carry - indica si hay que hacer un ajuste decimal en AX P: parity - indica si la paridad del ltimo resultado fue par V: overflow (tambin simbolizada O)- indica desbordamiento aritmtico en AX D: direction - indica si los indices SI o DI se incrementan (D=0) o decrementan (D=1) I: interrupt enable - indica si se permiten las interrupciones (I=1) o no (I=0) T: trap - controla la operacin paso a paso del procesador

Asi como la direccin de la prxima instruccin a ejecutarse est apuntada por la pareja CS:IP, hay un lugar de memoria especial apuntado por SS:SP llamado STACK y utilizado para guardar datos transitorios, parmetros que se pasan a las funciones y direcciones de retorno de subrutinas o interrupciones. Se llama stack porque opera como una pila de objetos, en donde el ltimo en ponerse es el primero en sacarse, mediante instrucciones especialmente diseadas para eso que se llaman PUSH y POP. Hay mtodos para consultar o escribir otros valores que no son los apuntados pos SS:SP (lo que equivale a sacar un objeto de la pila sin que se desmorone). El puntero SP est dando el offset de la ltima posicin de memoria escrita en la zona de stack y como se va llenando desde posiciones altas hacia las ms bajas, la prxima posicin libre es la SS:SP-1.

Por ejemplo, supongamos que SP contiene el valor 0FFE4h (ms adelante se ver qu papel juegan los registros de segmento como el SS, en la determinacin de la direccin de memoria real) y que AX contiene el valor 2233h. La instruccin PUSH AX pondr el valor 22 h (contenido en AH) en la posicin 0FFE3 h (0FFE4 - 1) y el valor 33 h almacenado en AL en la posicin de memoria 0FFE2 h y deja SP apuntando al ltimo byte ocupado, vale decir, que SP contendr el valor 0FFE2h.. La instruccin POP AX realiza la operacin inversa. No es mi intencin tratar de suplir un buen manual Intel (que puede bajarse gratis de internet del sitio www.intel.com) en el que se describe qu es cada registro y cules son las instucciones en las que est involucrado. Un buen sitio en castellano para consultar las instrucciones es http://udgftp.cencar.udg.mx/tutoriales/TutorialEnsamblador/ensam.html de la Universidad de Guadalajara, Mxico, en donde adems hay un tutorial de Assembly elemental con la fallida denominacin de Assembler. Las operaciones del procesador se van ejecutando de manera secuencial tal como estn almacenadas las instrucciones en la memoria. Existen instrucciones (saltos) que permiten cambiar la secuencia de ejecucin en forma absoluta o condicionada al resultado de alguna operacin anterior, tal como se dijo de la instruccin de comparacin en el ejemplo de pseudo-cdigo antes visto La instruccin ms elemental es MOV, que permite copiar un dato de un origen a un destino. OPERANDOS Las instrucciones pueden tener ninguno, uno, dos o tres operandos. A su vez, los operandos pueden ser inmediatos, registros, memoria o puertos. Un operando inmediato es un dato que viene en el cdigo del programa, por ejemplo, para cargar el registro AX con el nmero 20C5h se usa la instruccin:
MOV AX,20C5h MOV BX,[0400h] MOV DX,[BX] ;20C5h es un operando "inmediato" ;Otras instrucciones MOV pueden ser: ;0400h es una posicion de memoria ;[BX] tambin es una posicin de memoria

En el listado anterior, todo lo que hay despus del punto y coma ";" son comentarios extremadamente necesarios en programacin Assembly. No es el compilador quien los debe interpretar sino el propio programador o quien en el futuro deba modificar el programa. El nmero entre corchetes indica que el 0400h debe interpretarse como una DIRECCION de memoria (los corchetes deben leerse como "el contenido de", o sea : en esa operacin cargamos el registro BX con el contenido de la posicin de memoria 0400hexa del actual segmento de datos) Este tipo de referencia a memoria se llama Directo. En cambio, si expresamos [BX], nos estamos refiriendo a la posicin de memoria cuyo offset en el segmento actual de datos es el nmero contenido en el registro BX; este tipo de referencia a las posiciones de memoria se denomina Indirecto. Por ejemplo, supongamos para el cdigo anterior que en la direccin [0400] hay una word cuyo valor es 1234 h, y en la direccin de memoria [1234] hay una word cuyo valor es 56CCh, luego de ejecutarse esas instrucciones el registro BX contiene el valor 1234h y el registro DX contiene el valor 56CCh. En cambio el registro AX es cargado con el nmero 20C5h y a este direccionamiento se lo llama Inmediato. Los operandos pueden ser de 8, 16 o 32 bits, segn se desprenda del contexto de la operacin o del otro operando (por ejemplo, en el anterior MOV BX,[0400h], dado que BX es de 16 bits, lo que se va a mover es un word. Se deben inclur prefijos para especificar la longitud del dato cuando se de lugar a ambigedad como por ejemplo en la instruccin INC, en donde si el destino es una posicin de memoria, hay que especificar si es byte o word de la siguiente manera:
INC BYTE PTR [0406] ;incrementar el byte de offset 406h del segmento de datos

Modos de Direccionamiento
El modo de direccionamiento indica la forma en que el procesador calcula da direccin donde ir a buscar el dato origen o grabar el resultado en el destino, tal como se dej entrever en el punto anterior. Existen ocho modos de direccionamiento en los procesadores X86
y y y y y y y y

Implicito: la misma operacin lo indica (p.ej. PUSHA, siempre indica como destino el Stack) Registro: la instruccin menciona el registro (p. ej MOV AL,CH) Inmediato: la instruccin proporciona el dato (p. ej. MOV DL,5Fh) Directo: la instruccin da la direccin de memoria (p. ej. MOV BX,[0400h]) Registro-Indirecto: la direccin es el contenido de un registro (p.ej. MOV AX,[BX]) Relativo a base: direccin = base + constante (p.ej. MOV CX,[BX+6]) Directo Indexado: direccin = directo + ndice (p.ej. MOV DH,[0400h+SI]) Indexado a base: direccin = directo + base + ndice (p.ej. MOV AL,[0400h+BX+SI])

Cada registro de uso general o ndice tiene su propio registro de segmento asociado, segn la tabla siguiente:
AX, BX, CX, SI, DI BP, SP DI (instrucciones de strings) IP DS SS ES CS

En instrucciones de strings se opera entre un operador fuente (DS:SI) y otro destino (ES:DI). Aunque en estas instrucciones se lo vincula al segmento contenido en ES, en toda otra instruccin, el registro DI est asociado con el registro de segmento DS. A pesar de esto, puede cambiarse esta asociacin default con prefijos de segmento. Por ejemplo, si queremos que el AX se cargue con el contenido de la direccin de memoria 3C8, pero del segmento apuntado por ES, tenemos que usar:
MOV AX,ES:[3C8] ;cargar AX con el contenido de la direccin ES*10h+3C8h

A continuacin veremos como calcular una direccin segmentada del tipo SEG:OFF, en donde SEG es uno de los cuatro registros de segmento (DS, ES, SS o CS) y OFF es un registro de uso general o puntero.

Modelo de Memoria de una PC


La capacidad de direccionamiento de un procesador est dada por la cantidad de lneas del bus de direcciones (o sea el ancho en bits, de la palabra que el procesador es capaz de poner en el bus de direcciones de la computadora). En un procesador tpico de PC, tenemos 32 bits o sea 4 gigabytes (2 elevado a la potencia 32) de posiciones de memoria distinguibles. Esto constituye el espacio de direccionamiento real, pero no significa que nuestra PC tiene instalada esa cantidad de RAM, sino que en caso de estar fsicamente instalada, el procesador es capaz de direccionarla. Todo segmento de programa que se est ejecutando debe residir en memoria real (no slo el segmento de cdigo sino tambin el de datos). Como Windows es un sistema multitarea, si alguna aplicacin pasa a segundo plano, es posible que en caso de escasez de memoria real, el sistema operativo decida guardar en memoria virtual parte o toda la memoria real que la aplicacin ocupa, y la almacena en el archivo de intercambio (por lo general este archivo tiene varias decenas de megabytes y es de tipo oculto). Cuando la aplicacin vuelve a primer plano, el procesador

al ver que no estn en memoria real las recupera del archivo de intercambio. Incluso si la aplicacin es tan grande que excede la memoria real instalada, habr partes de ella en memoria fsica y otras partes en memoria virtual. El modelo de memoria utilizado en Win32 se basa en dos tablas de vectores, GDT y LDT apuntadas por registros especficos del procesador. Se llama "modelo de memoria plana" en oposicin con el ms antiguo llamado "segmentado" (propio del DOS y Win16). La memoria en lugar de dividirse en segmentos estancos, se divide en pginas contiguas. El procesador tiene la posibilidad de detectar si una pgina no est presente en memoria real y a partir de ah hay una serie de procedimientos para recuperarla desde la memoria virtual. Los mecanismos de gestin de memoria estn integrados en el kernel de Windows32 y su explicacin cae fuera de los alcances previstos para este escrito. Segmentacin Si observamos con atencin la pantalla del DEBUG, notaremos los cuatro registros de segmento denominados DS, ES, SS y CS. Tal como se ha dicho cada registro de segmento tiene la misin especfica de direccionar segmentos de datos, stack y cdigo. Como cuando Intel dio a luz este esquema de direccionamiento los registros de los procesadores eran de 16 bits y un MB de memoria era una cantidad fabulosa reservada slo para los computadores de laboratorio, se decidi que la forma en que se direccionara la memoria sera combinando dos segmentos como sigue: DIRECCION EFECTIVA = 10h * SEGMENTO + OFFSET tanto "segmento" como "offset" son registros que contienen un vector de 16 bits, y por lo tanto pueden elegir entre 64 k direcciones distintas. En pocas palabras, elegido el segmento, el procesador poda direccionar dentro del segmento 64 k posiciones de memoria distintas. Ejemplo CS= 3701h IP= 0100h 10h*CS = 37010 h + IP = 0100 h D.Eff. = 37110 h La notacin usada para expresar una direccin efectiva (o direccin absoluta) es SEG:OFFS; por ejemplo la prxima instruccin a ejecutar est en la direccin CS:IP. De lo anterior obtenemos las siguientes conclusiones:
y y y

y y

Existen 64 k segmentos posibles (los registros de segmento son de 16 bits) Con esta notacin se pueden expresar direcciones entre 00000 y 10FFEFh, en decimal 1.114.095 (no hasta FFFFFh o 1.048.575 = 1 MB como parecera lgico) La alineacin es cada 10h bits (la direccin efectiva de comienzo de segmento termina en 0h). 10h bytes se llaman pargrafos. Es comn decir que las direcciones efectivas de comienzo de segmento se alinean en pargrafos (lo cual es obvio, desde que en el comienzo de segmento el offset es 0) Una misma direccin efectiva puede expresarse de muchas maneras usando combinaciones entre segmento y offset (37110 h = 3701:0100 = 3600:0111, etc) Tanto segmento como offset son dos cantidades sin signo (no puede haber un offset negativo)

Cuando termine de leer esta pgina deber conocer: Instrucciones bsicas del X86

Instrucciones bsicas 8086


Este listado no pretende ser un substituto del manual Intel de instrucciones del 8086 -del que fervientemente recomiendo una minuciosa lectura una vez que haya comprendido bien esto- sino la ms breve descripcin posible para poder avanzar un poco ms en los aspectos ms bsicos que se precisan para comprender el tutorial de lenguaje Assembly de +gthorne. Esta es una lista completa de instrucciones 8086 a las que slo le faltan las instrucciones ESC, LOCK y WAIT, que no son tiles a nuestros fines inmediatos. En la siguiente tabla se muestran encolumnados los Mnemnicos (como MOV), los operandos (como fuente, destino) y la descripcin de la operacin. Los operandos son combinaciones entre tipos (registro, memoria e inmediato) con los direccionamientos admitidos en cada instruccin. Las instrucciones IN y OUT admiten un cuarto tipo de operando: puertos de I/O, con direccionamiento registro o inmediato. Instrucciones de movimientos de datos
MOV XCHG XLAT LAHF SAHF LDS LES LEA PUSH POP PUSHF POPF PUSHA POPA IN OUT origen destino destino,fuente destino,fuente destino,fuente fuente destino destino,fuente destino,fuente tabla_fuente ;la nica instruccin que utiliza todos los tipos de direccionamiento ;Intercambia los contenidos de destino y fuente ;carga el registro AL con el byte direccionado por (BX+AL) ;carga las flags S, Z, A, P y C en AH ;guarda AH en el registro de flags ;transfiere un puntero de 32 bits al registro DS y al registro destino ;transfiere un puntero de 32 bits al registro ES y al registro destino ;transfiere el offset de fuente (una direccin) a destino (un registro) ;guarda fuente en el stack (en la direccin SS:SP) ;recupera del stack (direccin SS:SP-1) y guarda en registro destino ;almacena el registro de flags en/desde el stack ;recupera el registro de flags en/desde el stack ; almacena los reg DI,SI,BP,SP,BX,DX,CX,AX en/desde el stack ;recupera los reg DI,SI,BP,SP,BX,DX,CX,AX en/desde el stack ;carga desde un puerto origen un byte o word en AL o AX ;escribe Al o AX en el puerto destino (direccionam. inmediato o DX)

Las operaciones aritmticas


ADD ADC SUB SUB MUL destino,fuente destino,fuente destino,fuente destino,fuente fuente ;suma fuente + destino y guarda el resultado en destino ;suma fuente + destino + Carry y guarda el resultado en destino ;resta destino - fuente y guarda el resultado en destino ;resta destino - fuente - Carry y guarda el resultado en destino ;multiplica AL o AX * fuente y guarda el resultado en DX:AX

IMUL DIV IDIV AND OR XOR NOT NEG INC DEC DAA / DAS AAA/AAD/ AAM/AAS

fuente fuente fuente destino,fuente destino,fuente destino,fuente destino destino destino destino

;igual que la anterior pero con numeros enteros con signo ;divide DX:AX / fuente y guarda cociente en AX y resto en DX ;igual que la anterior pero con numeros enteros con signo ;opera destino AND fuente y guarda resultado en destino ;opera destino OR fuente y guarda el resultado en destino ;opera destino XOR fuente y guarda el resultado en destino ;el NOT cambia todos los 1 en 0 y los 0 en 1 de destino. ;NEG realiza el complemento a 2 de destino ;Incremente an 1 el contenido de destino ;Decrementa en 1 el contenido de destino ;Efecta el ajuste decimal en suma / resta del registro AL ;ajustan el registro AL a valor decimal desempaquetado (para aplicar en operaciones suma, resta, multiplicacin y divisin)

Instrucciones de rotacin
RCL RCR ROL ROR SAL SAR SHR destino,contador destino,contador destino,contador destino,contador destino,contador destino,contador destino,contador ;rota destino a traves de carry a la izquierda contador veces ;rota destino a traves de carry a la derecha contador veces ;rota destino a la izquierda contador veces ;rota destino a la derecha contador veces ;desplaza destino a la izquierda contador veces y rellena con ceros ;desplaza destino a la derecha contador veces y rellena con bit SF ;desplaza destino a la derecha contador veces y rellena con ceros

NOTAS SOBRE INSTRUCCIONES DE ROTACIN

y El bit SF (signo) es el que est ms a la izquierda : si destino es operando es de 8 bits "SF" es el bit nmero 7 y si destino es un operando de 16 bits, es el bit nmero 15 y En el procesador 8086 se permite un dato inmediato en lugar de especificar un registro como contador solo si ese dato inmediato es 1. Por lo tanto, para uno de esos procesadores la instruccin RCL AX,1 es vlida mientras que la RCL AX,5 no lo es. A partir de 80286 se puede especificar cualquier numero de rotaciones como dato inmediato. Como DEBUG presupone 8086, cualquier valor inmediato distinto de 1 da error. y Si en un programa para 8086 se desean rotar ms de un bit a la vez, el valor contador se carga en CL y Para rotar un nibble (lo que es muy comn en la conversin de binario a BCD) es ms rpido y ocupa menos memoria si se utilizan 4 rotaciones de contador igual a 1 que si se utiliza el registro CL y Las instrucciones SAL y SHL son equivalentes y La flag de Overflow cambia con una logica precisa si la rotacin es de una posicin. En caso de rotaciones mayores, OVF queda indefinida. y En los procesadores 80286 en adelante la rotacin se hace MODULO 32, es decir que se rotar la cantidad de veces igual al resto de la divisin contador/32, o sea que ROL AX,33 equivale a ROL AX,1 o ROL AX,65. y Una rotacin con CL=0 equivale a un NOP de dos bytes

Instrucciones de comparacin
CMP TEST destino,fuente destino,fuente ;compara fuente y destino. Modifica las flags V, Z, S, C, P y AC ;AND entre fuente y destino . Ninguno de los operandos cambia.

TEST modifica las mismas flags que CMP pero siempre deja a V = 0 y C = 0.

Instrucciones de strings
CMPS CMPSB CMPSW LODS LODSB LODSW STOS STOSB STOSW MOVS string_destino,string_fuente string_destino,string_fuente string_destino,string_fuente string_fuente string_fuente string_fuente string_destino string_destino string_destino string_destino,string_fuente ;compara las dos cadenas de a bytes o words ;origen y destino indicados por DS:SI y ES:DI (bytes) ;origen y destino indicados por DS:SI y ES:DI (words) ;mueve un byte o una word desde fuente a AL o AX ;origen indicado por DS:SI (mueve un byte a AL) ;origen indicado por DS:SI (mueve una word a AX) ;mueve un byte o una word al destino desde AL o AX ;destino indicado por ES:DI (mueve AL a un byte) ;destino indicado por ES:DI (mueve AX a una word) ;mueve un byte o word de fuente a destino ;origen y destino indicados por DS:SI y ES:DI (un byte) ;origen y destino indicados por DS:SI y ES:DI (una word) ;compara la cadena de destino con AL o AX ;destino indicado por ES:DI (compara AL con un byte) ;destino indicado por ES:DI (compara AX con una word)

MOVSB string_destino,string_fuente MOVSW string_destino,string_fuente SCAS SCASB SCASW string_destino string_destino string_destino

En todos los casos, si se utiliza el prefijo REP, la cantidad de elementos de la cadena a operar est dada por el contenido del registro CX, si no es un solo elemento de la cadena. A cada operacin, CX es decrementado y SI y DI son incrementados o decrementados de acuerdo con el estado de la flag de direccin (Si D=0, se incrementan). El incremento o decremento de estos registros se hace de a uno si son operaciones de bytes o de a dos si son de a words. Para los casos en que se especifica el largo del operando con la B o W final, la string_destino est apuntada por ES:DI, la string_fuente est apuntada por DS:SI .

Instrucciones de repeticin
LOOP LOOPZ offset offset ;decrementa CX. Si CX no es cero, salta a offset (IP = IP + offset) ;decrementa CX, Si CX <> 0 y Z = 1 , salta a offset (IP = IP + offset) ;decrementa CX, Si CX <> 0 y Z = 0 , salta a offset (IP = IP + offset) En todos los casos, si no se produce el salto, se ejecuta la prxima instruccin REP REPZ instruccin instruccin ;decrementa CX y repite la siguiente instruccin MOVS o STOS hasta que CX=0 ;igual que REP, pero para CMPS y SCAS. Repite si la flag Z queda en 1 (igualdad) ;igual queREPZ, pero repite si la flag Z queda en 0 (las cadenas son distintas)

LOOPNZ offset

REPNZ instruccin

Instrucciones de salto

CALL RET INT INTO IRET JMP JA JAE JB JBE JZ JG JGE JL JLE JNC JNZ JNO JNP JNS JO JP JS JCXZ

destino valor nmero

;llama a procedimiento. IP <-- offset de destino y CS <-- segmento de destino ;retorna desde un procedimiento (el inverso de CALL), valor es opcional ;llamado a interrupcin. CS:IP <-- vector de INT.Las flags se guardan en el stack ;llama a la INT 4 si la flag de overflow (V) est en 1 cuando se ejecuta la instruccin ;retorna de interrupcin al programa restaurando flags

direccin offset offset offset offset offset offset offset offset offset offset offset offset offset offset offset offset offset offset

;Salta incondicionalmente al lugar indicado por direccin ;salta a IP + offset si las flags C=0 Y Z=0 (salta si primer operando es mayor) ;salta a IP + offset si la flag C=0 (salta si primer operando es mayor o igual) ;salta a IP + offset si las flags C=1 (salta si primer operando es menor)(igual a JC) ;salta a IP + offset si las flags C=1 o Z=1 (salta si primer operando es menor o igual) ;salta a IP + offset si las flags Z=1 (salta si primer operando es igual al segundo)(=JE) ;salta a IP + offset si las flags S=V Y Z=0 (salta si primer operando es mayor) ;salta a IP + offset si las flags S=V (salta si primer operando es mayor o igual) ;salta a IP + offset si las flags S<>V (salta si primer operando es menor) ;salta a IP + offset si las flags S<>V o Z=1(salta si primer operando es menor o igual) ;salta a IP + offset si la flag C=0 (salta si no hay carry) ;salta a IP + offset si la flag Z=0 (salta si no son iguales o no es cero) ;salta a IP + offset si la flag V=0 (salta si no hay overflow) ;salta a IP + offset si la flag P=0 (salta si no hay paridad -o la paridad es impar =JPO) ;salta a IP + offset si la flag S=0 (salta si no hay hay bit de signo) ;salta a IP + offset si la flag V=1 (salta si hay desbordamiento -overflow) ;salta a IP + offset si la flag P=1 (salta si la paridad es par ) (=JPE) ;salta a IP + offset si la flag S=1 (salta si el signo es negativo) ;salta a IP + offset si la flag CX=0 (salta si el registro CX es cero)

Las instrucciones de saltos por Above o Below se refieren entre dos valores sin signo (JA, JAE, JB y JBE), mientras que las Greater y Less se refieren a la relacin entre dos valores con signo (JG, JGE, JL y JLE). .

Instrucciones que afectan flags


CLC/CMC/STC CLD/STD CLI/STI ;pone a cero / complementa / pone en 1 la flag C (carry) ;pone a cero / uno la flag de direccin (D=0 hace que SI y DI se incrementen) ;deshabilita / habilita las interrupciones por hardware enmascarables

Instrucciones miscelneas
NOP CBW CWD HLT ;no-operacin: el procesador pasa a la instruccin siguiente sin hacer nada ;convierte el byte de AL en palabra (AX), copiando el bit 7 a todo el registro AH ;convierte word en double-word, copiando bit 15 de AX a todo el registro DX ;el procesador se detiene hasta que llegue un Reset o una interrupcin por hard.

Alguien puede preguntarse para qu puede servir una instruccin que no hace absolutamente nada como la NOP. Simplemente para llenar espacio, y es realmente una de las instrucciones ms tiles para un cracker, a punto tal que algunos mecanismos anticracking sofisticados buscan durante la ejecucin de un programa si alguien lo arregl sustituyendo algunas instrucciones por NOPs, y en caso de detectarlo, abortan la ejecucin. Pero esto es tema para ms adelante.

MODULO 4
Cuando termine de leer esta pgina deber conocer: y Uso del DEBUG Posiblemente sea el debug el depurador ms rudimentario que existe; pero el hecho que desde el principio haya sido provisto con el sistema operativo, nos permite encontrarlo hoy en cualquier mquina DOS o Windows. Muchas tareas elementales pueden realizarse sin otra ayuda que el Debug y por eso vamos a ver algunos comandos bsicos. Incluso es posible correr programas cargados en memoria utilizando breakpoints elementales, ejecutar paso a paso, saltar sobre procedimientos, editar programas en hexa y muchas ms cosas. Ya hemos dicho cmo podemos arrancarlo desde una ventana DOS, y usando el comando R (mostrar registros) nos mostrar algo similar a esto:
AX=0000 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1332 ES=1332 SS=1332 CS=1332 IP=0100 NV UP EI PL NZ NA PO NC 1332:0100 C3 RET .

Esto muestra el contenido de los registros del procesador incluyendo varias banderas: en el ejemplo, y en el mismo orden tenemos: V=0, D=0, I=1, S=0, Z=0, AC=0, P=0 y C=0 Si ponemos despus de la R el nombre de un registro, es posible modificar su contenido. Por ejemplo, para editar el contenido de CX, hay que poner el comando RCX. Debug nos presenta el contenido actual del registro y la posibilidad de ingresar un nuevo valor para sustituirlo. Los comandos L y W se utilizan para leer y escribir en archivos de disco. La cantidad de bytes transferida en cada operacin es el contenido de BX:CX. Previamente es necesario darle un nombre al archivo con el comando N. Se puede especificar la direccin a partir de la que se desea transferir datos o bien usar el vector por defecto DS:DX. Los comandos ms tiles y ms usados en Debug son:
A D E F G H I M P Q S T U XS ? direc1 direc2 valores cant direc cant direccin direccin cantidad direccin direc1 direc2 valor direccin valor1 valor2 puerto direc1 direc2 direc3 cant Ensamblar (ingresar cdigo assembly) Mostrar en pantalla direcciones de memoria en presentacin hexa Editar memoria desde direccin Llenar memoria desde direc1 hasta direc2 con el dato valor Ir (durante la ejecucin) a la direccin direccin Muestra el resultado de la suma y resta hexadecimal entre valor1 valor2 Obtiene una entrada desde el puerto puerto Mueve el bloque de memoria direc1- direc2 a partir de direc3 Salta sobre procedimientos cant de veces o hasta direccin direc Sale de Debug Busca en bloque de memoria desde direc1 hasta direc2 los bytes valores Igual que P pero son instrucciones simples Desensambla cant bytes a partir de la direccin direc Muestra estado de memoria expandida Presenta pantalla de ayuda

Nuestro primer programa


Usaremos el Debug para ensamblar un programa que realice algo tan til (?) como dejar en alguna parte de la memoria el nombre de nuestra escuela ECCE. Para sacar algo a pantalla, debemos leer el tutorial de +gthorne, que ser nuestro paso siguiente. Por ahora slo queremos practicar de manera que abramos una ventana DOS y escribamos DEBUG (enter). Nos proponemos hacer que ECCE sea escrito en memoria, en el offset 200h de nuestro segmento de datos DS. Sabemos que los cdigos ASCII son E=45h y C=43h, de manera que nuestro programa puede lucir as: a 100
1322:0100 1322:0103 1322:0106 1322:0109 1322:010D 1322:010F mov ax,4543 mov bx,4345 mov [200],ax mov [202],bx int 20 ;cargamos el registro AX con el dato 4543 (EC en ASCII) ;cargamos BX con "CE" en ASCII ;ponemos AX en la direccin de memoria 200 ;idem para BX, pero en la 202 (AX ocup la 200 y 201) ;finalizar y salir a Debug

Al apretar "enter" una vez ms, Debug nos devuelve su prompt "-" y ya estamos listos para nuestro prximo comando. Podemos ver algunas curiosidades del listado anterior: 1) Debug asume que los nmeros que le damos, sean direcciones o datos, son hexadecimales. 2) A medida que vamos ingresando el programa, nos va devolviendo la direccin de almacenamiento de la prxima instruccin que escribiremos. 3) Las tres primeras instrucciones MOV ocuparon de memoria de programa 3 bytes cada una, pero la cuarta ocup 4 bytes y la INT 20 slo ocup 2 bytes. 4) Aunque nada se ha hablado de la INT 20, es lo que por el momento usaremos para terminar el programa . 5) Cuando hacemos referencia al contenido de una posicin de memoria, encerramos la direccin entre corchetes []. Es muy importante saber distinguir entre la direccin y el valor almacenado en esa direccin de memoria. Nuestra lgica es muy simple: cargamos el ASCII "EC" en AX y lo dejamos en la direccin 200. Luego cargamos "CE" en BX y lo dejamos en la 202. Tanto AX como BX han sido meros vehculos para cargar la memoria con datos y slo a los efectos didcticos porque tambin est permitido : MOV word ptr [200],4543 ; cargar la word de memoria 200 directamente con el dato 4543 Esta instruccin ocupa 6 bytes, de modo que no ganamos espacio ponindola en lugar del ms elptico procedimiento de cargar AX y con ste escribir en 200. El prefijo "word ptr" es para que el procesador sepa que lo que moveremos a 200 es una word y no un byte o double-word. Veamos cmo se ve nuestro programa usando el comando desensamblar: -u 100 (desensamble a partir de la CS:100)
(Ntese que Debug listar usando slo maysculas, sin importar cmo escribimos nuestro cdigo) 1322:0100 1322:0103 1322:0106 1322:0109 1322:010D B84345 BB4543 A30002 891E0202 CD20 MOV AX,4543 MOV BX,4345 MOV [200],AX MOV [202],BX INT 20

NOTA: el valor de 1322 (el contenido del registro CS) es vlido para la PC donde se escribi este ensayo. Por lo general los valores no coinciden de una a otra PC, salvo que las instalaciones de software sean

idnticas y en ambas estn corriendo previamente al DEBUG los mismos programas. El listado es ms largo, pero las lneas que siguen hacia abajo son alguna cosa que estaba en memoria, ya que Debug desensambla por defecto los 20h primeros bytes desde la direccin indicada (o desde la que est apuntando), y en nuestro programa slo hemos usado 0Fh bytes (15 en decimal). Echmosle un vistazo: Aj!!, Debug no deja de sorprendernos, en una columna entre la direccin y el listado en lenguaje assembly puso unos nmeros hexadecimales. Son los cdigos de operacin (opcodes) que es lo que en definitiva se almacena en memoria y lo que nuestro Pentium debe interpretar y ejecutar. Debug compil nuestro programa ingresado en assembly y produjo ese cdigo binario con representacin hexadecimal para que el Pentium lo interprete. Antes de correr el fabuloso programa que hemos escrito, tenemos que ver qu hay en la posicin de memoria 200. Para ello usamos el comando D 200, que nos muestra la basura que hay en nuestra RAM desde DS:0200 hasta DS:027F. Como deseamos leer claramente nuestro nombre ECCE, vamos a llenar este espacio con ceros usando el comando - F 200 23F 00 con lo que le indicamos a Debug que debe llenar el bloque de memoria que comienza en 200 y termina en 23F con "00". Para estar seguros, escribamos nuevamente el comando D 200. Debemos ver las cuatro primeras filas del listado con los datos en 00. Estamos listos para correr nuestra maravilla. Con el comando R nos aseguramos que CS:IP est apuntando al inicio de nuestro programa (o sea a CS:0100). Para nuestro caso CS vale 1322, pero como ya se ha dicho, puede que en otra PC tenga otro valor. Corramos el programa con el comando G. Debug nos debe informar: El programa ha finalizado con normalidad. Bien! todo fue de maravillas. Veamos si nuestras siglas brillan en las posiciones 200 a 203 con el comando D 200 Esperbamos los hexa 45,43,43,45 a partir de la 200 (miremos adems en la columna ASCII del Debug, en donde claramente nos dice CEEC) y estn al revs. Qu habr pasado? Ser que hemos escrito BX en 200 y AX en 202?. Usemos al Debug para depurar , que para eso Bill Gates lo ha puesto donde est. Repitamos el comando F 200 23F 00 para dejar nuevamente en cero la memoria y ejecutemos nuestro programa paso a paso. Primero el comando R. Nos debe decir que IP apunta a 0100: 1322:0100 B84345 MOV AX,4543 -T (comando para ejecutar una sola instruccin). Lo relevante es: AX=4543 e IP=0103 1322:0103 BB4543 MOV BX,4345 es la prxima instruccin. Ejecutemos con T: 1322:0106 A30002 MOV [200],AX Ejecutemos el comando D 200 para ver qu hay en la memoria: hasta ahora 00 de la direccin 200 a la 203. Todo ok, porque hasta aqu slo hemos cargado los registros AX y BX. Hagamos otro T. 1322:0109 891E0202 MOV [0202],BX es la prxima instruccin

Hemos guardado AX en la direccin 200 y por lo tanto debera haber un 4543 ("EC" en ASCII) en las direcciones 200 y 201. Verifiquemos con el comando D 200: 1322:0200 43 45 00 00 ........ CE................ QUE PASO???? Est al revs. Tengo "CE" en lugar de "EC". Mmmmm!! Mr Intel tiene algo que ver con esto: Resulta que lo que leemos en AX como "EC", en la realidad lo debemos asumir como : En AL tengo un 43 ("C") y en AH un 45 ("E"). Y el procesador hace algo sumamente lgico, a la porcin ms baja del registro (AL) la almacena en la direccin de memoria ms baja (200) y a la porcin ms alta del registro (AH) la almacena en la direccin de memoria ms alta (201). Todo parece bien pero no funciona? Pero est bien tal como lo hizo Intel. Si leemos la memoria en sentido de direcciones ascendentes, debemos acostumbrarnos a leer los registro (y a cargarlos, ah fue donde nos equivocamos!) desde la porcin ms baja hacia la ms alta. Por lo tanto, debemos rescribir nuestro programa para que en AL se almacene la primera letra ("E") y en AH la segunda ("C"), y lo mismo para BX: a 100 1322:0100 MOV AX,4345 1322:0103 MOV BX,4543 (enter) nuevamente para salir del comando A. Ahora debemos modificar el registro IP, que nos qued apuntando a la mitad del programa: RIP (enter) nuestro comando IP 0109 respuesta de Debug :100 (enter) este valor lo ingresamos nosotros para decirle que queremos a IP=0100 Ejecutamos el programa nuevamente con G y examinamos la memoria con D 200 para ver nuestro hermosa sigla ECCE ya en su lugar y en el orden debido.

Acepte este buen consejo: No siga adelante si algo no qued claro. Relalo, busque otra fuente, alguien que le pueda explicar ms claro que yo, pero no lea +gthorne sin haber entendido aunque sea la mecnica con que operan los procesadores. Con el tiempo podr memorizar los mnemnicos de las instrucciones, con muy poca prctica puede dominar Debug y sus comando heredados de una era sombra de las PCs.

CAPITULO II
INTERRUPCIONES

1. Una historia vieja como la PC Hace muchos aos, en un pas muy lejano, un gigante azul se sinti solo en sus alturas y dijo: "No es bueno que el programador solo trabaje en su oficina. Hagamos una computadora personal para que tambin pueda llevarse el trabajo a su casa". Y as lo hizo. Esa decisin nos puso, amigo deseoso de convertirse en cracker que estas leyendo esto, en contacto unos 20 aos despus. IBM tom una decisin respecto a la arquitectura de sus computadoras personales destinada a marcar un cambio notable en la historia de la tecnologa. Adopt una arquitectura abierta, esto es, utiliz componentes que estaban en el mercado en lugar de fabricar chips propietarios. Al tomar esta resolucin, Intel pas a ser la opcin ms clara como proveedor de procesadores y perifricos: por aqul entonces acababa de salir al mercado la lnea de 16 bits 8086 y existan muchos perifricos de 8 bits de su predecesor, el 8085, tales como el controlador de interrupciones 8259, el PPI 8255, DMA 8237, la UART 8251, el timer 8253. En los procesadores Intel de la lnea X86, hay dos tipos de interrupciones: por hardware y por software. En las primeras, una seal llega a uno de los terminales de un controlador de interrupciones 8259 y ste se lo comunica al procesador mediante una seal LOW en su pin INT. El procesador interroga al 8259 cul es la fuente de la interrupcin (hay 8 posibles en un 8259) y este le muestra en el bus de datos un vector que la identifica. Por instrucciones de programa, se puede instruir al 8086 para que ignore la seal en el pin INT, por lo que estas interrupciones se denominan "enmascarables". Hay un pin adicional llamado NMI, que se comporta como una interrupcin, pero imposible de bloquear (Non-Maskable-Interrupt).

2. Tipos de interrupciones Las interrupciones por software se comportan de igual manera que las de hardware pero en lugar de ser ejecutadas como consecuencia de una seal fsica, lo hacen con una instruccin. Hay en total 256 interrupciones, de la 0 a la 7 (excepto la 5) son generadas directamente por el procesador. Las 8 a 0Fh son interrupciones por hardware primitivas de las PC. Desde la AT en adelante, se incorpor un segundo controlador de interrupciones que funciona en cascada con el primero a travs de la interrupcin 2 (de ah que en la tabla siguiente se la denomine mltiplex). Las 8 interrupciones por hardware adicionales de las AT se ubican a partir del vector 70h.
Decimal 0 1 2 3 4 Hexa 0 1 2 3 4 Generada CPU CPU CPU CPU CPU Descripcin Divisin por cero Single-step NMI Breakpoint Desbordamiento Aritmtico

5 6 7 8 9 10 11 12 13 14 15 112 113 114 115 116 117 118 119

5 6 7 8 9 0A 0B 0C 0D 0E 0F 70 71 72 73 74 75 76 77

BIOS CPU CPU HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD HARD

Imprimir Pantalla Cdigo de operacin invlido Coprocesador no disponible Temporizador del sistema (18,2 ticks por seg) Teclado Mltiplex IRQ3 (normalmente COM2) IRQ4 (normalmente COM1) IRQ5 IRQ6 IRQ7 (normalmente LPT1) IRQ8 (reloj de tiempo real) IRQ9 IRQ10 IRQ11 IRQ12 IRQ13 (normalmente coprocesador matemtico) IRQ14 (normalmente Disco Duro) IRQ15

En cuanto a las interrupciones por software, estn divididas entre las llamadas por el BIOS (desde la 10h a la 1Fh) y las llamadas por el DOS (desde la 20h hasta la 3Fh). Esto es slo la versin oficial, ya que en realidad las interrupciones entre BIOS y DOS se extienden hasta la 7Fh.

3. Cmo funciona una interrupcin A partir del offset 0 del segmento 0 hay una tabla de 256 vectores de interrupcin, cada uno de 4 bytes de largo (lo que significa que la tabla tiene una longitud de 1KB). Cada vector est compuesto por dos partes: offset (almacenado en la direccin ms baja) y segmento (almacenado en la direccin ms alta). Cuando se llama a una interrupcin (no importa si es por hardware o por software), el procesador ejecuta las siguientes operaciones: 1. PUSHF (guarda las banderas en el stack)

2. CTF/DI (borra la bandera de Trap y deshabilita interrupciones) 3. CALL FAR [4 * INT#] (salta a nueva CS:IP, almacenando direccin de retorno en stack) La expresin 4 * INT# es la forma de calcular la direccin de inicio del vector de interrupcin a utilizar en el salto. Por ejemplo, el vector de la INT21h estar en la direccin 84h Al efectuarse el salto, la palabra almacenada en la direccin ms baja del vector sustituye al contenido del registro IP (que previamente fue salvado en el stack) y la palabra almacenada en la direccin ms alta sustituye al contenido del registro CS (tambin salvado en el stack). Por ejemplo: La instruccin INT 21h es la usada para efectuar llamadas a las funciones del DOS. Supongamos que en la posicin de memoria 0000:0084 est almacenada la palabra 1A40h y en la direccin 0000:0086 est almacenada la palabra 208Ch. La prxima instruccin que se ejecute es la que est en la posicin 20C8:1A40 (nuevo CS:IP). El final de una rutina de interrupcin debe terminarse con la instruccin IRET, que recupera del stack los valores de CS, IP y Flags. Notemos que un llamado a interrupcin implica el cambio de estado automtico de la bandera de habilitacin de interrupciones. En pocas palabras, esto significa que al producirse una interrupcin, esta bandera inhabilita futuras interrupciones. Como la instruccin IRET restablece el registro de flags al estado anterior que tenia antes de producirse la interrupcin, las prximas interrupciones se habilitan en el mismo momento en que se produce el retorno desde la rutina de servicio.

4. Paso de parmetros desde el programa a la ISR Cuando las interrupciones son llamadas por software mediante la instruccin INT xx, por lo general se le deben pasar parmetros a la rutina de servicio de interrupcin (ISR). Estos parmetros definen la tarea que debe cumplir la ISR y son pasados en los registros del procesador, lo que es una opcin muy veloz. Un ejemplo casi extremo, en donde muchos de los registros del 8086 son utilizados son algunos servicios cumplidos por la INT 13h (disco). Para tomar slo un caso, en una operacin de escritura de un sector, los parmetros se pasan de la siguiente manera:
Registro AH AL CH CL(bits 0-5) CL(bits 6 y 7) DH DL BX Asignacin 03 (servicio de escritura de sectores) cantidad de sectores a escribir 8 bits ms bajos del nmero de cilindro nmero de sector 2 bits ms altos del nmero de cilindro nmero de cabeza nmero de unidad de disco (hard: mayor a 80h) offset del buffer de datos

ES

segmento del buffer de datos

Si bien no est escrito en ningn lado, las interrupciones utilizan el registro AH para identificar el tipo de operacin que deben ejecutar. Cuando una interrupcin devuelve cdigos de error siempre vienen en el registro AL, AX y/o en la bandera de Carry.

5. La interrupcin ms famosa Sin lugar a dudas se trata de la INT 21h (funciones del DOS). El nmero de funcin se pasa en el registro AH
Funcin 00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh 10h 11h Descripcin Terminar un programa Entrada de caracteres con salida Salida de un caracter Recepcin de un caracter por el puerto serial Envo de un caracter por el puerto serial Salida por puerto paralelo Entrada/salida de caracteres directa Entrada/salida de caracteres directa Entrada de caracteres sin salida Salida de un string de caracteres Entrada de un string de caracteres Leer estado de una entrada Borra buffer de entrada y llama a entrada de caracteres Reset de los drivers de bloques Seleccin de unidad actual Abrir archivo usando FCBs (File Control Blocks) Cerrar archivo (FCBs) Busca primera entrada de directorio (FCBs)

12h 13h 14h 15h 16h 17h 18h 19h 1Ah 1Bh 1Ch 1Dh/1Eh 1Fh 20h 21h 22h 23h 24h 25h 26h 27h 28h 29h 2Ah 2Bh 2Ch

Busca siguiente entrada de directorio (FCBs) Borrar archivo(s) (FCBs) Lectura secuencial (FCBs) Escritura secuencial (FCBs) Crear o vaciar un archivo (FCBs) Renombrar archivos (FCBs) Obsoleta Obtener denominacin de dispositivo, unidad actual Fijar direccin para DTA (Disk Transfer Area) Obtener informacin sobre unidad actual Obtener informacin sobre una unidad cualquiera Obsoletos Fijar puntero a DPB (Drive Parameter Block) a la unidad actual Obsoleta Lectura random (FCB) Escritura random (FCB) Leer tamao de archivo (FCB) Establecer nmero de registro (FCB) Establecer vector de interrupcin Crear nuevo PSP (Program Segment Prefix) Lectura random de varios registros (FCB) Escritura random de varios registros (FCB) Transferir nombre de archivo al FCB Obtener fecha Establecer fecha Obtener hora

2Dh 2Eh 2Fh 30h 31h 32h 33h 34h 35h 36h 37h 38h 39h 3Ah 3Bh 3Ch 3Dh 3Eh 3Fh 40h 41h 42h 43h 44h 45h 46h

Establecer hora Fijar bandera de Verify Obtener DTA Obtener nmero de versin del DOS Terminar programa pero dejarlo residente en memoria Obtener puntero a DPB de una unidad especfica Leer/escribir bandera de break Obtener direccin de bandera INDOS Leer vector de interrupcin Obtener espacio de disco disponible Obtener/fijar signo p/separador de lnea de comandos Obtener/fijar formatos especficos de un pas Crear subdirectorio Borrar subdirectorio Fijar directorio actual Crear o vaciar archivo (handle) Abrir archivo (handle) Cerrar archivo (handle) Leer desde archivo (handle) Escribir en archivo (handle) Borrar archivo (handle) Mover puntero de archivo (handle) Obtener/fijar atributo de archivo Funciones IOCTL (control de I/O) Duplicar handle Duplicacin forzosa de handles

47h 48h 49h 4Ah 4Bh 4Ch 4Dh 4Eh 4Fh 50h 51h 52h 53h 54h 55h 56h 57h 58h 59h 5Ah 5Bh 5Ch 5Dh 5Eh 5Fh 60h

Obtener directorio actual Reservar memoria RAM Liberar memoria RAM Modificar tamao de memoria reservada EXEC: ejecutar o cargar programas Terminar programa con valor de salida Obtener valor de salida de un programa Buscar primera entrada en el directorio (handle) Buscar siguiente entrada en el directorio (handle) Establecer PSP activo Obtener PSP activo Obtener puntero al DOS-info-block Traducir Bios Parameter Block a Drive Parameter Block Leer bandera Verify Crear PSP nuevo Renombrar o mover archivo Obtener/fijar fecha y hora de modificacin de archivo Leer/fijar estrategia de alocacin de memoria Obtener informaciones de error ampliadas Crear archivo temporal (handles) Crear archivo nuevo (handles) Proteger parte de un archivo contra accesos Funciones de Share.exe Obtener nombres de dispositivos de red Obtener/fijar/borrar entrada de la lista de red Ampliar nombre de archivo

61h 62h 63h/64h 65h 66h 67h 68h 69/6A/6B 6Ch

No usada Obtener direccin del PSP No usadas Obtener informacin ampliada de pais especfico Obtener/fijar pgina de cdigos actual Determinar el nmero de handles disponibles Vaciar buffer de archivos No usadas Funcin Open ampliada

6. Intercepcin de interrupciones (hooks) Un programa puede necesitar "enganchar" una interrupcin. Supongamos que hemos creado un virus que debe autodestruir su copia en memoria cuando el comando a ejecutar es "scan.exe". Evidentemente debemos interceptar la interrupcin 21h, funcin 4Bh/00 (cargar un programa y ejecutarlo), de tal manera que "nuestra" funcin verifique si el programa a cargar se llama scan.exe y en tal caso, borre lo que haya que borrar. Esta tarea, se logra en haciendo un programa residente (que puede ser parte del mismo cdigo del virus) para que 1. Cuando se produzca una llamada a la INT21h-4Bh, no se ejecute el cdigo normal del DOS sino nuestro cdigo 2. En l chequearemos si la funcin es una 4Bh-00, y en caso afirmativo verificamos si el programa a corres se llama scan.exe. Si todo esto es verdadero, sobrescribiremos las partes sensibles a la deteccin del virus y lo descargaremos de la memoria. 3. Finalmente saltamos a la verdadera INT21h funcin 4Bh Para lograr esto, es necesario contar con un loader que cargue en memoria nuestro programa. Este loader debe: 1. Reservar un espacio de memoria adecuado al tamao del cdigo que quedar residente. 2. Averiguar (mediante INT21h-35h) cual es el vector de interrupcin de la INT21h. Supongamos que sea 0102:2C40h 3. Poner este vector como direccin de retorno del cdigo residente (por lo general cargndolo en una direccin conocida en donde tiene que estar este valor) 4. Cambiar el vector 4Bh origina por la direccin de inicio de nuestro cdigo residente (digamos 7E00:0000) Lo que suceder cuando la PC infectada con nuestro virus intente ejecutar un scan.exe es lo siguiente: 1. Dentro del Command.com, se generar un llamado a la INT21-4Bh-00 con scan.exe como parmetro.

2. El procesador buscar el vector para el servicio a la interrupcin 21h en la direccin 0000:0084h 3. En ese lugar estar la direccin de inicio de nuestro residente, o sea 7E00:0000, y en ese lugar se inicia el procesamiento de la interrupcin. 4. Al ver que la llamada es para ejecutar un programa scan.exe nuestro residente vuelve a poner el vector de INT21h en el valor que le dio el DOS y luego se autodestruye (primero traslada a la parte ms baja de la memoria la funcin de borrado). Como ltimo acto, hace un salto JMP FAR 0102:2C40 5. Esto ltimo har que se ejecute scan.exe como si nada hubiese sucedido. Frecuentemente los virus utilizan interrupciones en desuso para sus fines (por ejemplo para saber si estn activos en memoria).

El tema de las interrupciones es tan inmenso que lo que acabamos de ver no es sino un pequeo pantallazo. Quedan cuestiones muy delicadas como la bandera INDOS y las formas de evitar la reentrada. Una descripcin muy completa de cada interrupcin, que incluye los registros usados para el paso de parmetros, est en el archivo intdos.zip, por Ralph Brown (en ingls) que pueden bajarse de sudden discharge o asmcoder , dos sitios que les recomiendo si se buscan tutoriales o archivos.

CAPITULO III
MANEJO DE STRINGS EN BIOS, DOS, y WINDOWS

1.- Funcin BIOS para manejo de strings El BIOS interacta principalmente de a un caracter por vez con el teclado, pantalla y puerto serial, por lo que a estos se los conoce como dispositivos de caracteres, en contraposicin con el drive de diskettes o el disco duro, que son dispositivos de bloques. Aunque menos frecuente que las funciones de manejo de strings del DOS, la funcin 13h de la INT10h tiene la ventaja que no depende del sistema operativo. Su funcin es visualizar en la pantalla una cadena de caracteres que deben estar almacenados en un buffer (en memoria). El paso de parmetros se realiza mediante los siguientes registros:
Registro AH Parmetro 13 h - define la operacin Modo de salida: 0 AL 1 2 3 BL CX DH DL BH ES:BX Atributo en BL, mantiene la posicin del cursor Atributo en BL, actualiza la posicin del cursor Atributo en buffer, mantiene posicin del cursor Atributo en buffer, actualiza posicin del cursor

Atributo de caracteres (solo modos 0 y 1) Cantidad de caracteres a visualizar Lnea de la pantalla Columna de la pantalla Pgina de pantalla Puntero al buffer de memoria

Los modos que actualizan la posicin del cursor se usan cuando se quieren escribir varios strings uno a continuacin del otro. En cambio los modos que la mantienen, se utilizan para escribir mensajes siempre en el mismo lugar de la pantalla. En los modos 0 y 1 todos los caracteres tienen el atributo especificado en BL, mientras que en los modos 2 y 3 en el buffer, seguido a cada caracter esta su byte de atributo, lo que permite que cada caracter tenga un

atributo distinto. La cadena en memoria tiene una longitud igual al doble de los caracteres a visualizar. El valor de CX debe ser no obstante igual a la cantidad de caracteres (la mitad del tamao del buffer). El byte de atributos tiene la siguiente estructura:
Bit # 7 6,5,4 3,2,1,0 Funcin Intermitencia (1=intermitente, 0=fijo) Color de fondo (0=negro, 7=blanco) Color del caracter (0=negro, 0Fh=blanco)

2. Funciones DOS de manejo de strings 2.1 Entrada de strings de caracteres: INT21h - funcin 0Ah Se leen caracteres desde la entrada standard (normalmente teclado) y se transfieren a un bffer en memoria. La operacin termina cuando se lee el caracter ASCII 0Dh (CR o retorno de carro), que corresponde a la tecla RETURN (o ENTER).
Registro AH DS:DX Parmetro 0Ah - cdigo de la funcin Puntero al buffer de memoria

Estructura del Buffer:


Posicin DS:DX DS:DX + 1 DS:DX + 2 y subsig. Significado Cantidad mxima de caracteres admitida en el buffer (debe ser inicializada por el programador) Cantidad de caracteres leda (la escribe el DOS) Buffer donde se almacenan los caracteres ledos. La direccin del ltimo es DS:DX + byte ptr (DS:DX)

En los dos primeros bytes, la cantidad de caracteres incluye al CR final. Suponiendo que el programador inicialice la posicin de memoria DS:DX en 10h, el buffer tendr un largo total de 16 caracteres, comenzando en DS:DX y finalizando en DS:DX + 0Fh, y podr aceptar 13 caracteres ms el de retorno. DOS no se preocupa por borrar la parte del buffer que no escribe. Veamos en la tabla siguiente, para un buffer de 16 de largo qu caracteres encontramos luego de dos entradas sucesivas, la segunda ms corta que la primera:
Direccin DS:DX + ... primera entrada 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 0f B u e n o s A i r e s 0d ?

segunda entrada

10 0a C o r d o b a 0d i r e s 0d ?

Hay que notar que si bien esta funcin es muy cmoda, se queda esperando el caracter de retorno y hasta que este no llegue el programa no puede hacer otra cosa que... esperar!. En cambio, si se busca de a un caracter por vez, es posible hacer que el programa consulte el teclado como una de las tantas actividades posibles dentro de un mismo lazo.

2.2 Salida de string de caracteres, INT 21h - funcin 9h Con esta funcin se enva un string de caracteres al dispositivo designado como salida standard (normalmente la pantalla). DOS permite redireccionar la salida a un archivo o a un puerto serial o LPT desde la misma lnea de comandos, por lo que al usar esta funcin no hay garantas de que el string aparezca en pantalla. En realidad, esto tambin es vlido para la entrada de caracteres vista en el punto anterior, aunque es mucho ms frecuente redireccionar la salida que la entrada. Por ejemplo, el comando interno type archivo har que el contenido del archivo sea visualizado en la pantalla, pero si agregamos un redirector con un dispositivo de salida "> LPT1", los caracteres del archivo sern direccionados al puerto de la impresora. El string debe finalizar obligatoriamente con el caracter "$" (cdigo ASCII 36). Los caracteres especiales como Bell, Backspace, CR, etc sern tratados como tales. Bell (ASCII 07) hace sonar una campana en el altavoz de la PC, CR vuelve al principio de la lnea, Nueva_lnea (ASCII 0Ah) pasa a la lnea de abajo, etc Al igual que en la lectura de strings, los parmetros son:
Registro AH DS:DX Parmetro 09h - cdigo de la funcin Puntero al buffer de memoria donde reside el string

En lenguaje Assembly, un string para usarse con esta funcin puede ser declarado como sigue: mensaje1 DB "Todos los hombres de buena voluntad",0Dh,0Ah,"$"

y para utilizar la funcin 9h, el cdigo a emplear sera:


display: MOV MOV INT RET DX, offset mensaje1 AH,9 21H

3. Funciones Windows de manejo de strings 3.1 CompareStrings

Esta funcin compara dos strings de caracteres usando como base el juego de caracteres del idioma especificado por el identificador. La sintaxis del llamado es: int CompareString( LCID Locale, DWORD dwCmpFlags, LPCTSTR lpString1, int cchCount1, LPCTSTR lpString2, int cchCount2 ); 3.2 GetDlgItemText La funcin GetDlgItemText captura el titulo o texto asociando con un control en una caja de dilogo. La sintaxis es: UINT GetDlgItemText( HWND hDlg, int nIDDlgItem, LPTSTR lpString, int nMaxCount ); 3.3 GetWindowText La funcin GetWindowText copia el texto de una barra de ttulo de una ventana especificada en un buffer. Si la ventana especificada es un control, lo que se copia es el texto del control. Sintaxis: int GetWindowText( HWND hWnd, LPTSTR lpString, int nMaxCount ); 3.4 GetWindowTextLength La funcin GetWindowTextLength obtiene la cantidad de caracteres que tiene el texto de la barra de ttulo de una ventana o (si la ventana especificada es un control), la cantidad de caracteres dentro del control. La sintaxis es: handle de la ventana o control direccin del buffer de texto mximo nmero de caracteres a copiar handle de la caja de dilogo identificador del control direccin del buffer para el texto mxima longitud del string identificador de lenguaje del sistema opciones de comparacin puntero al primer string tamao (bytes) del primer string puntero al segundo string tamao (bytes) del segundo string

int GetWindowTextLength( HWND hWnd handle de la ventana o control );

3.5 lstrcat La funcin lstrcat adiciona un strin a continuacin de otro. Sintaxis: LPTSTR lstrcat( LPTSTR lpString1, LPCTSTR lpString2 ); 3.6 lstrcmp y lstrcmpi La funcin lstrcmp compara dos strings de caracteres. La comparacin discrimina entre maysculas y minsculas. La funcin lstrcmpi es idntica pero no discrimina maysculas y minsculas.- Sintaxis: int lstrcmp( // int lstrcmpi( direccin del primer string direccin del segundo string direccin del buffer de strings concatenados direccin del string a concatenar con string1

LPCTSTR lpString1, LPCTSTR lpString2 ); 3.7 lstrcpy

La funcin lstrcpy copia un string en un buffer. Sintaxis:

LPTSTR lstrcpy( LPTSTR lpString1, LPCTSTR lpString2 ); direccin del buffer direccin del string a copiar

3.8 lstrcpyn La funcin lstrcpyn copia un nmero especificado de caracteres de un string dentro de un buffer. LPTSTR lstrcpyn( LPTSTR lpString1, direccin del buffer LPCTSTR lpString2, direccin del string a copiar int iMaxLength cantidad de caracteres o bytes a copiar ); 3.9 lstrlen La funcin lstrlen devuelve la longitud en bytes (versin ANSI) o caracteres (versin Unicode) del string especificado (no incluye el caracter NULL de terminacin).

int lstrlen( LPCTSTR lpString );

direccin del string

3.10 MultiByteToWideChar La funcin MultiByteToWideChar despliega un string de caracteres en un string Unicode. int MultiByteToWideChar( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cchMultiByte, LPWSTR lpWideCharStr, int cchWideChar ); 3.11 SetDlgItemText La funcin SetDlgItemText determina el texto de un control en un box de dilogo. Sintaxis: BOOL SetDlgItemText( HWND hDlg, int nIDDlgItem, LPCTSTR lpString ); handle del box de dilogo identificador del control puntero al texto cdigo de pgina opciones tipo de caracteres direccin del string a mapear nmero de caracteres en el string direccin del buffer Unicode tamao del buffer

3.12 SetWindowText La funcin SetWindowText cambia el texto en la barra de ttulo de una ventana. Si la ventana es un control, se cambia el texto del control. Sintaxis: BOOL SetWindowText( HWND hWnd, LPCTSTR lpString ); handle de la ventana o del control direccin del string

CAPITULO IV

PASO DE PARAMETROS EN LOS PROGRAMAS


Parte I: COMO PASAN LOS PARAMETROS A LAS INTERRUPCIONES BIOS Y DOS ASO DE PARAMETROS Es posible que una de las partes ms tardamente comprendidas por el principiante de ingeniera inversa es la manera en que pasan los parmetros desde el programa a una funcin. Este concepto es de fundamental importancia en el estudio de las protecciones y podemos decir sin lugar a dudas que la comprensin de este mecanismo es crucial para el anlisis del funcionamiento de un programa DOS o Windows.

LA ANTIGUA HISTORIA DEL DOS El viejo DOS en lugar de funciones API utilizaba interrupciones de software (INT 21h y subsiguientes), y un poco ms prximo al hardware, el mismo BIOS cuenta con su propio juego de interrupciones. Estas interrupciones de software funcionan igual que cualquier llamada a funcin, aunque el mecanismo de llamada es distinto, ya que se usa la instruccin INT en lugar de CALL. Por lo general, tanto el DOS como el BIOS pasaban los argumentos en los registros del mismo procesador. Si bien es una estrategia que optimiza la velocidad de procesamiento, tiene sus limitaciones en cuanto a la cantidad de parmetros que se pueden pasar. Otro de los problemas que tiene es que las funciones no pueden ser reentrantes a menos que se tomen previsiones excepcionales, aunque esto no era de mucha importancia ya que el DOS no es multitarea, sera slo problema para programas residentes. Por lo general se pasaban los parmetros por valor. Por ejemplo, en una interrupcin de BIOS de lectura de un sector de disco a memoria (INT 13, subfuncin 02) tenemos: reg AH AL CH CL CL DH DL ES:BX var 2 n c0 s c1 h d ba significado subfuncin 2: lectura de un sector cantidad de sectores a leer 8 bits ms bajos del nmero de cilindro (track) a leer numero de sector a leer (bits 0 a 5) 2 bits ms altos del nmero de cilindro (bits 6 y 7) nmero de cabeza lectora nmero de disco lgico (bit 7 en 1 para discos duros) direccin de inicio del buffer de lectura en memoria

A menos que se trate de aplicaciones muy especiales en que estos valores pueden ser fijos, lo usual es que cada uno de esos parmetros sea una variable que a su vez est almacenada en algn lugar de la memoria. En el siguiente listado que sigue estos parmetros son referidos con nombres simblicos supuestos y el lector debe tener presente que en el listado de lenguaje de mquina lo que se vern son las direcciones de almacenamiento de estos parmetros. Veremos cmo sera una llamada a la interrupcin que lea 4 sectores

consecutivos del disco C, ubicados en la pista 801 (0321h), cabeza 3, a partir del sector 12 (0Ch), y que almacene lo ledo en la direccin DS:0700. El registro CX en binario debe ser: 0010 0001 11 001100 = 21CC h Los bits 15 a 8 deben ser 21h (ocho bits menos significativos del nmero de track), los bits 7 y 6 ambos en uno (el 3 del nmero de track) y los bits 3 y 2 tambin en uno por en nmero de sector. En algn lugar del programa se produce la carga de los valores iniciales: PUSH POP MOV MOV MOV MOV DS AX segme,AX AX,0700 offse,AX AX,0380 ;haremos que los datos se escriban ;en el segmento de datos DS ;almacenamos en la variable segme ;en el offset 0700h ;almacenamos en la variable offse ;disco C (80h), cabeza 3

Y luego se cargan los registros desde la memoria antes de llamar a la int 13h MOV MOV MOV MOV MOV MOV CALL JC ... _leedisk: ... MOV MOV MOV MOV MOV MOV MOV MOV XCHG MOV INT RET curdisk,AL curhead,AH AX,21CC track0,AH sekt,AL AL,4 _leedisk _error ... ... DH,AL AX,segme ES,AX BX,offse CL,sekt CH,track DL,curdisk AL,curhead DH,AL AH,2 13 ;almacena 80 en variable curdisk ;almacena 03 en variable curhead ;nmero de track y sector

;nmero de sectores a leer ;leer ;si CY vuelve en 1, hubo error de lectura ;lectura de disco ;salvar cantidad de sectores a leer ;cargar segmento ;cargar offset de buffer s;ector y 2 bits ms altos de track ;cargar track ;unidad de disco a utilizar ;numero de cabeza cambiar nmero de sectores y cabeza ;subfuncin de lectura ;interrupcin 13h BIOS disco

Uno puede preguntarse cul es el objeto de poner los parmetros en memoria en lugar de cargarlos directamente en los registros apropiados para la llamada a la INT 13h. Es una cuestin de practicidad y buen estilo de programacin. Si las variables estn en memoria, el programa puede consultarlas en cualquier momento o modificarlas por ejemplo para hacer un lazo. Si se cargan como constantes, tal como sucede en la primera parte de la rutina, en donde se inicializan las variables, servirn solamente para efectuar esa llamada. Por ejemplo, si despus de esa primera lectura quisieramos leer los sectores 1 a 7 del mismo track, slo habra que poner: MOV AND OR MOV AL,sekt AL,C0h AL,1 sekt,AL ;nuevo sector inicial ;dejamos solo los dos bits del track (6 y 7) ;ponemos en 1 el numero de sector ;guardamos nuevamente

MOV CALL

AL,7 _leedisk

;numero de sectores a leer

NOTA IMPORTANTE Un lector de nivel intermedio podra objetar que es posible tratar parte del cdigo como si fuesen variables y de tal modo ahorrarnos un paso, dejando slo la carga inmediata de registros. El programa se vera as (inclumos ahora una columna para las direcciones del cdigo por razones obvias) CS:1000 MOV DL,80 ;cdigo del disco duro, unidad C CS:1002 MOV AL,4 ;leer cuatro sectores CS:1006 etc etc Si por ejemplo quisiesemos leer 2 sectores y cambiar la unidad C por la A, habra que poner: XOR AL,AL ;poner a cero AL (unidad A) MOV [CS:1001],AL ;cambia la carga de DL MOV AL,2 ;numero de sectores MOV [CS:1003],AL ;cambia carga de AL CALL _leedisk En algunas oportunidades se hace, es una tcnica conocida como automodificacin, pero no lo recomiendo para principiantes. Por cierto que en lugar de poner la direccin absoluta como se hizo ahora en beneficio de la claridad, es posible utilizar variables del compilador (que se traducen en constantes iguales a CS:1001 y CS:1003 para el programa)

El lector puede encontrar en Internet la completa y muy extensa lista de llamadas a interrupcin de Ralph Brown (por ejemplo en el sitio sudden discharge ), unas 250 pginas tamao oficio en letra condensada a dos columnas en donde se incluyen hasta interrupciones propias de virus. Mi mejor consejo si tiene que trabajar con programas DOS es que la consiga y la imprima (y a menos que su vista sea excelente, no la imprima en condensada aunque le lleve el dobe de papel). Hay una versin mucho ms condensada y menos exhaustiva que viene para instalar residente, atribuida a Peter Norton y que puede ser suficiente si los programas acceden a las interrupciones ms comunes (por ejemplo, no estn ni las que se utilizan para redes ni las de los DOS-extenders). Trate de bajarla de nuestro sitio usando este vnculo.

EN BUSCA DE ALTERNATIVAS Un poco agotado en las complejidades crecientes, el modo de paso de parmetros mediante registros iba a quedar acotado a rutinas del ncleo de sistemas operativos en donde la velocidad es un factor de gran importancia. Haba que buscar alternativas para mejorar la manera en que los parmetros son pasados a las funciones. Consideraremos ahora tres temas ntimamente relacionados con el paso de parmetros. * Paso de valor versus uso de punteros * Cmo opera el stack * Estructuras de datos 1) Paso de argumentos por punteros. En el punto anterior se vio con profundidad el paso de argumentos por valor, es decir, se le entrega a la funcin convocada el VALOR con el que tendr que operar. Dentro de las llamadas a interrupcion ms comunes, esto es algo inevitable porque los valores pasan en los mismos registros del procesador. Sin embargo cuando se estructur el ejemplo sobre la lectura de sectores de disco, se hizo un pequeo avance: se colocaban los valores en direcciones de memoria y luego la rutina los recuperaba antes de convocar a la interrupcin 13h.

El paso de argumentos mediante punteros consiste en una tcnica similar, en donde a la funcin convocada se le dice en qu direccin estn los valores con los que tiene que operar. Esta es la manera en que trabajan los compiladores C y Pascal por ejemplo. Supongamos que queremos sumar 7 y 11. En pseudo lenguaje C no sera correcto poner: A = Suma (7,11) que sera ms propio de Basic, sino: int A,B=7,C=11; A= Suma(B,C); printf A; Se declaran tres enteros, definiendose el valor de dos de ellos, se llama a una funcin Suma(x,y) que debe estar definida en otra parte del programa, que usa dos argumentos de entrada y devuelve un entero. Finalmente se imprime el entero resultante. Esto corresponde ms o menos con el siguiente listado en lenguaje Assembly: varA varB varC .... LEA PUSH LEA PUSH LEA PUSH CALL CALL DW DW DW .... AX, varA AX AX, varB AX AX, varC AX _add _printAx

7 11

Lo que en realidad se le est entregando a la funcin _add son tres valores en el stack que no son los que tiene que sumar, sino las direcciones en donde estan almacenados los datos de entrada y la direccin donde debe almacenar el resultado. Consulte en el punto siguiente cmo opera el stack. El presente ejemplo ser resuelto con valores numricos para que se aprecie bien la diferencia entre puntero y valor. Los valores de las direcciones de los operandos se denominan punteros (porque su valor est "apuntando" al lugar donde est almacenado el dato). Entre otras cosas, esto implica que mientras se est procesando una funcin tal como _add(x,y), otra tarea puede estar modificando los valores contenidos en las direcciones apuntadas por x e y, lo cual no siempre es deseable. 2) Cmo opera el stack El stack es un espacio particular de la memoria del sistema. Al stack se lo llama pila LIFO (Last In- First Out, el ltimo en entrar, el primero en salir) y es igual a tener una pila de diskettes: si quiero sacar alguno, lo ms sencillo es quitar primero todos los de arriba. El funcionamiento del stack se rije por el par de registros SS:ESP (Stack Segment : Extended Stack Pointer), que apunta a la ltima direccin ocupada por el stack. El puntero al stack se decrementa a medida que el stack se va llenando (porque a medida que crece el stack va ocupando posiciones de memoria cada vez ms bajas) e inversamente el puntero crece a medida que el stack se vaca. La instruccin para cargar al stack con parmetros es PUSH, mientras que su inversa es POP. Al producirse una interrupcin o un llamado a subrutina, se coloca automticamente la direccin de retorno (y en ocasiones las flags) en el stack, las que se restauran con la instruccin POP.

Supongamos que en el momento antes de una operacin PUSH AX, que pone el contenido de AX en el stack, el par SS:SP apunta a 1800:FFEE, y que el contenido de AX es 1234h. Luego del PUSH, la direccin de memoria 1800:FFED contendr el valor de AH, o sea 12h, la direccin inmediata inferior 1800:FFEC contendr el valor de AL, o sea 34h y el puntero SS:SP tendr igual valor (1800:FFEC). varA varB varC DW DW DW ;direccion de almacenamiento: DS:2000 ;direccion de almacenamiento: DS:2002 ;direccion de almacenamiento: DS:2004

7 11

A partir de la DS:2000 encontramos (se lista hasta la DS:2007): DS:2000 00 00 07 00 11 00 xx xx Supongamos que SS:SP vale SS:FF2E, LEA PUSH LEA PUSH LEA PUSH AX, varA AX AX, varB AX AX, varC AX ;carga en AX la direccion 2000 ;carga en SS:FF2C el valor 20 00 ;carga en AX la direccion 2002 ;carga en SS:FF2A el valor 20 02 ;canga en AX la direccion 2004 ;carga en SS:FF28 el valor 20 04

El stack pointer ahora esta en FF28. Listemos desde SS:FF28 hasta FF2F: SS:FF28 04 20 02 20 00 20 xx xx Notemos que la carga en el stack sigue la convencin Intel, poniendo el byte menos significativo en la direccin ms baja y el ms significativo en la direccin ms alta. 3) Estructuras de datos. Con todo, hay veces en las que conviene no hacer referencia a variables aisladas sino manejarlas en grupo, lo que se denomina estructura. Una estructura de datos se compone de miembros los que pueden ser de distinta longitud o naturaleza. Cuando el programa se refiera a la estructura lo har usando un puntero a la estructura que no es nada ms que la direccin de memoria donde comienza. Veamos un ejemplo simple. En un programa encontramos que hacemos constante referencia a la lectura de disco, y por lo tanto decidimos crear nuestra propia estructura para facilitar la escritura del programa. Notemos que los sistemas operativos tienen definidas estructuras para usos especficos. Utilizando lenguaje Assembly, una estructura ejemplo se puede definir como: lectura disco sector head reser track cant bufoff STRUCT db db db db dw dw dw 0 1 0 0 numero de disco numero de sector numero de cabeza reservado

0000 numero de track 0001 cantidad de sectores a leer 2000 segmento del buffer de lectura 0000 offset del buffer de lectura

bufseg dw

lectura ENDS En las estructuras de datos propias, podemos usar nuestra inmaginacin con total libertad, pero las estructuras que necesita el sistema operativo debemos ajustarnos completamente a las posiciones y longitud de los parmetros y disponerlos de la misma manera en que el sistema operativo espera encontrarlos. Hemos reservado un byte para futuros usos y para que los valores de dos bytes se alinien con direcciones pares de memoria. Si por ejemplo el valor del puntero "lectura" fuese 2800, encontraramos que: la direccin DS:2800 almacena el nmero de disco la direccin DS:2801 almacena el nmero de sector la direccin DS:2802 almacena el nmero de cabeza la direccin DS:2803 es un byte reservado para uso futuro la direccin DS:2804 almacena en dos bytes el numero de track la direccin DS:2806 almacena en dos bytes la cantidad de sectores leer la direccin DS:2808 almacena el segmento del buffer de lectura la direccin DS:280A almacena el offset del buffer de lectura. Si dentro del programa queremos hacer referencia por ejempo a la cabeza lectora, podemos poner: MOV lectura.head,5 seleccionar la cabeza lectora 5

El compilador buscar la direccin de la estructura "lectura", en nuestro ejemplo DS:2800. Luego buscar el elemento "head", que por la definicin de la estructura sabe que ocupa un byte y que es el tercero. Por lo tanto el compilador generar una instruccin apropiada para que se almacene el valor 5 en la direccin de memoria DS:2802.

PASO DE PARAMETROS EN LOS PROGRAMAS

Parte II: COMO PASAN LOS PARAMETROS A LAS FUNCIONES API DE WINDOWS

PARAMETROS PARA FUNCIONES API Windows sigue las nuevas reglas sobre paso de parmetros tal como se ha visto en el mdulo anterior: pasa punteros en el stack y tambin hace uso de estructuras cuando esto resulte adecuado. Para cualquier funcin API, los parmetros se almacenan en el stack en el orden inverso al que figuran en la declaracin. Igualmente, cualquier valor de retorno vendr en el registro EAX si se trata de un entero (si es mayor, ser un puntero a una cadena o a una estructura). Tomemos un ejemplo del API Help de Microsoft o del muy gil y condensado similar elaborado por Sync+, por ejemplo la funcin _lwrite: definicin de funcin API _lwrite extrada de las API Help
The _lwrite function writes data to the specified file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the WriteFile function. UINT _lwrite( HFILE hFile, // handle to file LPCSTR lpBuffer, // pointer to buffer for data to be written UINT uBytes // number of bytes to write );

OK, qu hay que hacer para llamar esta funcin? Supongamos que tengo abierto previamente un archivo cuyo handle es 3CCh, en el cual quiero escribir 1000h bytes desde el buffer que est en la direccin 40023300h MOV PUSH LEA PUSH MOV PUSH CALL CMP JNZ EAX,1000 EAX EAX,lpBuffer EAX EAX,EBX EAX _lwrite EAX,1000 _error ;cantidad de bytes a escribir ;DIRECCION del buffer de escritura ;normalmente el handle se guarda en EBX ;si se acaba de abrir el archivo ;debe estar en memoria el Kernel32.dll ver si se transfirierorn todos los bytes

Ntese que si se ponen los parmetros en el stack en el orden inverso a lo que se declaran, significa (por ser el stack un elemento LIFO) que sern extrados por la funcin en el orden en que estn declarados. Aqui hay dos detalles que considerar: primero el hecho de que el orden de declaracin de parmetros en Pascal es inverso al de C. Esto no presenta ningn problema, porque el compilador llama siempre a los parmetros en el mismo orden (porque en realidad pasa a lenguaje de mquina y en ese nivel no puede haber diferencias en el orden), de manera que de esto se encarga el compilador y basta con recordar que es inverso

al que aparecen en las API Help. El segundo detalle es ms interesante. Mientras Pascal vuelve de la funcin API con el stack ya equilibrado, en el lenguaje C es el programador el que tiene que encargarse de esa tarea. Desde el punto de vista de la ingeniera inversa, si nosotros seguimos una funcin API y vemos que termina en RET (4*n) donde n es el nmero de parmetros, es seguro que el compilador es estilo Pascal, mientras que si vemos que luego de retornar de la API, el programa acomoda el stack haciendo POPs o ADD ESP,(4*n), se trata de un compilador C. Pongamos como ejemplo la funcin vista _lwrite. Tiene tres parmetros y por lo tanto 4*n=0Ch, por lo tanto, si vemos algo asi: CALL ADD _lwrite ESP,0C

se tratar muy probablemente de un ejecutable generado por un compilador C. En cambio, en Pascal la misma funcin _lwrite finaliza con un RET 0Ch y por lo tanto no es necesario el ADD posterior. NOTA PARA EL PRINCIPIANTE
Es muy, pero MUY importante que el stack pointer quede siempre equilibrado entre el valor que tena antes de ingresar los parmetros al stack y luego de ejecutada la funcin API. Y es fcil deducir por qu: si asi no fuera, la instruccin RET siguiente a producirse el desequilibrio del stack retornara a un lugar que en realidad lo ms probable es que sea un parmetro en lugar de cdigo. Esto es igualmente vlido si una funcin es llamada con una cantidad de parmetros distinta a la que exige su definicin.

Junto con las definiciones de funcin y los parmetros con los que hay que llamarlas hay en la API Help menciones a flags que controlan la operacin de la funcin. Quizs un funcin emblemtica en este sentido sea CreateWindow, que tiene una gran cantidad de banderas (por ejemplo, WS_BORDER, que cuando est activada hace que la funcin cree una ventana que tiene una linea fina como borde). Durante la construccin del programa, el compilador se encargar de activar el bit correspondiente a WS_BORDER, dentro del parmetro dwStyle. Sin embargo, cuando decompilamos un programa por ejemplo con el W32DASM, nos encontramos con instrucciones como PUSH 10830041. Esto corresponda posiblemente a parmetros como el dwStyle, que controlan mediante bits individuales el comportamiento de la funcin. Supongamos que determinamos que el anterior push corresponde efectivamente al parmetro dwStyle, por ser el antepenltimo en ser cargado en el stack. Cmo saber cules son las banderas que el programador quiso activar?. Hay un slo camino, que es seguir los pasos que dio el compilador al generar el ejecutable. En esto nos ayuda el archivo windows.inc, que viene con el compilador (tambin disponible en el ensamblador MASM32). Abrimos ese archivo (676 kB de definiciones!). Comenzamos a buscar WS_BORDER y encontramos : WS_BORDER equ 00800000h esto significa que tiene activado el bit 23, Bingo! el push que estamos considerando lo activa y por lo tanto vemos que la ventana tendr borde con linea fina. De la misma manera tenemos que proceder con todos los bits de todos los parmetros que modifican la funcin de acuerdo con el estado de las banderas. Arduo? Si, nadie dijo que esto sea tarea fcil, slo podemos afirmar que no es muy complicada, slo extensiva. Por lo general no es necesario comprobar el 100% de las flags (lo que nos llevara a perder un par de horas en una funcin como CreateWindow). Tenemos que concentrar nuestra atencin en el problema que queremos resolver, por ejemplo, si la ventana de entrada de claves est inicialmente maximizada, hay que ver aquellas llamadas a CreateWindow con la flag WS_MAXIMIZE activada.

NOTA PARA EL PRINCIPIANTE


Es importante reconocer algunas caractersticas en las notaciones empleadas para nombrar funciones API. Las que incluyen una A o W final son funciones de 32 bits con un equivalente de 16 bits que no lleva esa letra. Por ejemplo

CreateWindow es de 16 bits, mientras que CreateWindowA es de 32 bits, strings de un byte CreateWindowW es de 32 bits, string de 2 bytes Cuando una funcion termina en Ex tiene capacidades extendidas sobre la de igual nombre pero sin el Ex (y tambin algn parmetro adicional para controlar esa capacidad). Por ejemplo: CreateWindow: tiene 11 parmetros, en cambio CreateWindowEx :12 parmetros: se agrega dwExStyle que controla el estilo extendido

CAPITULO V

GLOSARIO DEL CRACKING

AND

Operacin binaria cuyo resultado es 1 slo si ambos operadores son 1. Tambin es el mnemnico de una instruccin de procesador que consiste en realizar la operacin binaria bit por bit entre los operandos declarados en la instruccin. Por ejemplo, AND EAX,EBX instruye al procesador a realizar una operacin binaria AND bit por bit entre los registros EAX y EBX y almacenar el resultado en EAX. Lenguaje de programacin que permite el ms absoluto control sobre el procesador. Es fundamental un aceptable manejo de este lenguaje a la hora de hacer ingeniera inversa sobre un target, ya que por lo general no se dispone del programa fuente y debe utilizarse una dead list. Literalmente "puerta trasera", es un mecanismo que se instala en los sistemas a los que un hacker accede, con el objeto de sistematizar y ocultar futuros accesos. El horrible aviso comercial que encabeza toda pgina de un sitio de hosting gratuito Se deriva de "Basic Input - Output System" (sistema bsico de entrada-salida), por referirse de algn modo a la interface necesaria entre el sistema operativo y el hardware. Aunque los dispositivos y el procedimiento utilizado para controlarlos puede diferir en cada PC, los sistemas operativos tienen reglas fijas para utilizar los recursos. Estas reglas son las funciones BIOS y la sintaxis empleada para convocarlas. Cuando por ejemplo, corremos (es un decir) el Notepad de Windows, hay tres capas de software una dentro de la otra: La exterior es la aplicacin Notepad, la intermedia es el sistema operativo (Windows en este caso) y la ms interna el BIOS. Asi, ste avisa a Windows que el usuario apret una tecla, Windows le avisa a Notepad, y ste toma alguna accin al respecto, que puede ser algo tan simple como poner el caracter en el buffer de edicin, y avisar a Windows que tiene que sacar el caracter por pantalla, para lo cual este avisar al BIOS de qu forma debe representarlo. Esta estructura en capas puede parecer compleja pero es la nica manera de permitir que distintos fabricantes puedan hacer PCs para un mismo sistema operativo o que una misma PC pueda correr distintos sistemas operativos. En nuesta pgina sobre interrupciones hay un breve listado de las interrupciones utilizadas por el BIOS y por el DOS La palabra se deriva de "Binary unIT" (unidad binaria). El ancho de las palabras binarias se especifica en bits: p.e. decimos que los registros de los procesadores actuales es de 32 bits y que el del (hoy) futuro Merced es de 64 bits. Esto da una idea de potencia de clculo, ya que para obtener el mismo resultado para una operacin suma simple como ADD EAX,ECX el procesador 8088 de las primeras PCs tena que hacer dos sumas sucesivas porque el ancho de palabra era de 16 bits. Que sigue las reglas del lgebra de Boole o que opera con valores binarios de un bit. Funcin Booleana: Aquella cuyo resultado puede ser cierto o falso (1 o 0), por ejemplo comprobar si durante un acceso a disco se produjo un error o no. Area de memoria que se utiliza para realizar operaciones en las que un dispositivo deja datos a los que el programa consulta asincrnicamente. El bffer ms fcil de entender es el de teclado: entre el BIOS y el sistema operativo leen el teclado y dejan en el bffer el cdigo de las teclas apretadas. El programa luego va a esa rea de memoria, normalmente mediante funciones del Sistema Operativo, para leer los cdigos y descargar el bffer (le saca los caracteres que va leyendo). Esto permite, por ejemplo, seguir escribiendo mientras se produce un acceso a disco sin que se pierdan caracteres, ya que si bien el programa debe esperar a que termine la operacin de disco, la funcin BIOS de lectura de teclado es llamada por la interrupcin de hard y es atendida con mayor prioridad. El bffer para accesos a disco es el rea de memoria destinada a recibir los datos que se leen o en donde el programa escribe los datos que se deben transferir al disco.

ASSEMBLY

BACKDOOR

BANNER

BIOS

BIT

BOOLEANO

BUFFER

BYTE

Palabra de 8 bits. Con 8 bits se pueden representar 256 (=28) nmeros decimales distintos desde 0 (todos los bits en cero) hasta 255 (todos los bits en 1)

CARRY

Flag de los procesadores que indica un desborde aritmtico que debe ser tenido en cuenta cuando se opere el dgito siguiente. Es el "me llevo uno" que decimos cuando hacemos una suma decimal y una columna nos da 10 o ms: lo que estamos haciendo es un "carry" (llevarse) a la siguiente posicin decimal. En un hipottico procesador de un bit de ancho de palabra, si sumamos 1+1, el resultado es 0 y se enciende la bandera de carry porque en realidad en binario la suma de 1+1 nos da 10 (que es igual a 2 decimal), el 0 es el resultado de la posicin binaria y el 1 debe sumarse a los operandos de la siguiente posicin. Adems, por convencin se emplea la flag de carry para indicar el resultado de una funcin booleana, como por ejemplo averiguar si existi error en un acceso a disco. Aunque esto es slo una convencin que puede ser cambiada por el programador, por lo general si el carry vuelve en 0, no hubo error. De "to crack": abrir, hacer crujir. Desactivar una proteccin de software, sea anticopia o de limitacin de uso. En el ambiente de hacking se usa "crackear" como sinnimo de entrar en una computadora ajena para reventar el contenido. Literalmente "Listado Muerto", con lo que el lector puede figurarse por qu a pesar de estar orgullosos de nuestro idioma castellano, en este caso preferimos expresarnos en ingls. Es el listado que obtenemos procesando un archivo ejecutable con un desensamblador: una serie de instrucciones en lenguaje Assembly que es una imagen "esttica" del ejecutable en un momento en que no est corriendo (de ah lo de listado muerto). Es muy til para la ingeniera inversa de programas y un poco menos til desde el punto de vista del cracker. Quizs por esto, los grandes gurs como ORC+ y fravia+ aconsejan este mtodo (que consideran mucho ms sutil) antes que el SoftICE. Significa "Depurar", aunque traducido literalmente es "desenbichar". Crase o no, la historia cuenta que all por los finales de la pasada dcada del 40 un prototipo de computadora que funcionaba con rels electromecnicos tuvo un fallo y se descubri que haba sido provocado por una polilla (bug) cada entre los contactos de un rel.

CRACKING

DEAD LIST

DEBUG

El depurador ms elemental existente viene incluido en el Sistema Operativo y se llama precisamente Debug.exe (est en la carpeta Command del directorio Windows o, para los ms viejos, en el directorio DOS). Si bien no es gran cosa, nuestra recomendacin es aprender el funcionamiento de Debug porque permite probar en forma inmediata el funcionamiento de partes pequeas de cdigo y porque permite ver de cerca la operacin del procesador y visualizar sus registros ms importantes. En esta pgina, hay un aceptable tutorial sobre el uso del Debug. Valor que se toma por defecto (es decir, en caso que no se suministre un valor para una determinada entrada, esta asume el valor por defecto). Por ejemplo, si no indicamos otra cosa, la entrada estndar de un procesador de textos es el teclado, pero eso cambia si le decimos al procesador que abra un archivo. En DOS se utilizan los redireccionadores para cambiar la entrada y salida por defecto: El smbolo "<" reasigna la entrada y el ">" la salida. Por ejemplo, la orden: TYPE DATA.TXT > LPT1 indicaba al DOS que enve los caracteres de salida de la orden TYPE no a la pantalla (salida estndar) sino al puerto de la impresora.

DEFAULT

DESENSAMBLADOR

Programa que permite a partir del ejecutable de una aplicacin obtener un listado en lenguaje Assembly de esa aplicacin. Dispositivo de hardware que se conecta en un puerto de la PC (normalmente el de la impresora, pero tambin los hay para puerto serie y teclado) y que contiene claves o algoritmos para indicarle a un programa que est autorizado para correr. Se lo llama tambin hardkey (llave de hard) y pronto ser denominado "ese pedazo de plstico intil que habra que tirar", ya que como se puede leer en la seccin Proteccin por hardkey de nuestro sitio, es una de las protecciones con mayor cantidad de puntos dbiles. Un cracker decente no tiene dificultades para vencerla. Con todo, an hay programas muy importantes y caros (AutoCAD por ejemplo) que la utilizan. Smbolo que identifica un operador de 32 bits (doble-word) Con una DWORD pueden representarse nmeros desde el 0 hasta 4.294.967.295 (=231) (Assembler) Es el compilador de programas escritos en lenguaje Assembly, vale decir que toma como entrada un archivo de texto (programa fuente Assembly) y entrega como salida un ejecutable. Complementando el lenguaje Assembly, existen rdenes llamadas "Directivas de ensamblador" que son procesadas (aunque no generan cdigo ejecutable). Ejemplos de directivas son SEGMENT (define la utilizacin de segmentos que har el programa) y MACRO, til a la hora de evitar reescribir partes de cdigo que se repiten varias veces a lo largo del programa fuente. Revistas baratas confunden los

DONGLE

DWORD

ENSAMBLADOR

trminos Assembly y Assembler, usndolos en forma indistinta o equvoca. Operacin del procesador transparente para el programador que consiste en ir a buscar (fetch) la prxima instruccin a ejecutar. El proceso en los procesadores es algo ms complicado debido al cache L1 de instrucciones, al doble thread y a la prediccin de las bifurcaciones. La traduccin literal es "bandera", aunque sera ms preciso decirle "sealador". Es un operador booleano que indica alguna situacin, que puede ser carry, overflow, error, igualdad, etc. Aunque el largo til es un bit, algunos programadores suelen utilizar enteros para almacenar variables booleanas que sealan la ausencia o presencia de algo, en cuyo caso normalmente slo cuenta el bit menos significativo de la word o dword (se utiliza la comparacin con cero luego de un TEST o AND). Las flags de los procesadores X86 estn descritas en esta pgina (Programa) Listado original de un programa, tal como fue escrito por el programador. Es un archivo de texto. Actividad consistente en acceder sin autorizacin a partes vitales de computadoras ajenas. Literalmente significa "manija" y es muy descriptivo de la funcin que realiza. Los objetos que maneja un programa tienen atributos muy variados y sera muy pesado por ejemplo en el caso de una ventana dar instrucciones del tipo: "muestre un botn con la leyenda OK en la ventana Primera_ventana, que est en la posicin (106,190) cuyas dimensiones son (90,75) con color de fondo 225, ttulo ....etc, etc". En lugar de eso, al definirse la ventana se crea una estructura que contiene todos esos datos y se le da un handle (que viene a ser como un nick de la ventana). Ese handle es como un puntero lgico al que el programa debe hacer referencia cuando quiere operar con el objeto. El concepto de handle se haba implementado en el DOS slo para el manejo de archivos. Cuando se crea un objeto (por ejemplo al abrir un archivo), la funcin de creacin devuelve un handle: INT handle_archivo handle_archivo = open (nombre_archivo, modo) (en la realidad el proceso es un poco ms complejo porque antes de asignar el valor a la variable handle_archivo hay que verificar si la funcin OPEN no tuvo errores) Cuando no se posee un servidor web propio se debe recurrir a algun otro para que hospede (host) nuestras pginas. Hay servidores pagos y otros gratis que ofrecen hosting a cambio de que cada pgina tenga un aviso publicitario cuyo rdito queda para el host. Sentencia bsica en lenguaje Assembly. En el archivo fuente debe ir una sentencia por lnea. Consta de tres partes: el mnemnico que identifica el tipo de operacin (AND, ADD, MOVSB, etc), los operandos y el comentario. Hay instrucciones que no requieren operandos, otras que necesitan uno slo y otras que precisan dos (fuente y destino). El comentario es siempre opcional y debe obligatoriamente comenzar con punto y coma. La sintaxis es: MNEMONICO destino,fuente ;comentario

FETCH

FLAG

FUENTE HACKING

HANDLE

HOSTING

INSTRUCCION

Notar que tanto destino como fuente son utilizados como fuente de datos durante la ejecucin de la instruccin, pero destino adems es el receptor del resultado. La posicin de los operadores es fija, siempre destino es el primero despus del mnemnico. Mnemnico de la instruccin de salto incondicional. Hay dos tipos, segn el salto se realice dentro del mismo segmento o a otro segmento. Consulte en esta pgina en qu consiste la segmentacin. Para identificar esta situacin, se antepone NEAR o FAR a la direccin de salto. NEAR es la opcin default. En este caso, la instruccin completa ocupa 3 bytes: uno para el opcode (0E9h) y dos para el offset, que es un entero de 16 bits, lo que permite saltar 32767 posiciones hacia adelante o 32768 posiciones hacia atrs. El offset se cuenta a partir del contenido del registro IP al momento de finalizar la ejecucin de la instruccin. Un offset 0 es igual a tres NOPs consecutivos, ya que el procesador ejecutar la instruccin siguiente. Un offset -3 es un lazo infinito, ya que siempre se salta al inicio del mismo JMP. Los saltos condicionados son similares a los NEAR. En el caso de JMP FAR, si el opeando es inmediato la instruccin ocupa 5 bytes: uno del opcode (0EAh), dos de offset y dos finales para el segmento. En este caso, el offset se cuenta no desde el contenido del registro IP, sino desde el inicio del segmento al que se salta. Si el operando es una posicin de memoria, el opcode ocupa dos bytes (0FF2Eh) y dos bytes ms el offset de la posicin de memoria donde est almacenado el vector con la direccin de destino del salto.

JMP

KERNEL

Literalmente "pepita". Ncleo de un sistema operativo, por extensin de la denominacin usada para el Unix. En el Kernel estn las funciones bsicas del sistema operativo como el manejo del sistema de archivos, en contraposicin con el Shell que es la parte encargada de interpretar los comandos. Smbolo con que se representa a las instrucciones en lenguaje Assembly. En esta pgina hay una tabla conteniendo los mnemnicos y una breve descripcin de la operacin que realiza cada instruccin del procesador 8086. Ejemplos de mnemnicos son JMP, NOP, JZ, AND, MOVSB, etc. Mnemnico de la instruccin que realiza el complemento a dos del operando. Un complemento a dos equivale a un cambio de signo de un nmero entero. El operando puede ser un registro o una posicin de memoria, tanto de 8, 16 o 32 bits. Mnemnico de la instruccin que realiza el complemento a uno de un operando. Equivale a cambiar todos los ceros en unos y viceversa. Literalmente significa "desplazamiento". Consulte cmo operan los offset en una direccin segmentada o cmo se calcula la direccin de destino de un salto en base al offset indicado en la instruccin. Nmero binario de uno o dos bytes que es interpretado como una instruccin por el procesador. Opcodes y los mnemnicos son dos codificaciones distintas de una misma instruccin, una leble por un procesador y otra por un humano. Valores con los que se efectuar la operacin definida por el mnemnico de una instruccin. Los operandos de la mayora de las instrucciones son fuente y destino. Las operaciones unarias (NOT por ejemplo) tienen un solo operando. Mnemnico de la instruccin que realiza una combinacin lgica O de los operandos, que consiste en dar un 1 por resultado si alguno de los operandos es 1. Flag de procesadores X86 que se prende cuando el resultado de una operacin aritmtica no cabe en el operando designado como destino (por ejemplo en un MUL cuando la mitad superior del resultado tiene algn bit encendido). Supongamos sumar 07FFF h + 2 = 8001h. El resultado parece correcto y lo es si los nmeros no tienen signo, pero si los nmeros son enteros con signo, la suma de 32767+2 nos da como resultado -32767, cuando la realidad es que el resultado es 0001 y un carry a la palabra de orden superior (carry que en decimal vale 32768 unidades). Por lo tanto, en este caso tambin se activa la flag OVF para prevenir al programador de esta situacin. Programa de encriptacin que utiliza el mtodo de dos claves (una pblica y otra privada) para mantener la confidencialidad de los documentos intercambiados a traves de un medio tan promiscuo como internet. Es el encriptador por default en el ambiente underground por ser gratis y tener un algoritmo muy fuerte. Desde la versin 5 en adelante todo esto ha cambiado, cuenta con el auspicio de una empresa comercial y con una clave universal que permite abrir cualquier mensaje. Mnemnicos para sacar y poner objetos en el stack. El objeto puede ser el contenido de un registro o una posicin de memoria. Literalmente "puntero". Es un valor que est sealando una posicin en memoria. Los procesadores X86 tienen dos registros SI y DI (ESI y EDI para 32 bits) que tienen funciones especiales como punteros, lo que es muy til para el manejo de strings (ms sobre esto en nuestra pgina sobre strings). En lenguajes de alto nivel (como C) un parmetro a funcin no se pasa como un valor sino como un puntero que direcciona la posicin de memoria en donde est almacenado el parmetro. Vea adems PTR en sta misma pgina. "Program Segment Prefix" o Prefijo de segmento del programa, propio del DOS. Es un rea de memoria de 100h (256) bytes que se crea en el momento en que el intrprete de comandos lanza un programa (para decirlo de otro modo, cuando el command.com ley nuestro comando "edlin data.txt" y carga en memoria al fabuloso edlin.com para procesar al archivo data.txt).

MNEMONICO

NEG

NOT

OFFSET

OPCODE

OPERANDOS

OR

OVERFLOW

PGP

POP, PUSH

POINTER

PSP

El PSP preceder en memoria a edlin.com, ya que se cargar a partir de la direccin 0 del segmento CS, mientras que edlin lo har a partir de CS:100. En esos 100h bytes se guardan varios valores, entre los cuales est una parte del buffer de teclado que contiene el argumento (data.txt en este caso), y un procedimiento para cerrar el programa cuando edlin nos haya hartado (a los 22 segundos, si el lector es de la poca de los ancestrales DOS 3.1, estoy seguro que me comprender)

PTR

Directiva que sirve al compilador Assembly para saber que no es un dato directo sino un puntero. Pueden anteponerse BYTE, WORD o DWORD para establecer el largo de la palabra apuntada: CMP WORD PTR [SI],2Fh ; compara la word en memoria apuntada por SI y SI+1 con 002Fh Lugar de almacenamiento extraordinariamente veloz que tiene el procesador: se lee o escribe en un ciclo (esto no necesariamente significa que la instruccin que lo hace se procese en un ciclo). Hay registros accesibles al programador y otros que no (el lector encontrar aqu una buena descripcin del modelo 8086 ). Estos ltimos aparecieron a partir del 80486 y se emplearon entre otras cosas como contadores y para la prediccin de saltos. El direccionamiento "registro" significa que uno (o dos) de los operandos es un registro interno del procesador. Lamentablemente en castellano se usa la misma palabra para designar un registro de procesador que para uno de una base de datos (que en ingls se dice RECORD). Procedimiento que consiste en aplicar ingeniera inversa a una pieza de software. A diferencia del cracking, que slo busca permitir la utilizacin del programa sin pagar por l, el reversing busca comprender el programa a tal punto que pueda ser posible su mejoramiento o potenciacin. La memoria segmentada es un resabio del DOS, que qued "pegado" con eso por haber nacido para procesadores de 16 bits (y que por lo tanto manipulaban hasta 65536 direcciones). Para salvar el problema se ide la segmentacin que consiste en dividir la memoria en pargrafos de 16 bytes cada uno. Con esto estamos pasando de una direccin de 16 bits a una de 20 bits, que ya puede direccionar 1MB. Para hacer esto se utiliza un registro de segmento y otro de offset. Los X86 tienen cuatro registros de segmento: DS (data), ES (extra), CS (code) y SS (stack). Ms sobre segmentacin en esta pgina SEGMENT es tambin una directiva para el ensamblador que informa sobre la forma en que se deben asumir los segmentos durante la compilacin.

REGISTRO

REVERSING

SEGMENT

SERIALZ

Nmeros de serie utilizados para activar programas sin necesidad de pagar por ello. El sitio ms famoso al momento es el de Oscar As como conocemos lo que es el Kernel , exterior a l esta el Shell, que es el intrprete de comandos de Unix. Hay varios tipos, cada uno con mayores o menores restricciones (restricted Shell, Bourne Shell, etc), que el administrador del sistema otorga a los usuarios segn su categora. Por extensin, intrprete de comandos de cualquier sistema operativo). El stack es una zona de memoria para ser usada por el procesador en las llamadas a procedimiento (ah se guarda la direccin de retorno) y para almacenamiento de variables temporales (como el valor de un registro que se quiere conservar). Como el stack se va ocupando desde posiciones altas hacia las ms bajas, el registro SP (stack pointer; que en los procesadores de 32 bits -80386 en adelante- se llama ESP) se va decrementando por dos en cada almacenamiento de word y en 4 por cada almacenamiento de dword. El stack pointer seala la ltima (la ms baja) posicin ocupada por el stack. El segmento ocupado por el stack est apuntado por el registro SS (stack segment). Literalmente "ristra", traducido normalmente como "cadena", es una sucesin de valores, normalmente, aunque no necesariamente, caracteres de un byte cada uno. Lea tambin el tutorial sobre funciones para manejo de strings Objetivo, programa sobre el que se realizar un crack o una operacin de ingeniera inversa. Mnemnico de una instruccin de procesador que consiste en realizar un AND lgico entre los dos operandos de la instruccin, modificando las flags de cero, paridad y signo. Ninguno de los operandos cambia. Es muy comn usarla para verificar si el valor booleano retornado por una subrutina es cero o no. Flag del procesador que si est encendida provoca que el procesador ejecute una INT3 despus de cada instruccin. La utilizan los depuradores para posibilitar la ejecucin del comando "step" (ejecucin paso a paso). Programas o sitios crackeados, disponibles en Internet. Mnemnico de la instruccin Exclusive-OR, que consiste en complementar en el operando destino los bits cuya posicin coincida con los "unos" del operando fuente. Modalidad de cracking que consiste en "presentir" cul fue la intencin del programador cuando ide una proteccin y que debemos ORC+. Los budistas Zen sostienen que si uno "siente" a la presa, no es

SHELL

STACK

STRING

TARGET TEST

TRAP

WAREZ XOR ZEN

necesario verla, la flecha se disparar del arco en el momento preciso. Aunque es ms rpida, slo ser efectiva si el cracker tiene una buena experiencia en su oficio.

CAPITULO VI
1. Introduccin a numeracin binaria y hexadecimal

En general, la matemtica diaria es base 10 (decimal), aunque la tendencia de los constructores de


PCs fue usar base 2 (binario). El binario fue la eleccin simplemente porque OFF y ON son trminos fciles en electrnica y este modelo encaja bien con 1's y 0's. En algn momento, alguien decidi que continuar con numeracin binaria era algo tedioso para los humanos y se propuso que los nmeros se vean parecidos a los de la aritmtica decimal, pero conservando la progresin con potencias de 2 para que la conversin a binario sea fcil. De esta forma se populariz el hexadecimal (base 16). Qu tiene esto que ver con crackers o programadores assembly? TODO. Si no se comprende cmo operar con hexadecimales y cmo convertir entre binario y hexa, es imposible depurar (reversar) cualquier programa. En cualquier sistema de numeracin, siempre se sigue esta simple regla: en una base B, los dgitos se numeran desde cero hasta B-1 Que significa lo anterior?, por ejemplo que en base 10 tenemos diez dgitos, del 0 al 9. En binario tenemos slo dos: 0 y 1, y para base 16 (hexa) tenemos 16 dgitos. Por simplicidad, se usan los nmeros del 0 a 9 y las seis primeras letras del alfabeto. 0123456789ABCDEF (estos dgitos valen 0-15 al convertirlos al sistema decimal) la cuenta es similar a la del sistema decimal: ... E F 10 11 12 ... 18 19 1A 1B 1C 1D 1E 1F 20 21 22 ... 10 en hexa es 16 decimal, 20 hexa es 32, 30h es 48, 40h es 64 etc. Una cuenta en sistema binario sera como sigue: 0 1 10 11 100 101 110 111 1000... Asi 10 (en cualquier base) siempre es igual a B, la base misma - Equivale a decir que 10 (binario) is 2 decimal, 10 (octal) es 8 decimal, etc Bien, si yo tuviese 16 dedos podra sacar la cuenta como lo hacen los nios, pero como no los tengo, cmo calcular cunto es A9h en base 10? Ya sabemos que base 16 se amolda a potencias de 2, lo que no es difcil de manejar. Una vez que uno aprende a convertir un nmero a binario, es fcil cambiar de base a cualquier nmero, hacindolo en dos etapas: primero se convierte de una base a binario y luego de binario a la otra.

Conversin de Decimal a Binario


A esto me gusta llamarlo 'matemtica del resto'. Bsicamente, en lugar de una suma repetida, contando hasta un dgito hexa, usaremos divisin repetida para acelerar el proceso.

Nuestros amigos DIV y MOD


En computacin, los datos se almacenan como nmeros enteros, ya sea como una larga serie de dgitos en cualquier base ms la ubicacin del punto decimal (o para hablar generalmente para cualquier base, el punto raz), o como partes de una fraccin (numerador, denominador y cantidad a sumar en tres partes separadas). Hay por cierto otros mtodos con nmeros imaginarios, pero esto cae fuera de los lmites de esta leccin.

Usando nmeros enteros, la divisin se hace tal como lo hemos aprendido en base 10, de a un dgito por vez y recordando el resto de cada etapa. Para cada operacin de divisin, tenemos 2 respuestas: el cociente (DIV) y el resto (MOD). Aunque estamos ms familiarizados con DIV, MOD tiene interesantes propiedades usadas en programas de computacin, especficamente en randomizacin y scroll de mens. Usaremos como notacin 47 MOD 4, o 47%4 cuando queramos decir "dividir 47 por 4 y obtener el resto", ya que el signo "%" se usa como smbolo para MOD en lenguajes de alto nivel como el C. para nuestro caso: 47/4 = 11, resto = 3 DIV = 11, MOD = 3 y tambin: 47%4 = 3 (47 MOD 4 es igual a 3) Con estos conocimientos podemos comenzar con la conversin de bases entre decimal y binario (no es tan feo, no se preocupe). Quisiera que primero conozca que 47 en binario es 101111. Ahora voy a mostrarle como deducirlo matemticamente. Bsicamente, dividimos en forma repetitiva nuestro nmero por la base binaria (2) y tomamos cada MOD (resto) como el prximo dgito binario. 47 / 2 nos d DIV=23 MOD=1, string binario = 1 23 / 2 nos d DIV=11 MOD=1, string binario = 11 11/2 nos d DIV=5 MOD=1, string binario = 111 5/2 nos d DIV=2 MOD=1, string binario = 1111 2/2 nos d DIV=1 MOD=0, string binario = 01111 1/2 nos d DIV=0 MOD=1, string binario = 101111 Note que el string se construye de derecha a izquierda, al revs de cmo uno lee. Esta es una caracterstica del sistema de numeracin arbigo que incrementa el valor de los dgitos de derecha a izquierda Esto puede parecer tonto en un principio, pero las mquinas requieren tal nivel de instruccin para hacer aquello que nosotros sabemos hacer desde hace tanto que olvidamos los basamentos de lo que es un nmero: supongamos el 2041; lo tomamos en su totalidad, pero sabemos muy bien que el 2 tiene mucho ms valor que el 4 o el 1. En cambio las computadoras requieren hacer esto de a pasos.

Escribiremos un programa en pseudocdigo (una mezcla de lenguaje cotidiano con lenguaje de computacin). Es de gran ayuda escribir en pseudocdigo antes de pasar el programa a un lenguaje concreto. Viendo nuestro anterior ejemplo, podemos determinar cundo se cumpli la operacin consultando si DIV = 0. Nuestro programa sera:
1. 2. 3. 4. 5. Obtener el valor DIV (del usuario o del mismo programa) Dividir DIV por 2, dejar el cociente en DIV y el resto en MOD Almacenar MOD como prximo dgito de un string RES Repetir las acciones 2 y 3 hasta que DIV = 0 (inclusive) Informar el resultado RES

Conversin de un nmero binario a hexadecimal Como 24 = 16 cada 4 dgitos del string binario, tendremos un dgito hexa. Notar que tambin aqu hay que ir de derecha a izquierda como en las operaciones con nmeros decimales. Usando nuestro ejemplo del 47: 101111 Lo separamos en grupos de a 4: 10 | 1111 Y ahora consultamos la siguiente tabla de conversin: 0000 = 0 ........ 1000 = 8 0001 = 1 ........ 1001 = 9 0010 = 2 ........ 1010 = A 0011 = 3 ........ 1011 = B 0100 = 4 ........ 1100 = C 0101 = 5 ........ 1101 = D 0110 = 6 ........ 1110 = E 0111 = 7 ........ 1111 = F Por lo que nuestro nmero (10 | 1111) , se convierte en: 0010 = 2h y 1111 = Fh por dems simple, 101111 es 2F en hexadecimal o, ms rigurosamente: 47 (dec) = 101111 (bin) = 2F (hex) Si por ejemplo quisisemos convertir a base octal, debemos separar de a tres bits, o sea que para el 47 decimal hacemos:

101 | 111 111 = 7 101 = 5 47 (dec) = 101111 (bin) = 2F (hex) = 57 (oct)

Ahora que usted conoce las relaciones entre las bases, le ser mucho ms fcil leer cdigo assembly, y posiblemente en un futuro prximo, comenzar a entender qu est leyendo

2. Se aprende mejor con ejemplos

Frecuentemente, los buenos ejemplos son breves y van justo al punto. Puede ser muy difcil para un programador assembly novato obtener alguna conclusin valedera de un programa largo e indocumentado (o malamente comentado) que parece ms una sopa de letras que cdigo. Estos ejemplos pueden cortarse y pegarse en sus propios programas. Se me ha preguntado recientemente cul es el mejor lugar para encontrar informacin sobre Assembly. Un lugar (mala respuesta) es Internet. Sin embargo, mi informacin favorita proviene de un medio ms tradicional: los libros. Y los mejores libros sobre Assembly son sin duda los ms viejos, los que muestran cmo optimizar cdigo de 8086. Yo prefiero comprar manuales de segunda mano por un dlar que contienen un tesoro en cdigo, siempre necesario, como por ejemplo el legendario manual de Peter Norton.

En las siguientes pginas veremos el cdigo necesario para realizar las siguientes funciones:
Operaciones con strings Mostrando Numeros en Assembly Operaciones con Archivos Search Funciones de Bsqueda Otros Cdigos tiles

Lo bsico con Strings


(HELLO WORLD) La primer cosa que un instructor de programacin debe mostrar es cmo sacar mensajes por pantalla (esto se denomina "representacin"). El mensaje ms popularmente usado es "Hello, World". Ahora mismo vamos a ver un par de formas de cmo hacerlo. No hay necesidad de entender ahora cmo funciona, sino cules son las reglas bsicas para su utilizacin en futuros programas. Tambin se mostrar como parte de un programa para que se vea lo fcil que es incorporar esta pieza de cdigo a otras de mayor tamao.

En DOS
Llamado a la Rutina:
message mov db 'hello world','$' dx,offset message

call

DisplayString

La Rutina: (Pequea porque DOS se encarga casi de todo)


; muestra strigs apuntados por dx usando: int 21h, ah=9 DisplayString: mov ax,cs mov ds,ax mov ah,9 ; Funcin DOS: mostrar display int 21h ; Llama la interrupcin del DOS ret

En BIOS
Otra manera es usar la interrupcin 10h del BIOS en lugar de la funcin 9 de la interrupcin 21h (DOS). El motivo para hacer esto es doble: por un lado, muchos de los programas a crackear no se apoyan en los simples mtodos del DOS y por otro, si no conocemos el BIOS, no podremos escribir cdigo para sistemas no-DOS como el UNIX. Llamado a la Rutina:
message mov call db'hello world','$' dx,offset message BiosDisplayString

La Rutina:
; muestra string apuntados por dx usando: int 10h, ah=14 BiosDisplayString: mov si,dx ; el bios necesita si en lugar de dx mov ax,cs ; usar segmento actual (de cdigo) mov ds,ax ; para los datos a ser mostrados bnxtchar: lodsb ; buscar el prximo carcter a mostrar push ax ; preservar ax de cualquier cambio cmp al,'$' ; marca de final de string? Jz endbprtstr Pop ax ; restaura ax Call BiosDisplayChar Jmp bnxtchar endbprtstr: pop ax ; limpiar ret ; Observe que usando el BIOS debemos mostrar de a un carcter por vez. BiosDisplayChar: ; muestra el caracter que hay en al Mov ah,0Eh ;Cdigo de la funcin disp-char de BIOS Xor bx, bx Xor dx, dx Int 10h ; Llamado a la funcion BIOS Ret

Aunque hay otras maneras de mostrar caracteres (por ejemplo la INT 21h, ah=02 imprime igualmente un carcter en la pantalla), por lo general todo el mundo usa la INT 10h funcin 0Eh aqu mostrada. El conocimiento de las interrupciones es muy til para el cracking .

Y LOS NUMEROS?
(Cdigo Assembly para mostrar nmeros en cualquier base) Llamado a la Rutina:
mov call ax, 0402h DisplayWord

La Rutina: ; muestra la Word que hay en AX


DigitBase dw 010h ; usando base 16 dgitos ;cambiar lo anterior por 10h por 0Ah para ver nmeros decimales DisplayWord proc near mov si,offset DigitBase mov di,offset TempNum NextDgt: xor dx,dx div si add dx,30h ; convertir a dgito ascii mov [di],dl dec di cmp ax,0 ; falta algn dgito? ja NextDgt inc di mov dx,di mov ah,9 int 21h ; mostrar string apuntado por DX (DOS) retn

DisplayWord endp
db 4 dup (20h) ; nmero mximo de dgitos db 20h db 24h,90h Con esto ltimo, reservamos espacio en memoria. Es para almacenamiento temporario del string a mostrar. TempNum

Ntese que en el ejemplo anterior podramos haber llamado a la int 10h del BIOS en lugar de haberlo resuelto con la funcin 9 de la Int 21h.

3. Algunos modelos tiles


Nota del Traductor: Los siguientes modelos contienen las directivas de ensamblador necesarias para poder compilar
exitosamente programas simples en lenguaje assembly. Pueden ser copiados y pegados como comienzo de edicin de un programa. Para que el principiante tenga una idea de la importancia de contar con estos modelos en lo que a ahorro de tiempo se refiere, le sugiero que trate de hacer uno que compile sin errores.

MODELO DE ARCHIVO .COM


;********************************************** ; ; MODELO DE ARCHIVO EJECUTABLE .COM (COM.ASM) ; ; Compilar con: ; ; TASM COM.ASM ; TLINK /t COM.OBJ

; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM ;---------------------; Zona para datos ;---------------------;---------------------MAIN_PROGRAM: ;--------------; Cdigo de programa ;--------------;--------------mov al, 0h ; cdigo de retorno 0 (0 = no error) exit_program: mov ah,4ch ; salir al DOS int 21h end start

MODELO DE ARCHIVO .COM #2 (ALTERNATIVO)


;********************************************** ; ; MODELO DE ARCHIVO EJECUTABLE.COM #2(COM_B.ASM) ; ; Lo incluimos para poderlo comparar con ; el modelo .EXE mostrado ms abajo ; ; Compilar con: ; ; TASM COM_B.ASM ; TLINK /t COM_B.OBJ ; ; +gthorne'97 ; ;********************************************** COM_PROG segment byte public assume cs:COM_PROG org 100h start: jmp MAIN_PROGRAM ;---------------------; Zona de datos ;---------------------;---------------------MAIN_PROGRAM: ;--------------; Cdigo de programa ;--------------;--------------mov al, 0h ; cdigo de retorno (0 = no error) exit_program: mov ah,4ch ; salir al DOS int 21h COM_PROG ends end start

MODELO DE ARCHIVO .EXE


;********************************************** ; ; MODELO DE ARCHIVO EJECUTABLE .EXE (EXE.ASM) ; ; Compilar con: ; ; TASM EXE.ASM ; TLINK EXE.OBJ ; ; +gthorne'97 ; ;********************************************** .model small ; normalmente small, medium o large .stack 200h .code EXE_PROG segment byte public assume cs:EXE_PROG,ds:EXE_PROG,es:EXE_PROG,ss:EXE_PROG start: jmp MAIN_PROGRAM ;---------------------; Zona de datos ;---------------------;---------------------MAIN_PROGRAM: ;--------------; Cdigo de programa ;--------------;--------------mov al, 0h ; cdigo de retorno (0 = no error) exit_program: mov ah,4ch ; salir al DOS int 21h EXE_PROG ends end start

MODELO DE ARCHIVO .EXE #2 (ALTERNATIVO)


;********************************************** ; ; MODELO DE ARCHIVO EJECUTABLE .EXE 2 (EXE2.ASM) ; (Comparar con el primer modelo .COM) ; Probado con TASM 4.1 ; Donado por Eyes22, Modificado para semejarse ; los otros modelos ; Compilar con : ; ; TASM EXE2.ASM ; TLINK EXE2.OBJ ; ; +gthorne'97 ; ;********************************************** ;dosseg ; directiva que es ignorada en tasm 4,

; descomentar en caso de errores .model small .stack 200h .data .code start: jmp MAIN_PROGRAM ;---------------------; Zona de datos ;---------------------;--------------; Cdigo de programa ;--------------;--------------mov al, 0h ; cdigo de retorno (0 = no error) exit_program: mov ah,4ch ; salir al DOS int 21h end start

Cita textual del libro Assembly Language for the IBM-PC

Programas COM: Hay dos tipos de programas transitorios, dependiendo de la extensin usada: COM y EXE. Recuerde que usamos DEBUG para crear y salvar un pequeo programa COM. Un programa COM es una imagen binario de un programa en lenguaje de mquina. El DOS lo carga en memoria en la direccin de segmento ms baja disponible, creando un PSP en offset 0. El cdigo, datos y stack se almacenan todos en el mismo segmento fsico (y lgico). El programa no puede superar los 64 kB menos el largo del PSP y dos bytes reservados en el tope del stack. Todos los registros de segmento se cargan con la direccin base del programa, el cdigo comienza en el offset 100h y el rea de datos sigue al cdigo. El stack est al final del segmento ya que el DOS inicializa al registro SP en 0FFFEh. Hello.asm Programa ejemplo "hello world" escrito en formato .COM Note que las directivas DOSSEG, DATA y STACK son innecesarias, y la directiva ORG (que inicializa al contador de direcciones en 100h) se antepone a toda instruccin assembly para dejar espacio para el PSP, que ocupa desde la direccin 0 hasta la 0FFh.
.model tiny .code org 100h maine proc mov ah,9 mov dx, offset helo_msg int 21h mov ax, 4c00h int 21h maine endp helo_msg db 'Hello, world!' '$' end maine

4. Desarrollo de programas (Se aplica para cualquier lenguaje)

Hace mucho tiempo


En una Galaxia no tan lejana Alguien invent el diagrama de flujo. Este dispositivo fue una sucia herramienta que requera nivel universitario para ser escrita, la entenda slo uno mismo y era como un enredo de espaghettis a la hora de usarse para dirigir la escritura de un programa.

Hace tambin mucho tiempo


En la tierra de la ficcin interactiva (Que puede muy bien estar en otra galaxia lejana...) Alguien ms se dio cuenta que diagramas de cajas simples mostrando la ubicacin en un fantasioso texto de aventuras permita un mapeado fcil y rpido que permita retomar el trabajo al tiempo, sin perder la ilacin debido a la simplicidad de las cajas y sus descripciones.

Ms Recientemente
En la tierra del sentido comn (El cual tiende a no ser tan comn...) Algunos astutos individuos se dieron cuenta de que las computadoras no tenan por qu ser tan confusas que no eran necesarios unos tontos que agregaran frustracin con sus diagramas.

De aqu en adelante comienza IPO


Con sus diagramas de caja simples Para facilitar el planeamiento y desarrollo de programas

Qu es IPO?
Del Ingls: INPUT - PROCESS - OUTPUT En castellano: ENTRADA - PROCESO - SALIDA

Es por lejos la ms simple y usable forma para planear la programacin jams desarrollada. Tarda un gran tiempo la gente en aprender la idea que complejidad no significa necesariamente superioridad. (Lea algn texto que compare las arquitecturas CISC y RISC y entender la idea).

La manera en que funciona es realmente clara, todo lo que hay que hacer es comenzar con un plan bsico... Todos los programas tienen algn grado de entrada (desde un usuario, dispositivo o programa), algn grado de procesamiento de aquella entrada y algn tipo de salida, la cual puede ser una pantalla, una impresora, otro programa, etc

Sabiendo esto, podemos desarrollar todos un programa o parte de ellos con alguna mutacin de este proceso

Aqu hay una ms amplia descripcin de un programa tpico. La ENTRADA incluye estas etapas:
y

y y y

Leer la lnea de comando para ver si hay algn argumento especial tal como un nombre de archivo o una directiva a la manera de los comandos del DOS (por ejemplo dir /w *.txt) donde los argumentos /w y *.txt deben ser ledos e interpretados Leer datos desde un archivo de configuracin (.CFG) Pedirle al usuario el ingreso de algn dato (p. ej. su nombre) Leer datos que ingresan desde un scanner, cmara o cualquier otro dispositivo de entrada presente en el sistema.

El PROCESAMIENTO Involucra todo aquello que se hace para manipular o alterar los datos de entrada recibidos (por ejemplo ordenarlos, operarlos matemticamente, etc). Esto es por lo general la mayor parte del programa. La SALIDA Es como la fase inversa de la entrada. Podemos grabar la configuracin actual, mostrar al usuario algn mensaje, imprimir algo, o enviar los datos a disco o a la entrada de otro programa.

Tuve que programar en algn lenguaje o en otro por ms de 15 aos (aunque tampoco tengo mucha edad), y perd innumerables veces la pista del cdigo de programa, qu estaba haciendo y la direccin a seguir para completar un producto. Siguiendo este lineamiento para la programacin e incluyendo pequeos comentarios en todo el desarrollo del cdigo es la nica forma de garantizar que una semana o un mes despus de ser escrito uno pueda reinterpretar el cdigo y aqul trabajo pueda ser de alguna utilidad. Si no lo creyese as, no hubiese escrito esta parte del tutorial, que por otra parte, ser usado como gua a lo largo de todas las lecciones en cada programa o subrutina que escribamos de aqu en adelante.

5. Comienzos en Assembly

Habiendo ledo en el captulo anterior cmo se desarrollan los programas, es probable que se pregunte si ahora vamos a comenzar a escribir cdigo. Nuestra primera leccin ser sobre cmo construir la caparazn de un programa para que maneje varios tipos de entradas y se inscriba dentro del modelo IPO. Qu tan bueno puede ser un programa si no es interactivo? Incluso programas de baja interactividad como los patches requieren la lectura de datos desde archivos. Si ya est familiarizado en la tcnica de cmo se hacen las llamadas al DOS, saltee esta parte. El texto que sigue es para asegurarse que nadie quede a oscuras an si ha comenzado desde cero. Despus de todo, hemos dirigido este tutorial a los principiantes. La primera cosa que uno desea de un programa es que sea capaz de mostrar un mensaje tonto como "hello, world". Eso haremos. Primero necesito que usted comprenda qu son los registros (las hiper-rpidas variables construidas dentro del procesador x86 de su PC).

En los viejos lenguajes de programacin en alto nivel, el BASIC fue el ms fcil de todos los que se hayan conocido (no confundir con Visual Basic, esa monstruosidad de nuestros amigos de Microsquash, tampoco Qbasic, ni BASICA, sino el viejo y llano BASIC que cada mquina emul a travs de los aos para que si una persona que desea aprender un lenguaje de programacin se atasque con ste, para nada til). En BASIC, haba una manera de ingresar informacin y mostrarla al usuario, usando comandos semejantes a los que siguen: DATA "Hello Planet Hollywood"; READ D$; (from data) PRINT D$; o ms simplemente: LET D$ = "Hello Planet Hollywood"; PRINT D$; y la computadora debera haber mostrado nuestro mensaje en la pantalla, en el supuesto que lo hayamos escrito bien. En Assembly las cosas no son diferentes. Nos quedamos con el primero de los dos modelos BASIC, y escribimos algo como lo que sigue: MYSTRING DB 'Hello Planet Hollywood"; MOV DX, OFFSET MYSTRING y cuando lo tengamos que imprimir, usaremos una llamada al DOS con las siguientes sentencias: MOV AH, 09h INT 21h Ponindolo todo junto, tenemos: MYSTRING DB 'Hello Planet Hollywood','$' MOV DX, OFFSET MYSTRING MOV AH, 09h INT 21h No est del todo mal, verdad? Note el signo '$' al final de la cadena. El DOS necesita que de alguna manera se le seale el final del string, o sea cundo debe dejar de sacar caracteres a la pantalla. Sin l, DOS seguira tirando a la pantalla los caracteres que encuentre en memoria despus del string, usualmente el mismo programa o datos sin valor que quedaron en la memoria luego de encender la PC o que fueron dejados ah por un programa anterior. El signo $ es algo para no olvidar. Hay otra manera de manejar strings en assembly, llamada string-cero, consistente en que en lugar de terminar con "$" terminan con 00h. No es mejor una que la otra, solo son diferentes ( en realidad, la string-cero es manejada por el BIOS en lugar del DOS). Uno podra hacer una rutina para impresin de cadenas de caracteres terminadas en cualquier valor no imprimible, aunque no sera muy til teniendo gratis las dos ya mencionadas. Quizs ms adelante usted quiera desarrollarla para esconder alguna encriptacin en la que se incluya el caracter de

terminacin. Tambin puede usar rutinas que impriman un determinado nmero de caracteres, que no necesitan contar con un caracter de terminacin. Volvamos a nuestro ejemplo: No he mencionado an que los datos deben separarse del cdigo para evitar ser ejecutados. Si pone atencin en los modelos de programas .COM y .EXE vistos un par de captulos antes, ver que en ellos hay una zona para datos y otra para cdigo ejecutable. La primera sentencia del programa hace un salto por sobre la zona de datos para que el nunca se confundan con instrucciones de mquina. Esto tampoco es muy diferente que en BASIC, en donde la gente tiende a poner las sentencias DATA al final del programa. Considere adems que cualquier lenguaje de programacin decente tiene que haber sido escrito alguna vez en assembly, y por tanto no se sorprenda en tener que usar sentencias de string similares. COMO TRABAJAN LOS REGISTROS En el ejemplo anterior, hemos visto que se puede utilizar el registro DX para almacenar una variable de string (que se denomin D$ en BASIC para hacer ms fcil la comparacin). En BASIC uno tiene la cantidad de variables que quiera, pero en assembly slo hay pocas variables de registro para escoger, lo cual sigue estando bien porque no se necesitan ms, ya que las variables pueden almacenarse en cualquier lugar de la memoria que uno elija, y no slo en la zona de variables como en BASIC. A continuacin se resumen los registros de propsitos generales de un procesador x86: AX - Acumulador (donde usualmente quedan los resultados) BX - Registro Base (usualmente indica el comienzo de una estructura que reside en memoria) CX - Contador (lara contar lo que sea, incluso la longitud de strings) DX - Registro de datos - Usualmente apunta a strings o reas de datos en memoria. Los anteriores registros de propsito general son exactamente eso: de propsito general. En el programa uno puede en ocasiones intercambiar las funciones de uno con otro, pero cuando nuestro programa se tiene que comunicar con el DOS no, porque DOS espera datos especficos en cada registro. El programa "hello" visto es un buen ejemplo de esto. El Acumulador (AX) tiene el mayor perfil que uno puede imaginar. Tiende a "acumular" lo que sea. Cuando uno sale de un programa o de una subrutina de cualquier clase, el resultado o los cdigos de error por lo general vuelven en AX. Y cuando se llama un procedimiento, contiene el cdigo de comando como el en ejemplo "hello" en donde AH se carga con un 9h. Cada uno de estos registros tiene 16 bits (dos bytes) aunque desde el 80386 en adelante estos registros pasan a ser de 32 bits y a llamarse EAX, EBX, etc (aunque sigue siendo vlido referirse a la parte baja del registro como AX, o a los ms pequeos AH y AL -por high y low). AX est compuesto por AH (bits 15...7) y AL (bits 7...0) BX est compuesto por BH y BL etc. Veamos ahora registros de uso mucho ms especializado. Los dos siguientes usualmente se unan en operaciones de copia o comparacin de cadenas de caracteres. DI - Indice Destino (El lugar a dnde se mueven los datos) SI - Indice Fuente (El lugar de origen de los datos) y ahora mencionemos a otro:

BP - Puntero Base Muy frecuentemente SI, DI y BP se usan para tener presente en qu lugar del cdigo uno se encuentra -realmente no importa cul sea el uso que se le da a cada registro hasta que uno tiene que comunicarse con algn otro cdigo que espera los datos ubicados en lugares especficos. Esto sucede bastante a menudo. Examine por ejemplo los virus y ver qu poco frecuentes son las referencias a SI y BP. Hay un registro especial que parece como poner la mano de dios en el programa. Es el puntero de instrucciones IP, usado por el procesador para saber cul es la prxima instruccin que ha de ejecutarse.

Por qu esto es importante? Ahora mostraremos un truco de uso frecuente: digamos que por ejemplo estamos en un depurador como SoftICE viendo un lazo del programa que estamos examinando y queremos salir de ese lazo. Cambiando el valor de IP podemos quedar en la parte exterior del lazo. Tenga cuidado al hacer esto porque pasar de un lugar a otro del programa puede tener consecuencias imprevisibles. Los virus (otra vez usando estas bestias como ejemplo) tienden a usar bastante instrucciones que cambian al IP de manera no convencional. Los encabezados de archivos .EXE informan al DOS cul es el segmento de arranque de cdigo (que debe cargarse en CS) y cul es la direccin de la primera instruccin a ejecutar (que debe cargarse en IP). Por lo comn los virus de archivos EXE ponen su cdigo al final del programa y alteran el encabezado de tal forma que los registros CS e IP apunten a sus instrucciones de inicio, con lo cual logran ejecutarse antes que cualquier otra instruccin del programa. Luego al final de su cdigo hacen un salto al inicio del programa (cuya direccin saben porque la leyeron del encabezamiento antes de cambiarla). Ms que creativo, podra decirse. Slo por diversin hchele un vistazo a mi programa SYMBIOTE. Hace exactamente la misma cosa y es el modo que hay que usar para agregar cdigo a los programas. Los archivos .COM son un poco diferentes, tal vez incluso ms simples. Symbiote puede manejar archivos EXE o COM y aunque le tome un rato, por favor no deje de revisarlo porque puede aprender bastante de l, ya que est comentado de forma que se pueda comprender lo que est haciendo en cada momento. SI USTED NO HA HECHO ESTO ANTES: Vaya y modifique tanto los modelos .COM o .EXE agregando las lneas de cdigo para nuestro anterior ejemplo "hello". Considerando que la mayora de las llamadas DOS usan bsicamente el mismo mtodo, no tendr dificultades con otras llamadas. En la prxima leccin, entraremos en el tema de interactividad leyendo entradas de usuario como parmetros en la lnea de comando. Sera muy bueno que antes usted practique algo con el DEBUG. Abra una ventana DOS e ingrese los siguientes comandos: cd \windows\command (o cualquiera sea el directorio de comandos) debug mode.com master greythorne -d 80 Se obtendr esta imagen de la direccin DS:0080 y subsiguientes:

1788:0080 12 20 6D 61 73 74 65 72 - 20 67 72 65 79 74 68 6F 1788:0090 72 6E 65 0D ............... Lo que estamos viendo es la parte del PSP que DOS crea para correr el programa MODE.COM, en donde se almacenan los parmetros que el usuario ingresa en la lnea de comandos. Los valores son todos hexa y el primer 12 indica que el largo de la lnea de comandos es 18 caracteres (=12h), la que comienza con 20h (cdigo ASCII del espacio que separa el nombre del programa cargado MODE.COM del primer parmetro). Notar adems que finaliza con 0Dh, que es el ASCII para el retorno de lnea, pero que ese caracter no se cuenta entre los 12h de largo. Tambin sobre la derecha de la ventana DOS ver el texto que ha escrito como parmetro. Los caracteres ms all del 0Dh no tienen ninguna importancia. No olvide que para salir de debug se utiliza el comando "q". Todo esto ser explicado prximamente, pero un poco de investigacin previa no puede herir a nadie ;-)

6. Un poquito de Interactividad con el usuario

Nuestro primer programa real


En esta seccin vamos a realizar un pequeo programa con una dosis de interactividad con el usuario. Ante todo, insistamos sobre los comentarios, todo aquello que sigue al punto y coma en cada lnea, que son muy tiles y que el compilador los ignora. Note adems que la convencin del punto y coma iniciando un comentario es para los assemblers, pero no intente comentar as una porcin en lenguaje assembly de un programa C: el compilador C/C++ interpreta el smbolo ";" de manera distinta al assembler. El siguiente trozo de programa muestra texto en pantalla:
;********************************************** ; ; .COM Modelo de archivo de programa (COM.ASM) ; ; Compilar con: ; ; TASM COM.ASM ; TLINK /t COM.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' MAIN_PROGRAM:

mov dx,offset CopyMsg mov ah, 09h int 21h mov al, 0h EXIT_PROGRAM: mov ah,4ch int 21h end start

;apunta al string en zona de datos ;funcin DOS 9 = print string ;ejecutar funcin ;codigo de retorno (0 = sin error) ;salir al DOS

Ntese que el mensaje tiene un "rtulo" (CopyMsg). El programa hace referencia al rtulo cuando solicita que se imprima el string porque en realidad todo string es referido como la direccin de la memoria en donde est almacenada su primer caracter, lo que se llama brevemente "offset" (desplazamiento en castellano, aunque le seguiremos diciendo offset para que coincida con el nombre de la directiva de compilador que se usa en los programas), pero que en realidad significa "offset desde el comienzo del segmento". Notemos adems que MAIN_PROGRAM es tambin un rtulo, pero en el segmento de cdigo, por lo que no sera adecuado utilizar la directiva offset para referirse a l. En su lugar, se puede hacer que este rtulo sea la direccin de destino de una instruccin de salto. Aunque nuestro string a imprimir es "'Copyright (c)1997 By Me!", hay otros tres caracteres "de cola": 0Dh (retorno de carro), 0Ah (nueva lnea) y $, que indica el final del string. La combinacin 0Dh,0Ah es el equivalente a apretar la tecla ENTER y hace que el cursor se ubique en el comienzo de la lnea siguiente. Otro caracter de inters es Bell, cdigo 07h, que en lugar de mostrarse en pantalla, hace que la PC haga un "beep" en el parlante, el mismo que se escucha durante el proceso de booteo o al producirse algn tonto error de Windows (lo que sucede bastante frecuentemente :-) Ahora veamos cmo hacer para imprimir un slo caracter. La versin DOS se muestra en las lneas que siguen y aunque para esta clase no se necesita, tenga en cuenta que las personas imprimen caracteres usando mtodos de lo ms variados y la ingeniera inversa requiere conocer todas estas posibilidades. Primero veamos dos lneas que son muy tiles y que muestran cmo obtener un caracter del teclado. En esta versin, el se examina el teclado hasta que el usuario apriete una tecla. mov ah,08h ; DOS funcin 08h, esperar que el usuario apriete una int 21h ; tecla. Al volver, la funcin DOS tiene el cdigo de la tecla apretada en el registro AL. A continuacin veremos cmo hacer que ese caracter sea enviado a la pantalla. La funcin DOS que lo hace espera que el caracter a mostrar est en el registro DL, de modo que la prxima instruccin copiar el contenido de AL en DL (instruccin MOV) y a continuacin se llama a la funcin DOS para mostrar el caracter en la pantalla. mov dl, al ; copiar el caracter que vino del teclado en AL al reg. DL mov ah,06h ; funcin DOS 06h, imprimir un caracter en pantalla. int 21h Emplearemos lo aprendido en un programa que ya hemos usado como ejemplo:
;********************************************** ; ; KEYPRESS.ASM ; Nuestro primer programa interactivo ; ; Compilar con: ; ; TASM KEYPRESS.ASM

; TLINK /t KEYPRESS.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM ;----------------------datos------------------CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' PressEnter db 0Dh,0Ah,'$' ;----------------------cdigo-----------------MAIN_PROGRAM: ; DISPLAY OUR COPYRIGHT MESSAGE mov dx,offset CopyMsg ;dar a conocer el offset del string mov ah, 09h ;funcin 9 = print string int 21h ;llamada a funcin DOS ;adicionamos un nuevo ENTER mov dx, offset PressEnter ;offset de string a DX mov ah, 09h ;funcin 9 = print string int 21h ; ; tomar una tecla apretada por el usuario (sin eco) ; El resultado queda en el registro AL mov ah,08h ;funcin 8: leer una tecla int 21h ; sacar a pantalla el eco (imprimir el caracter) mov dl, al ; copiar el cdigo del caracter al DL mov ah,06h ;funcin 6: mostrar el contenido de DL int 21h ;en pantalla ; Slo por diversin, emitiremos un beep mov dl, 07h ;poner en DL el cdigo del beep mov ah,06h ;igual que antes int 21h mov al, 0h ;cdigo de retorno (0 = sin error) mov ah,4ch ;salir al DOS int 21h end start

Tenemos ahora casi todo lo necesario para hacer un programa que realice una tarea til. Toda vez que en un programa hay un cursor parpadeando esperando que se apriete una tecla, no est inactivo, sino que se encuentra en un loop que verifica constantemente si se apret una tecla. No es la PC en si misma la que lo hace sino el programa que esta corriendo. El procesador est haciendo sus propias tareas dentro de la PC. Y de repente, una persona o programa hace algo que interrumpe el flujo normal de las cosas. No es necesario que el procesador gaste su tiempo en lo que le interesa un programa en particular (escaneando constantemente al teclado para ver si se apret alguna tecla). El que nuestro programa deba atender permanentemente al teclado en un momento dado, no significa problema y es en realidad la forma en que cualquier juego o programa de entrada de datos lo debe hacer, an cuando no sea evidente. Es usual que se establezca un lazo infinito del que slo se sale en un caso especial o cuando se ingresa determinado cdigo. En nuestro caso, aceptaremos como teclas vlidas una "Y" o una "N" tanto en mayscula como en minscula. Es importante aclarar este aspecto: el programa no ser optimizado. Dejaremos esto para ms tarde y nos preocuparemos de hacer que funcione. El pseudocdigo de un lazo infinito es:

START_OF_LOOP: ; el rtulo (observe los dos puntos ":") ; el cdigo va aqui JMP START_OF_LOOP ; saltar hacia el inicio del lazo GO_ON_WITH_PROGRAM: ; un rtulo fuera del lazo Lo que necesitamos ahora es saber cmo se sale del lazo (la lgica que nos lleva al rtulo GO_ON_WITH_PROGRAM). Debemos poder decirle que si se obtuvo una tecla vlida que salga del lazo. Para esto, disponemos de la funcin CMP (comparar), que evala dos variables y prende o apaga flags segn sean iguales o una mayor que la otra (pero no modifica a ninguna de las variables). Por si queremos usarlo para otra cosa, pondremos en BL el cdigo de la tecla que la Int 08 nos deja en AL. Por qu BL? slo porque es un registro que no hemos usado an. No hay otra razn. La sintaxis es: CMP var_x, var_y Para nuestro caso, que queremos comparar BL con el caracter "Y": CMP BL,'Y' Notar las comillas en la "Y", que indican que la comparacin se hace entre BL y el cdigo ASCII correspondiente a la letra "Y". Para los nmeros (decimales y hexa) se utilizan las notaciones: CMP BL, 89 CMP BL, 059h Las tres formas son equivalentes ya que el cdigo ASCII para la Y es 89 decimal o 59h hexa. Ahora veamos la instruccin de salto JZ (jump if zero), tambin llamada JE (jump if equal) que salta a la direccin indicada si el resultado de la comparacin es cero, es decir var_x es igual a var_y. En caso de ser distintos, contina la ejecucin de la instruccin que sigue. La instruccin opuesta es JNZ, tambin llamada JNE. El siguiente trozo de cdigo hace lo que hemos descrito hasta ahora:
START_OF_LOOP: mov ah,8 ;funccion 8, leer una tecla apretada int 21h mov bl, al ;guardamos la tecla en BL cmp bl, 'Y' ;ver si la tecla es una 'Y' je GO_ON_WITH_PROGRAM cmp bl, 'N' ;ver si la tecla es una 'N' je GO_ON_WITH_PROGRAM JMP START_OF_LOOP ;volver a buscar una tecla GO_ON_WITH_PROGRAM: ;lugar de salida, ya fuera del lazo

Ahora est en condiciones de seguir este programa con facilidad:


;********************************************** ; ; KEYPRESS.ASM ; Nuestro primer programa interactivo ; ; Compilar con:

; ; TASM KEYPRESS.ASM ; TLINK /t KEYPRESS.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 org 100h start: jmp MAIN_PROGRAM ;---------------------CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' PressEnter db 0Dh,0Ah,'$' ;---------------------MAIN_PROGRAM: ; Mostramos el mensaje de Copyright mov dx, offset CopyMsg ; offset del string en DX mov ah, 09h ; funcin 9 = print string int 21h ;ahora enviemos un retorno y nueva lnea adicionales mov dx, offset PressEnter ;offset en DX mov ah, 09h ; funcin 9 = print string int 21h START_OF_ENDLESS_LOOP: mov ah,8 ;funcion 8, buscar una tecla apretada int 21h mov bl, al ;guardamos el cdigo de la tecla cmp bl, 'Y' ; es la tecla una 'Y'? je GO_ON_WITH_PROGRAM ;salir del lazo si es cierto cmp bl, 'N' ; es la tecla una 'N'? je GO_ON_WITH_PROGRAM ;salir del lazo si es cierto cmp bl, 'y' ; es la tecla una 'y'? je GO_ON_WITH_PROGRAM ;salir del lazo si es cierto cmp bl, 'n' ; es la tecla una 'n'? je GO_ON_WITH_PROGRAM ;salir del lazo si es cierto ; si no es lo que esperbamos, emitir un beep mov dl, 07h ; poner cdigo de beep en DL mov ah,6 ; funcion 6, imprimir un character int 21h JMP START_OF_ENDLESS_LOOP GO_ON_WITH_PROGRAM: ; mostrar la tecla apretada (eco) mov dl, bl ;poner el cdigo de la tecla en DL mov ah,6 ;funcin 6, imprimir un character int 21h mov mov int al, bl ; poner de nuevo el cdigo de la tecla ; en AL para que sea el valor de retorno ; salir al DOS

ah,4ch 21h end start

Como prctica, modifique el programa anterior para que si la tecla apretada fue una "n" o "N", saque a pantalla el texto "ha dicho que no!" y si la tecla fue una "y" o "Y", que imprima "Afirmativo!". Tambin sera de utilidad que en el inicio del programa oriente al futuro usuario que las teclas que se esperan son Y/N. No hay nada ms frustrante que no conocer qu espera la PC como respuesta.

NOTA: el valor de salida de un programa se almacena en la variable ERRORLEVEL del DOS, de manera que es posible usar el programa dentro de un archivo batch que haga diferentes cosas basado en la tecla que el programa le informa que fue apretada.

7. Modularidad y Procedimientos

Desarrollo de Aplicaciones
Recientemente me preguntador cmo crear grandes programas. Hay algunos trucos para hacerlo. En la segunda parte haremos una revisin para hacer que nuestros programas sean modulares. IMPORTANTE MAS ALLA DE TODA RAZON: COMENTE TANTO COMO PUEDA LOS PROGRAMAS, es decir ponga un comentario en la mayora de las lneas sobre la accin que se est tomando en esa parte del cdigo. Decir para un MOV CX,8 que se carga un 8 al CX no es comentario brillante, pero en cambio si : "cargar CX con el nmero de loops " y es invaluable a la hora de depurar el cdigo. Si nunca ha escrito programas grandes, NO CUESTIONE, HAGALO. Los comentarios son importante cuando usted necesita que alguien le ayude a depurar el cdigo. Nadie ayudar si no hay comentarios que den informacin, porque es verdaderamente difcil, cuando no imposible. Y si esta pensando que usted lo puede lograr sin comentarios ni ayuda, adelante, seguramente es mejor que yo. O un tonto, usted decide. Tambin escriba comentarios sobre lo que hacen las distintas secciones del programa, por ejemplo: ;*********** ;esta seccin toma la lnea de comandos y la copia en un buffer ;luego la interpreta y almacena switches y flags en memoria ;espera que se le pase en CX la longitud de la lnea de comando ;*********** ---------------

Modularidad:
Se puede escribir un programa linealmente desde el principio al fin sin separarlo en mdulos. Pero hay problemas: no es posible escribir cdigo ms all de los 64 kB. El cdigo puede quedar tan rgido que un ligero cambio en una de sus partes, posiblemente implique la re-escritura del programa completo. Y adems si nuestro programa de una seccin es ms extenso que el buffer de memoria del compilador, no lo podremos compilar. Escribiendo el programa en mdulos, si es necesario cambiar algo, slo se debe modificar el mdulo en cuestin. Como estos mdulos pueden llamarse desde varios puntos del programa, se reduce el tipeado y por lo tanto la posibilidad de error. Cuando los programas se escriben en mdulos, los compiladores toman cada parte por separado, no produce desborde de memoria y la depuracin se hace ms fcil.

La forma de modularizar un programa es utilizando PROCs. Todos los lenguajes decentes permiten la construccin de subrutinas que pueden ser llamadas desde cualquier parte del programa. En assembly se las llama "procs" (abreviatura de procedures, igual que en Pascal). En C se las denomina "funciones", aunque cada lenguaje las maneja de manera ligeramente diferente. Para el TASM, un proc puede verse como sigue:
PrintLine proc near mov ah, 9 ;funcin ah=9 (imprime en pantalla) int 21h ; ret ;cdigo de retorno desde el proc endp PrintLine y para llamarla usamos el siguiente cdigo: mov dx, offset MyMessage call PrintLine Es verdaderamente prctico!!! Hay tambin algunas desventajas, que se muestran cuando uno escribe muchos procs. CompareByte proc near Loop: inc ah cmp ah, 092h jne Loop ret endp CompareByte ;---------------------CompareWord proc near Loop: inc ax cmp ax, 02942h jne Loop ret endp CompareWord ;----------------------

Cuando esto se compila, si bien CompareWord y CompareByte son dos rutinas distintas, el rtulo "Loop" est duplicado y el compilador nos da error porque no sabe a cual de los dos nos referimos en los saltos JNE. La solucin evidente es tratar de diferenciarlos:
CompareByte proc near CmpByteLoop1: inc ah cmp ah, 092h jne CmpByteLoop1 ret endp CompareByte ;---------------------CompareWord proc near CompareWordLoop1: inc ax cmp ax, 02942h jne CompareWordLoop1 ret endp CompareWord ;----------------------

Si nuestro programa es suficientemente largo uno puede volverse tonto tratando de encontrar maneras de diferenciar las cosas. Hay una solucin fcil: Usar el IDEAL MODE

Al principio del modelo EXE o COM, agregamos la palabra IDEAL para que TASM sepa que debe utilizar el modo ideal. Veamos cmo alterar el encabezado del modelo COM :
;---------------------COM_PROG segment byte public ideal assume cs:COM_PROG org 100h start: ;---------------------Esto simplifica la manera de escribir procedimientos tambin: proc PrintLine mov ah, 9 ;funcin ah=9 (imprimir en pantalla) int 21h ; ret ;volver del proc endp PrintLine

La ventaja real viene a la hora de diferenciar rtulos comunes. Esto se hace con u par de smbolos "at" (@@) antepuestos al rtulo:
proc CompareByte @@Loop: inc ah cmp ah, 092h jne @@Loop ret endp CompareByte ;---------------------proc CompareWord @@Loop: inc ax cmp ax, 02942h jne @@Loop ret endp CompareWord ;----------------------

Los smbolos @@ indican que se trata de un smbolo local a la rutina y que no debe ser visible para el resto del cdigo. Cuando algo no es local, se lo denomina GLOBAL, y est disponible para cualquier parte del programa. Las partes globales son tiles, pero para algunas pocas cosas. Por ejemplo en el programa de un juego es adecuado tener el score en variable global para que sea visible en todas las secciones del juego. Las variables y smbolos locales permiten hacer programas largos sin el riesgo de tener efectos peligrosos en otras secciones del cdigo. Veamos como ejemplo nuestro programa para obtener una tecla Y o N. Lo escribiremos como ejemplo de procedimientizacin (qu palabrita!) de cdigo. Lo exageraremos un poco a propsito. Nuestro objetivo es hacer una seccin "main" con la menor lneas de cdigo posible, slo hacer unos pocos llamados y salir. Simplsticamente, una seccin main sera:
; entrada call input call process call output ; salida

Si bien este no es un requerimiento excluyente, tenga en cuenta que cuanto ms se acostumbre a programar en mdulos, ms fcil le ser hacerlo.

;********************************************** ; ; KEYPRESS.ASM ; Nuestro primer Programa Interactivo ; (con un poco de procedimientizacin) ; ; Compilar con: ; ; TASM KEYPRESS.ASM ; TLINK /t KEYPRESS.OBJ ; ; +gthorne'97 ; ;********************************************** .model small .code .386 ideal org 100h start: jmp MAIN_PROGRAM ;---------------------- datos -------------CopyMsg db 'Copyright (c)1997 By Me!',0Dh,0Ah,'$' PressEnter db 0Dh,0Ah,'$' ;---------------------- cdigo -------------proc PrintString ;imprime el string apuntado por DX mov ah, 09h ;comando 9 = imprimir string int 21h ; ret ; endp PrintString ;---------------------proc PrintChar ; imprime caracter contenido en DL mov ah,6 ;funcin 6 = imprimir un caracter int 21h ; ret endp PrintChar ;---------------------proc CopyRight ;muestra anuncio de Copyright mov dx,offset CopyMsg ;poner en DX el puntero al string call PrintString mov dx,offset PressEnter ;agregar un ENTER final call PrintString ret endp CopyRight ;---------------------proc GetInput ;verifica teclas vlidas @@Loop: ; primero buscar una tecla leyendo el teclado mov ah,8 ;funcin 8, leer tecla apretada int 21h mov bl, al ;guardamos el cdigo de la tecla ;porque nos fascina hacerlo cmp bl, 'Y' ;ver si la tecla es una 'Y' je @@Done cmp bl, 'N' ;ver si la tecla es una 'N' je @@Done cmp bl, 'y' ;ver si la tecla es una 'y' je @@Done cmp bl, 'n' ;ver si la tecla es una 'n' je @@Done ; hacer un "beep" si la tecla es distinta a la esperada mov dl,07h ;poner cdigo para BEEP en DL call PrintChar jmp @@Loop ;y pedir tecla nuevamente @@Done: ;ECO (mostrar en pantalla la tecla que el usuario apret)

mov dl,bl ;copiar el cdigo de tecla a DL call PrintChar ret endp GetInput ;---------------------MAIN_PROGRAM: call CopyRight ;mostrar mensaje de Copyright call GetInput ;requerir de entrada de usuario ;----------------------mov al, bl ;valor de salida = cdigo de tecla mov ah,4ch ;salir al DOS int 21h end start ------------------------------------------------------

Aqui damos por terminado este pequeo tutorial de lenguaje assembly. No olvide que as como usted obtuvo estos conocimientos gratuitamente, debe brindarlos a los dems y aportar los propios para que la comunidad de entusiastas del assembly siga creciendo da tras da.

S-ar putea să vă placă și