Debe introducir al menos 3 caracteres en el buscador.
Inicio / Wikis / Cursos gratis / Curso de programación de virus - Ensamblador I: Conceptos basicos

Curso de programación de virus - Ensamblador I: Conceptos basicos

 ***** (108 opiniones)
Creative Commons Curso gratis de Wintermute - 22 de Febrero de 2006
Temas Relacionados: Seguridad informática
5. Ensamblador I: Conceptos basicos

Este, es el capítulo más largo probablemente del curso de programación de virus. Programar en ensamblador no es fácil, pero cuando se le coge el tranquillo es extremadamente gratificante; estás hablando directamente con la máquina, y aquello que le pides, ella lo hace. El control, es absoluto... nada mejor pues, a la hora de programar virus o cualquier tipo de aplicación crítica.

Algunos conceptos previos

Procesadores CISC/RISC

Según el tipo de juego de instrucciones que utilicen, podemos clasificar los microprocesadores en dos tipos distintos:

-RISC: Aquellos que utilizan un juego reducido de instrucciones. Un ejemplo de ello sería el ensamblador del Motorola 88110, que carece por ejemplo de más saltos condicionales que "salta si este bit es 1" y "salta si este bit es 0". Por un lado se obtiene la ventaja de que en cierto modo uno se fabrica las cosas desde un nivel más profundo, pero a veces llega a hacer la programación excesivamente compleja.

-CISC: Son los que usan un juego de instrucciones ampliado, incluyéndose en esta clasificación el lenguaje ensamblador de los 80x86 (el PC común de Intel, AMD, Cyrix...). Para el ejemplo usado antes, en el asm de Intel tenemos 16 tipos distintos de salto que abstraen el contenido del registro de flags y permiten comparaciones como mayor que, mayor o igual que, igual, menor, etc.

Little Endian vs Big Endian

Existen dos formas de almacenar datos en memoria, llamados Little Endian y Big Endian. En el caso de los Big Endian, se almacenan tal cual; es decir, si yo guardo en una posición de memoria el valor 12345678h, el aspecto byte a byte de esa zona de memoria será ??,12h,34h,56h,78h,??

El caso de un Little Endian - y el PC de sobremesa es Little Endian, por cierto -, es distinto. Byte a byte, los valores son almacenados "al revés", el menos significativo primero y el más significativo despuñes. Normalmente no nos va a afectar puesto que las instrucciones hacen por si mismas la conversión, pero sí hay que tenerlo en cuenta si por ejemplo queremos acceder a un byte en particular de un valor que hemos guardado como un valor de 32 bits (como sería el caso de 12345678h). En ese caso, en memoria byte a byte quedaría ordenado como ??,78h,56h,34h,12h,??.

Juego de registros de los 80x86

En las arquitecturas tipo 80x86 (esto es, tanto Intel como AMD o Cyrix, que comparten la mayoría de sus características en cuanto a registros e instrucciones en ensamblador), tenemos una serie de registros comunes; con algunos de ellos podremos realizar operaciones aritméticas, movimientos a y desde memoria, etc etc. Estos registros son:

EAX: Normalmente se le llama "acumulador" puesto que es en él donde se sitúan los resultados de operaciones que luego veremos como DIV y MUL. Su tamaño, como todos los que vamos a ver, es de 32 bits. Puede dividirse en dos sub-registros de 16 bits, uno de los cuales (el menos significativo, o sea, el de la derecha) se puede acceder directamente como AX. A su vez, AX podemos dividirlo en dos sub-sub-registros de 8 bits, AH y AL:

EBX: Aquí sucede lo mismo que con EAX; su división incluye subregistros BX (16 bits), BH y BL (8 bits).

ECX: Aunque este registro es como los anteriores (con divisiones CX, CH y CL), tiene una función especial que es la de servir de contador en bucles y operaciones con cadenas.

EDX: Podemos dividir este cuarto registro "genérico" en DX, DH y DL; además, tiene la característica de que es aquí donde se va a guardar parte de los resultados de algunas operaciones de multiplicación y división (junto con EAX). Se le llama "puntero de E/S", dada su implicación también en acceso directo a puertos.

ESI: Se trata de un registro de 32 bits algo más específico, ya que aunque tiene el sub-registro SI (16 bits) refiriéndose a sus bits 0-15, este a su vez no se divide como lo hacían los anteriores en sub-sub-registros de 8 bits. Además, ESI va a servir para algunas instrucciones bastante útiles que veremos, como LODSX, MOVSX y SCASX (operando origen siempre)

EDI: Aplicamos lo mismo que a ESI; tenemos un "DI" que son los últimos 16 bits de EDI, y una función complementaria a ESI en estos MOVSX, etc (el registro ESI será origen, y el EDI, el operando destino).

EBP: Aunque no tiene ninguna función tan específica como ESI y EDI, también tiene su particularidad; la posibilidad de que se referencien sus bits 0-15 mediante el sub-registro BP.

EIP: Este es el PC (Program Counter) o Contador de Programa. Esto es, que en este registro de 32 bits (que no puede ser accedido por métodos normales) se almacena la dirección de la próxima instrucción que va a ejecutar el procesador. Existe también una subdivisión como "IP" con sus 16 bits menos significativos como con EBP, EDI, etc, pero no lo vamos a tener en cuenta; en un sistema como Linux o Windows se va a usar la combinación CS:EIP para determinar lo que hay que ejecutar siempre, y sólo en sistemas antiguos como Ms-Dos se utiliza el CS:IP para ello.

ESP: Se trata del registro de pila, indicando la dirección a la que esta apunta (que sí, que lo de la pila se explica más tarde).

Además de estos registros, tenemos otros llamados de segmento, cuyo tamaño es de 16 bits, y que se anteponen a los anteriores para formar una dirección virtual completa. Recordemos en cualquier caso que estamos hablando de direcciones virtuales, así que el procesador cuando interpreta un segmento no está operando con nada; simplemente se hace que direcciones de la memoria física se correspondan con combinaciones de un segmento como puede ser CS y un registro de dirección como puede ser EIP. La función de estos registros de segmento es la de separar por ejemplo datos de código, o zonas de acceso restringido. Así, los 2 últimos bits en un registro de segmento indican normalmente el tipo de "ring" en el que el procesador está corriendo (ring3 en windows es usuario, con lo que los dos últimos bits de un segmento reservado a un usuario serían "11"... ring0 es supervisor, con lo que los dos últimos bits de un segmento con privilegio de supervisor serían "00")

-CS es el registro de segmento de ejecución, y por tanto CS:EIP es la dirección completa que se está ejecutando (sencillamente anteponemos el CS indicando que nos estamos refiriendo a la dirección EIP en el segmento CS).

-SS es el registro de segmento de pila, por lo que tal y como sucedía con CS:EIP, la pila estará siendo apuntada por SS:ESP.

-DS normalmente es el registro de datos. Poniendo ya un ejemplo de acceso con la instrucción ADD (sumar), una forma de utilizarla sería "add eax,ds:[ebx]", que añadiría al registro EAX el contenido de la dirección de memoria en el segmento DS y la dirección EBX.

-ES, al igual que FS y GS, son segmentos que apuntan a distintos segmentos de datos, siendo los dos últimos poco utilizados.

Tenemos algunos otros registros, como el de flags que se detallará en un apartado específico (si se recuerda del capítulo 1 la descripción genérica, contiene varios indicadores que serán muy útiles).

Finalmente, están (aunque probablemente no los usaremos), los registros del coprocesador (8 registros de 80 bits que contienen números representados en coma flotante, llamados R0..R7), el GDTR (global descriptor table) e IDTR (interrupt descriptor table), los registros de control (CR0, CR2, CR3 y CR4) y algunos más, aunque como digo es difícil que lleguemos a usarlos.

La órden MOV y el acceso a memoria

Usos de MOV

Vamos con algo práctico; la primera instrucción en ensamblador que vamos a ver en detalle. Además, MOV es quizá la instrucción más importante en este lenguaje sicontamos la cantidad de veces que aparece.

Su función, es la transferencia de información. Esta transferencia puede darse de un registro a otro registro, o entre un registro y la memoria (nunca entre memoria-memoria), y también con valores inmediatos teniendo como destino memoria o un registro. Para ello, tendrá dos operandos; el primero es el de destino, y el segundo el de origen. Así, por ejemplo:

MOV EAX, EBX

Esta operación copiará los 32 bits del registro EBX en el registro EAX (ojo, lo que hay en EBX se mantiene igual, sólo es el operando de destino el que cambia). Ya formalmente, los modos de utilizar esta operación son:

- MOV reg1, reg2: Como en el ejemplo, MOV EAX, EBX, copiar el contenido de reg2 en reg1.

-MOV reg, imm: En esta ocasión se copia un valor inmediato en reg. Un ejemplo sería MOV ECX, 12456789h. Asigna directamente un valor al registro.

-MOV reg, mem: Aquí, se transfiere el contenido de una posición de memoria (encerrada entre corchetes) al registro indicado. Lo que está entre los corchetes puede ser una referencia directa a una posición de memoria como MOV EDX, [DDDDDDDDh] o un acceso a una posición indicada por un registro como MOV ESI, [EAX] (cuando la instrucción sea procesada, se sustituirá internamente "EAX" por su contenido, accediendo a la dirección que indica).

También hay una variante en la que se usa un registro base y un desplazamiento, esto es, que dentro de los corchetes se señala con un registro la dirección, y se le suma o resta una cantidad. Así, en MOV ECX,[EBX+55] estamos copiando a ECX el contenido de la dirección de memoria suma del registro y el número indicado.

Finalmente, se pueden hacer combinaciones con más de un registro al acceder en memoria si uno de ellos es EBP, por ejemplo MOV EAX,[EBP+ESI+10]

-MOV mem, reg: Igual que la anterior, pero al revés. Vamos, que lo que cogemos es el registro y lo copiamos a la memoria, con las reglas indicadas para el caso en que es al contrario. Un ejemplo sería MOV [24347277h], EDI

-MOV mem, imm: Exáctamente igual que en MOV reg, imm sólo que el valor inmediato se copia a una posición de memoria, como por ejemplo MOV [EBP],1234h

Bytes, words y dwords

La instrucción MOV no se acaba aquí; a veces, vamos a tener problemas porque hay que ser más específico. Por ejemplo, la instrucción que puse como último ejemplo, MOV [EBP],1234h, nos daría un fallo al compilar. El problema es que no hemos indicado el tamaño del operando inmediato; es decir, 1234h es un número que ocupa 16 bits (recordemos que por cada cifra hexadecimal son 4 bits). Entonces, ¿escribimos los 16 bits que corresponden a [EBP], o escribimos 32 bits que sean 00001234h?.

Para solucionar este problema al programar cuando haya una instrucción dudosa como esta (y también se aplicará a otras como ADD, SUB, etc, cuando se haga referencia a una posición de memoria y un valor inmediato), lo que haremos será indicar el tamaño con unas palabras específicas.

En el ensamblador TASM (el más utilizado para Win32/Dos), será con la cadena byte ptr en caso de ser de 8 bits, word ptr con 16 bits y dword ptr con 32. Por lo tanto, para escribir 1234h en [EBP] escribiremos MOV word ptr [EBP],1234h. Sin embargo, si quisiéramos escribir 32 bits (o sea, 00001234h), usaríamos MOV dword ptr [EBP],1234h.

Usando el NASM para linux, olvidamos el "ptr", y los ejemplos anteriores se convertirán en MOV word [EBP],1234h y MOV dword [EBP],1234h.

Recordemos, una vez más, que un dword son 32 bits (el tamaño de un registro), un word 16 bits y un byte, 8 bits.

Referencia a segmentos

Cuando estamos accediendo a una posición de memoria (y no ya sólo en el ámbito del MOV), estamos usando también un registro de segmento. Normalmente el segmento DS va implícito (de hecho, si en un programa de ensamblador escribimos MOV DS:[EAX],EBX, al compilar obviará el DS: para ahorrar espacio puesto que es por defecto). No obstante, podemos indicar nosotros mismos a qué segmento queremos acceder siempre que hagamos una lectura/escritura en memoria, anteponiendo el nombre del registro de segmento con un signo de dos puntos al inicio de los corchetes.

Operandos de distinto tamaño

Vale, tengo un valor en AL que quiero mover a EDX. ¿Puedo hacer un MOV EDX,AL?. Definitivamente no, porque los tamaños de operando son diferentes.

Para solucionar este problema, surgen estas variantes de MOV:

-MOVZX (MOV with Zero Extend): Realiza la función del MOV, añadiendo ceros al operando de destino. Esto es, que si hacemos un MOV EDX, AL y AL vale 80h, EDX valdrá 00000080h, dado que el resto se ha rellenado con ceros.

-MOVSX (MOV with Sign Extend): Esta forma lo que hace es, en lugar de 0s, poner 0s o 1s dependiendo del bit más significativo del operando de mayor tamaño. Es decir, si en este MOV EDX, AL se da que el bit más significativo de AL es 1 (por ejemplo, AL = 10000000b = 80h), se rellenará con 1s (en este caso, EDX valdría FFFFFF80h). Si el bit más significativo es 1 (por ejemplo, AL = 01000000b = 40h), se rellenará con 0s ( EDX será pues 00000040h). 

Autor y licencia de 'Curso de programación de virus - Ensamblador I: Conceptos basicos'
Wintermute

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.
Wikilearning tiene permiso expreso por escrito de los autores para publicar los contenidos que ha extraído de otras webs, incluyendo su uso comercial.

Wikis relacionados con 'Curso de programación de virus - Ensamblador I: Conceptos basicos'

Explica conceptos basicos relacionados con blender para entender el funcionamiento de dichos elementos en el... Más »
La macroeconomía es el estudio del comportamiento agregado de una economía, es decir, es la... Más »
El formulario, junto con la línea de comandos, fue uno de los primeros estilos de... Más »
Hablar de marcas es hablar de estrategia de negocio. Estos conceptos sobre marcas te ayudarán... Más »
Muchas personas imagina que los llamados virus informáticos son unos organismos que flotan en el... Más »
Gente Wiki
Jose Enrique Arroyo Verástegui
Licenciado en psicología y profesor de bachillerato desde hace 22 años. Director del museo de el grullo, jalisco, mexico.
Angel Escobar
El diseño y la fabricacion son mi fuerte en sector industrial y de construccion. He construido lanzadores de hormigon con...
Ingeniero de materiales
Benjamín Vega Godínez
C. E. O. Benjamín. Vega. Godínez (. B. V. G. 1973 -. ). Primer mandatario de la organización a fin...
Derecho internacional, Derecho penal,...
Viki Alejandro
Licenciada en ciencias de la educación especialidad física y matemáticas. Docente de nivel medio superior y superior.
Nestor Boche
Ingeniero 35 años. Gerente de empresa con 3 años de vida. Discipulo de la administración, tecnología, crecimiento, basadas en que...
David Torres
Residencia: xalapa, veracruz, méxico licenciado en educación especial en el área de audición y lenguaje maestro en necesidades educativas especiales catedrático de la...
Pedagogía
Suscribirse
Concurso de proyectos educativos
¿Estás seguro de que deseas eliminar este capítulo?