1
[RVLCN]
CLASES de ProgramaciOn CON MASM+Radasm Capitulo I: Instalacion y Configuracion. Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL LEGAL
ó
2
[RVLCN]
[ Introducción ] RVLCN te da la bienvenida al curso de programaci ón con MASM32 usando el IDE RadAsm RadAsm,, aquí aprender ás a crear y dise ñar tus propias aplicaciones en forma f ácil y r ápida. MASM32 ofrece una buena alternativa alternativ a si quieres aprender a programar en ensamblador, tiene una gran cantidad de constantes, estructuras, y librer ías que usaras al momento de programar, esto nos ahorra mucho tiempo al escribir nuestra aplicaci ón, además que su sintaxis es agradable a comparaci ón de otros compiladores en ensamblador. Este curso es 100% practico, cada capitulo contiene videos donde se puede observar como se programa, describiendo el proceso de programaci ón, también lo que no ha quedado claro o no esta descrito en el video se puede aclararlo en el documento respectivo de cada capitulo. Si tienes dudas, preguntas podr ás hacerla en la lista MASm+Radasm, para que no quede nada inconcluso.
[ Agradecimientos Agradecimientos ] Gracias a hutch que constantemente actualiza y da soporte a MASM32 MASM32,, y también ha kelitO por programar el mejor IDE (RadASM) ( RadASM) para Assembler que nos facilita y nos ayuda al momento de programar nuestras aplicaciones.
[ Materiales ] 1.- Necesitamos el compilador MASM32 v9.0 o superior: Pagina Oficial: http://www.masm32.com/ Descargar compilador: http://website.assemblercode.com/masm32/m32v9r.zip Version 9. 9. 2.- Necesitamos tambi én el IDE RADASM v 2.2.0 o superior: Pagina Oficial: http://www.radasm.com/ Descargar IDE : http://www.radasm.com/RadASM2000/RadASM.zip Descargar los Lenguajes de Programaci ón: http://www.radasm.com/RadASM2000/Assembly.zip Descargar el idioma del IDE: http://www.radasm.com/RadASM2000/RadLNG.zip http://www.radasm .com/RadASM2000/RadLNG.zip
3
[RVLCN]
3.-Necesitamos saber sobre las Funciones de Windows: Win32 Programmer ’s Reference: http://www.rvlcnsecurity.com/cla http://www.rvlcns ecurity.com/clases/anexo/win ses/anexo/win32api.rar 32api.rar 4.- Para descomprimir los archivos puedes usar el WinZip o el Winrar: Winrar : http://www.rarlab.com/rar/w http://www.rarl ab.com/rar/wrar36b5 rar36b5.exe .exe
[Instalación de Nuestro Compilador] Descomprimimos nuestro archivo m32v9r.zip que hemos descargado y abrimos el instalador “install.exe” y muestra lo siguiente:
Fig.1 Elegimos en que disco duro queremos instalar, luego presionamos el bot bot ón Start,, para continuar la instalaci ón y aparece el siguiente mensaje: Start
Fig. 2 Instala masm32 en la unidad C:\?, C:\? , presionamos el bot ón Si y muestra el siguiente mensaje:
Fig. 3
4
[RVLCN]
Esta instalaci ón no esta hecha para correr sin supervisi ón o en el background, realiza intensivas operaciones de procesador para construir las librer ías y puede que no funcione correctamente o no cree las librer ías si no es supervisada en baja prioridad. Presionamos el bot ón Aceptar , y aparece la ventana para extraer los archivos:
Fig. 4 Procedemos a presionar el bot ón Extract, y empieza la extracci ón de los archivos:
Fig. 5
Una vez terminada la extracción de sus archivos muestra una ventana en DOS:
Fig. 6 Presionamos la tecla ENTER y observamos como crea las librer ías de las APIS de Windows necesarios para crear nuestros programas, despu és de que termina muestra la siguiente ventana:
5
[RVLCN]
Fig. 7 Volvemos a presionar la tecla ENTER, para continuar con la creaci ón de librer ías:
Fig.8 Listo se termino de crear todas las librer ías, volvemos a presionar la tecla ENTER:
6
[RVLCN]
Fig. 9 “Instalación
Exitosa”, volvemos a presionar la tecla ENTER para que termine la
instalación:
Fig. 10
SI se desea aceptamos el mensaje, sirve para instalar el qeditor.exe que para nosotros es obsoleto. Ya tenemos el compilador Instalado y listo para programar, pero para ello vamos a instalar el IDE RadAsm.
[ Instalación del IDE RADASM ] Extraemos el archivo RadASM.zip presionando el clic derecho del Mouse:
7
[RVLCN]
Fig. 11
Fig. 12 Seleccionamos el disco duro donde queremos extraer los archivos en mi caso he elegido C:\. Damos clic al bot ón Aceptar. Luego debemos extraer el paquete de lenguajes de programaci ón Assembly.zip y también extraemos el paquete de Idioma RadLNG.zip en la misma carpeta donde tenemos el RadAsm en mi caso es C:\RadAsm:
8
[RVLCN]
Fig.13
Como se observa en la Fig.13 estamos en el directorio assembly donde debemos copiar el archivo masm.ini y la carpeta \MASM, para pegarlo en el directorio de RadAsm como muestra la siguiente figura:
Fig. 14 Luego abrimos el RadASM.exe, para configurar el idioma y agregar el lenguaje de programaci ón: Para agregar el Lenguaje de programaci ón debemos ir al Option/Programming Languages, como muestra la siguiente imagen:
men ú
Fig. 15 Damos Clic y sale una ventana para agregar el lenguaje de programaci ón:
9
[RVLCN]
Fig. 16 Damos clic en el bot ón marcado con rojo y sale una ventana para abrir solo archivos con extensi ón *.ini y seleccionamos el archivo masm.ini:
Fig.17 Damos clic en el botón Abrir y observamos que se ha habilitado el bot ón add (Agregar Fig.16) y como ultimo paso presionamos el bot ón OK (Fig.16). Para cambiar a nuestro idioma espa ñol, nos vamos al men ú Option/language, como muestra la imagen siguiente:
10
[RVLCN]
Fig. 18 Damos clic y muestra la ventana de idiomas as í que seleccionamos el espa ñol como muestra la imagen siguiente:
Fig. 19 Presionamos el bot ón Apply (Aplicar), y luego el bot ón OK. Si Usted ha instalado el Masm32 en otra Unidad por ejemplo la D:\ debemos configurar la ruta, para que pueda compilar los programas que escribimos, para ello nos dirigimos al men ú Opciones/Fijar Rutas:
Fig. 20
11
[RVLCN]
Al hacer clic en esa opción aparecer á una ventana para configurar la carpeta donde esta instalado el compilador, si tenemos el Masm32 en la unidad D:\ debemos configurar de esta manera:
Fig. 21 Luego damos clic en el bot ón Aplicar y luego el bot ón Ok Ya terminamos de instalar y configurar todo, ya estamos listo para empezar a aprender programaci ón en MASM32+RadAsm.
[ Optimizando Instalación ] Para una instalaci ón mucho más r ápida que la anterior te recomiendo el [RVLCN]_InstRApiMAsm_RadASm.rar lo puedes descargar de: http://www.rvlcnsecurity.com/clases/anexo/RVLCN_InstRApiMAsm_RadASm.rar
Una vez descargado descomprimimos el archivo y damos doble clic en [RVLCN]-InstRApiMAsmRad.exe y muestra lo siguiente:
12
[RVLCN]
Fig. 22 Si quieres instalar en otra unidad presionamos el bot ón marcado con azul, y si deseamos instalar el RadAsm activaremos la casilla marcada con negro, luego damos clic en el bot ón Instalar (marcado con amarillo). Radasm Se instala en la misma carpeta donde hemos instalado masm32, por ejemplo:
Ya no es necesario configurar el RadAsm, ya esta listo para trabajar con el.
[ Recordatorio ] Si tienes Dudas, sugerencias, otros, hacerlas en lista.
13
[RVLCN]
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com http://RVLCNsecurity.com http://beam.to/RVLCN http://beam.to/REVOLUCION Julio-2006
Copyright(c) 2005-2006 RVLCN
1
[RVLCN]
CLASES de ProgramaciOn CON MASM+Radasm Capitulo II: Nuestra Primera Aplicacion. Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL
2
[RVLCN]
[ Estructura de nuestros Programas] Para crear un programa en MASM32 se debe seguir una estructura que pueda entender nuestro compilador por ejemplo: .386 .model flat, stdcall option casemap:none include windows.inc include kernel32.inc includelib kernel32.lib .data .code Prog001: invoke ExitProcess,0 end Prog001 Con ese código ya hemos creado un programa que pueda entender nuestro compilador y así crear nuestra aplicaci ón, ahora explicare para que sirve cada una de las secciones del c ódigo: .386.- Esta directiva sirve para establecer el tipo de procesador y sus instrucciones con lo que se va a trabajar, en esta caso 80386. .model flat, stdcall.- Aquí establecemos el modelo de memoria requerido para nuestros programas de 32 bits. option casemap:none.- Esta opción hace sensible las mayúsculas de las minúsculas es decir que por ejemplo “Z” es diferente a “z”. Include y Includelib.- MASM32 incluye archivos y librer ías para manejar un gran numero de funciones que existen en Windows, a estas funciones se les llama APi, como por ejemplo la API ExitProcess que esta en nuestro c ódigo. El include se utiliza para agregar archivos con extensi ón .inc y .asm El includelib se utiliza para agregar librer ías con extensión .lib MASM32 también incluye el archivo window.inc donde encontramos un gran numero de constantes y estructuras usadas por las funciones de Windows (API). .data.- Existen dos tipos de información, la información inicializada y la no inicializada (.data?).
3
[RVLCN]
1.- Información Inicializada (.data).- En esta secci ón declararemos los datos que conocemos con los que inicia nuestro programa por ejemplo: .data Etiqueta MsgTexto Valor_1
Tipo de variable db dd
Datos inicializados “BiENVENIDO AL CURSO DE MASM + RADASM ”,0 7
2.- Información No Inicializada (.data?).- En esta Sección declararemos los datos que no conocemos o que vamos a escribir cuando el programa se ejecute usualmente lo utilizamos para almacenar datos, por ejemplo: .data? Etiqueta Buffer Valor_1
Tipo de variable db dd
Datos No inicializados 128 dup (?) ?
.code.- Después de la secci ón de datos debes indicar a MASM32 donde empieza el código del programa y tambi én donde termina, para ello he puesto la etiqueta Prog001 seguido de “:”, para indicarle que abajo empieza el c ódigo de nuestro programa, y al terminar el c ódigo del programa se escribe end mas la etiqueta que hemos declarado quedando de esta manera: end Prog001.
[ Programando en RadAsm] 1.- A nuestro código anterior implementaremos una nueva funci ón para que muestre una ventana que nos de la bienvenida, para ello abrimos el RadAsm.exe, y comencemos programar como muestra el video:
Prog001.exe
4
[RVLCN]
[ Explicando el video Prog001.exe] En nuestro programa que hemos desarrollado se ha utilizado 2 funciones: MessageBox ExitProcess Si abrimos nuestra documentaci ón de las Apis de Windows (Win32 programmer ’s Reference) y buscamos la función MessageBox encontramos lo siguiente:
int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ); HWND.- Este par ámetro sirve para identificar el manejador de la ventana padre, nuestro caso colocamos NULL ó “0” por que no tiene manejador (handle). LpText.- Aquí colocamos la direcci ón donde se encuentra nuestro mensaje. LpCaption.- En este par ámetro funciona igual que lpText la diferencia que este es el titulo del mensaje uType.- Este par ámetro es muy útil al momento de crear nuestra ventana sirve para personalizar nuestro mensaje. Podemos especificar que tipo de botones deseamos y tambi én el icono, por ejemplo en nuestro programa se ha puesto las siguientes constantes: Botones Icono Estas constantes están declaradas en el archivo window.inc MB_OK MB_ICONINFORMATION Para saber más sobre esta funci ón le sugiero que revise la documentaci ón que mencione anteriormente. Todo programa que escribimos en MASM32 debemos colocarle la siguiente función: VOID ExitProcess( UINT uExitCode );
5
[RVLCN]
Con esta función cerramos nuestro programa, en el par ámetro uExitCode se especifica el código de salida, en nuestro caso se ha puesto 0. invoke.- MASM32 también tiene un sintaxis de alto nivel, que nos facilita llamar a nuestras funciones de forma correcta, es decir que al momento de compilar MASM32 comprobara si los par ámetros de nuestra función son los correctos y se emplea de esta manera: INVOKE FUNCION, Argumentos FUNCION.- Es aquí donde escribiremos el nombre de la funci ón que se va ah utilizar . Argumentos.- Los argumentos son los par ámetros de las funciones y est án separadas por comas “,”. 1.-Operadores en el archivo prog001.asm: addr .- Este operador sirve para pasar la direcci ón de nuestra etiqueta hacia nuestra función por ejemplo las etiquetas MsgTexto y MsgTitulo. offset.- Es similar al addr pero con algunas diferencias como muestra el siguiente cuadro. addr No puede ser utilizado con instrucciones mnemonic Trabaja Solo con referencias que est én delante del código. Puede operar con estructuras.
offset Se utiliza con instrucciones mnemonic Trabaja con referencias que est én delante y atr ás del código. No puede operar con estructuras.
2.-Operadores en el archivo prog001.inc: Windows tiene una gran cantidad de APi en nuestro sistema que son empleados por todos los programas de Windows, y estas APi o funciones la encontramos en las librer ías de enlace dinámico (dynamic-linked libraries “DLL”), como por ejemplo: user32.DLL, kernel32.DLL, shell32.DLL, y nosotros para poder usar las funciones en nuestros programas necesitamos agregar 2 archivos para cada librer ía: user32.inc y kernel.inc.- En estos archivos encontramos todas las funciones declaradas que pertenecen a user32.dll y kernel32.dll respectivamente, esto nos ahorra tiempo al momento de programar por que nos evita estar declarando las funciones que vamos a emplear, pero observemos su contenido para ver que contiene, para ello debemos abrimos los archivos .inc: Para abrir el archivo se ñalamos el nombre del archivo .inc que queremos abrir y presionamos el bot ón derecho del Mouse, se despliega un men ú contextual donde hacemos clic a la opci ón Abrir , como muestra la siguiente imagen:
6
[RVLCN]
Fig. 1 Luego se abre una nueva ventanita en el RadAsm mostrando lo siguiente:
Fig. 2
7
[RVLCN]
Buscaremos nuestra API MessageBox presionando las teclas CTRL + F y escribimos la función que vamos a buscar, como muestra la siguiente imagen:
Fig. 3 Luego damos clic en el bot ón hallar y encontramos lo siguiente:
Fig. 4 Ya hemos encontrado nuestra funci ón y comprobado que esta API esta declarado en el user32.inc, si buscamos la otra API que hemos utilizado ExitProcess no lo encontraremos por que esa API esta en Kernel.inc. user32.lib y kernel.lib.- Para que nuestro programa se pueda enlazar a las librer ías de uso dinámico de Windows, necesita informaciones como el nombre de la función y la dirección donde se encuentra, para que al momento de ejecutar nuestro programa cargue la Liberia inmediatamente. Esta informaci ón que he mencionado se encuentra en los archivos .lib.
[ Variables ] Tipo BYTE WORD DWORD FWORD ó REAL4 QWORD ó REAL8 TBYTE ó REAL10
Tipos de Variables Abreviatura Espacio DB 1 byte ó 8 bits DW 2 bytes ó 16 bits DD 4 bytes o 32 bits DF 6 bytes o 48 bits DQ 8 bytes o 64 bits DT 10 bytes o 80 bits
Descripci ón Cadenas de texto y caracteres Valor entero en el rango: -32, 786 a +65, 535 Valor entero en el rango: -2gb a +4gb 48 bit con punto flotante 64 bit con punto flotante 80 bit con punto flotante
8
[RVLCN]
Veamos unos ejemplos de c ómo se debe declarar las variables ( en la secci ón .data y en .data?):
EJEMPLO EN DATOS INICIALIZADOS .data Cadena db Valor dd Punto df
“BiENVENIDO
AL CURSO DE MASM + RADASM ”,0
77 4.575 Que viene hacer lo mismo :
.data Cadena Valor Punto
BYTE DWORD REAL4
“BiENVENIDO
AL CURSO DE MASM + RADASM ”,0
77 4.575
EJEMPLO EN DATOS NO INICIALIZADOS .data? Acumulador db Contador dd FlotanteP df
? ? ? Que viene hacer lo mismo :
.data? Acumulador Contador FlotanteP
BYTE DWORD REAL4
? ? ?
[ Creando plantilla en RaDAsm ] El programador de Radasm ah pensado en todo y para no volver a escribir toda la estructura de nuestros programas cada vez que queremos programar, crearemos una plantilla como lo hago en el siguiente video:
9
[RVLCN]
Creando Plantilla.exe Si queremos ir a la carpeta donde esta nuestro c ódigo fuente abrimos el men ú Proyecto/Explorar Path como muestra la imagen:
Fig. 4
Y abre la carpeta donde tenemos nuestro c ódigo fuente:
10
[RVLCN]
Fig.5 2.- En el ejercicio anterior se ha utilizado los datos inicializados, ahora falta crear un ejemplo utilizando los datos no inicializados:
Prog001a.exe Se ha utilizado en el ejemplo Prog001a la función GetModuleFileName y se declara de la siguiente manera: Librer ía Kernel32.lib
GetModuleFileName,NULL,addr Buffer ,225 Esta función extrae el directorio m ás el nombre de la aplicaci ón, y la devolver á en la variable Buffer , si ya fue ocupada la modificara y pondr á nuevos caracteres, el valor 225 significa la longitud m áxima de caracteres que va a devolver. Buffer cumple la funci ón de almacenador de datos, donde almacenara la cadena de texto devuelta por la funci ón que sea utilizado.
11
[RVLCN]
3.- Hagamos nuestro programa m ás grande y un poco m ás complejo para el siguiente ejemplo, para ello utilizaremos la librer ía masm32.lib. Masm32 tiene su propia librer ía donde podemos encontrar muchas funciones útiles que muchas veces necesitamos y no la tomamos en cuenta, en el siguiente video utilizaremos algunas de estas funciones, para ello Vamos a Crear un programa que muestre el directorio en un mensaje y en otro mensaje el nombre de la aplicaci ón que se esta ejecutando:
prog002.exe
[ Funciones Utilizadas video prog002.exe ] Librer ía MAsm32.lib
GetAppPath,addr Buffer Esta función devuelve el directorio de la aplicaci ón y lo ara en la variable que hemos puesto en este caso Buffer y se quedara almacenado hasta que otra función remplace el dato que contiene la variable. Librer ía MAsm32.lib
NameFromPath,addr Buffer ,addr NombreApp Como sabemos Buffer contiene el nombre mas el directorio de la aplicaci ón por que ya fue utilizada por la API GetModuleFileName , y la función NameFromPath extraer á solo el nombre y la almacenara en la variable NombreApp.
12
[RVLCN]
Operador DUP.- significa duplicaci ón, se utiliza para separar espacios en la memoria y su sintaxis es de esta manera: Sintaxis: Contador dup (valor inicial) En contador escribimos el tama ño que vamos a duplicar, y el valor inicial lo escribimos dentro del par éntesis si se pone el signo ? significa que es un valor indefinido. En nuestro código se ha declarado de la siguiente manera: Etiqueta Buffer NombreApp
Variable db db
Contador 225 50
DUP dup dup
Valor Inicial (?) (?)
Y significa lo siguiente: En la variable Buffer se ha separado 225 bytes en la memoria y en la Variable NombreApp se ha separado 50 bytes en la memoria. Recomiendo que si se va ha utilizar una variable para almacenar todo tipo de cadenas de texto devueltas por las funciones, las variables declaradas tengan un espacio considerable a lo que se va obtener. Te preguntaras por que se hace esto, pues cuando utilices m ás variables en tu código, si no le has separado un espacio considerable en la memoria a dicha variable que vas ha utilizar, la cadena de texto devuelta muchas veces invade las otras variables y esto te puede ocasionar problemas.
[ Ejercicio ] Utilizando la ayuda Win32 programmer ’s Reference, para saber el uso y par ámetros que corresponden a las funciones haga estos ejercicios: 1.- Crear nuevos mensajes, utilizando la API MessageBox, ejemplo prog001a:
Fig.6 2.- En el programa anterior agr égale la API MessageBeep, en el lugar donde usted quiera.
13
[RVLCN]
3.- Cree un programa que muestre el directorio de Windows en un mensaje y después debe mostrar el directorio del sistema en otro mensaje, utilice las funciones: GetWindowsDirectory y GetSystemDirectory
[ Vocabulario ] API (Application Programming Interface).- Interfaz de Programaci ón de Aplicaciones, son funciones de uso general que se encuentran en nuestro sistema Windows, y est án almacenadas en librer ías como por ejemplo user32.dll y kernel32.dll. Sintaxis.- Es una forma de combinaci ón de las palabras seg ún las reglas establecidas por el lenguaje de programaci ón. Mnemonic (Nem ónico).- En el lenguaje ensamblador, las instrucciones se representan por nemónicos o combinaciones de las letras que recuerdan el significado de la instrucci ón en ingles.
[ Recordatorio ] No olvidar preguntar en la lista MASM32-RadASM, las soluciones de estos ejercicios ser án enviados a la lista dentro de una semana, tambi én puedes enviar tus propias soluciones. Si tienes Dudas, sugerencias, otros, tambi én hacerlas en lista.
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com http://RVLCNsecurity.com http://beam.to/RVLCN http://beam.to/REVOLUCION
Julio-2006
Copyright(c) 2005-2006 RVLCN
1
[RVLCN]
Clases de ProgramaciOn CON MASM+Radasm Capitulo III: Registros del MicroProcesador Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk
DESCARGO LEGAL
2
[RVLCN]
[ Registros del Microprocesador ] Nuestro procesador necesita registros para almacenar datos, y pueden ser utilizados libremente. Entre los principales registros tenemos: Registros de Propósitos generales. Son 4 registros EAX, EBX, EDX, ECX y se emplea para uso general, y se subdividen en: EAX, EBX, ECX,EDX (32 bits ) AX, BX, CX, DX (16 bits) AH, BH, CH, DH (8 bit, H = Hight ). AL, BL, CL, DL (8 bit L = Low).
Ejemplo EAX = 12345678 AX = 5678 AH = 56 AL = 78 El procesador 80368 permite el uso de estos registros: EAX, EBX, ECX, EDX que son de 32 bits. Registros de uso general EAX (Acumulador)
Descripci ón
Es utilizado para operaciones aritm éticas (suma, resta, división, multiplicación). Algunas Funciones después de ser utilizadas devuelven un valor a EAX. EBX (Base) Se utiliza para direccionar el acceso a datos, situados en la memoria, tambi én se puede utilizar para operaciones aritm éticas. ECX (Contador) Se utiliza como contador por algunas instrucciones, tambi én es utilizado para operaciones aritm éticas. EDX (Datos) Algunas operaciones de entrada/salida requieren su uso, y las operaciones de multiplicaci ón y divisi ón con cifras grandes suponen al EDX y al EAX trabajando juntos. Puede usar los registros de propósitos para suma y resta de cifras de 8, 16, 32 bits. Registros de Indice Descripci ón ESI El registro índice de 16 bits es requerido por algunas operaciones con cadenas (de caracteres). EDI El registro índice destino tambi én es requerido por algunas operaciones con cadenas de caracteres. Registro de banderas Descripci ón Se usa para registrar la informaci ón de estado y de control de las operaciones del microprocesador, y son 9, CF, OF, ZF, SF, PF, AF, DF, IF, TF.
3
[RVLCN]
[ Instrucciones del Microprocesador ] Las instrucciones son secuencias de bits (unos y ceros), e indican que operación debe hacer y con que dato se debe realizar la operaci ón, por ahora veremos 11 instrucciones: MOV (Mover)
Destino
Fuente
Esta instrucción MOV significa mover y se encarga de pasar el contenido del operando Fuente al de Destino. En la programaci ón debemos respetar las siguientes reglas:
Destino.- Puede ser variables y registros de 8, 16 y 32 bits. Fuente.- Puede ser variables, registros de Windows y valores enteros. ADD (Suma)
Destino
Fuente
La instrucción ADD significa Suma. Suma el contenido de los dos oper ándos y el resultado es remplazado en el operando Destino.
Destino.- Puede ser variables y registros de 8, 16 y 32 bits. Fuente.- Puede ser variables, registros de Windows y valores enteros. SUB (Resta)
Destino
Fuente
La instrucción SUB significa Resta. Resta el contenido del operando Fuente con la de Destino y el resultado es almacenado en el operando Destino. Destino.- Puede ser variables y registros de de 8, 16 y 32 bits Fuente.- Puede ser variables, registros de Windows y valores enteros. INC (Incrementa 1)
Destino
DEC (Decrementa 1)
Destino
Estas instrucciones incrementas y decrementan respectivamente el valor contenido en el operando Destino. Destino.- Puede ser variables y registros de 8, 16 y 32 bits. PUSH (Guarda)
Fuente
PUSH se encarga de guardar el contenido del operando Fuente, en la Pila. Fuente.- Puede ser variables, valores enteros y registros de 16 y 32 bits.
4
[RVLCN]
POP (Recupera)
Destino
Al contrario de PUSH, esta instrucci ón recupera el contenido guardado en la pila. Destino.- Puede ser variables y registros de 16 y 32 bits. Cuando se guarda varios valores con la instrucci ón PUSH y si se quiere recuperar se utiliza la instrucci ón POP , respetando la siguiente regla: “ Ultimo
en guardar y primero en recuperar ”
Instrucciones Lógicas: Utiliza la calculadora de Windows (modo cient ífica) para pasar en los sistema decimal, hexadecimal y binario las cantidades expresadas. AND
Destino
Fuente
Realiza la operaci ón Lógica AND entre los oper ándos Fuente y Destino de bit a bit, y el resultado es remplazado en el operando Destino.
TABLA DE VERDAD AND A B Resultado 0 0 0 0 1 0 1 0 0 1 1 1 Ejemplo:
1110 (14 en decimal o E hexadecimal). 1101 (13 en decimal o D hexadecimal). 1100 (12 en decimal o C hexadecimal). OR
Destino
Fuente
Realiza la operaci ón l ógica OR inclusiva entre los oper ándos de bit a bit, y el resultado es remplazado en el operando Destino.
TABLA DE VERDAD OR A B Resultado 0 0 0 0 1 1 1 0 1 1 1 1
5 Ejemplo:
[RVLCN]
1110 (14 en decimal o E hexadecimal). 1101 (13 en decimal o D hexadecimal). 1111 (15 en decimal o F hexadecimal).
NOT
Destino
La instrucción NOT invierte los bits en el operando Destino. TABLA DE VERDAD NOT A Resultado 1 0 0 1
Ejemplo:
1101 (13 en decimal o D hexadecimal). 0010 (2 en decimal). XOR
Destino
Fuente
Realiza la operaci ón lógica XOR exclusiva entre los oper ándos bit a bit, y el resultado es remplazado en el operando Destino. TABLA DE VERDAD XOR A B Resultado 0 0 0 0 1 1 1 0 1 1 1 0
Ejemplo:
1110 (14 en decimal o E hexadecimal). 1101 (13 en decimal o D hexadecimal). 0011 (3 en decimal).
Todas las operaciones lógicas que hemos visto tienen la siguiente regla: Fuente.- Puede ser variables, valores y registros de 16 y 32 bits Destino.- Puede ser variables y registros de 16 y 32 bits.
[ Ejercicios Con Instrucciones] Abrimos el archivo prog002a con nuestro IDE RadAsm donde encontramos lo siguiente: En el archivo .INC hemos declarado la variable Valor_1 tipo DD
6
[RVLCN]
prog002a: ;##################[Operaciones Aritm éticas]################ MOV EAX,444 ; EAX = 444 ADD EAX,333 ; EAX = 444 + 333 = 777 MOV Valor_1,EAX ; Movemos el Resultado en la ; variable Valor_1 = EAX = 777 MOV EBX,15Dh ; EBX = 15Dh MOV EAX,20Ch ; EAX = 20Ch ADD EAX,EBX ; EAX = 20Ch + EBX = 15Dh = 369h PUSH EBX ; Guardamos el contenido del Registro EBX = 15Dh ; en la Pila. DEC EAX ; Decrementamos 1 a EAX = 369h - 1 = 368h INC EBX ; Incrementamos 1 a EBX = 15Dh + 1 = 15Eh SUB EAX, EBX ; Restamos EAX = 368h - EBX = 15Eh = 20Ah POP EBX ; Recuperamos el contenido de la Pila al ; registro EBX SUB EBX,10 ; Restamos EBX = 15Dh - 10 =153 Cuando se quiere declarar n úmeros en Hexadecimal debemos escribir el car ácter h al final del valor, si no hay ning ún car ácter al final significa que es decimal. ;##################[Operaciones L ógicas]################ MOV EAX,12 ;12 = 1100b MOV EBX,11 ;11 = 1011b AND EAX,5 ; EAX=12 (1100b) And 5(0101b) = 4 (0100b) OR EAX,EBX ; EAX= 4(0100b) OR EBX 11(1011b) = F(1111b) OR EBX,1101b ;EBX = 11(1011b) OR 13(1101b) = F(1111b) XOR EAX, EBX ;EAX = F(1111b) XOR EBX = F(1111b) = 00000 PUSH -2 ; Guardamos en la Pila el valor -2 POP EBX ; Recuperamos el Valor Guardado en la pila ; En el registro EBX NOT EBX ; NOT EBX = -2 = 1
Cuando se quiere declarar n úmeros binarios debemos escribir el car ácter b al final del valor entero. En Las Operaciones l ógicas si desean comprobar los resultados pueden verificar la tabla de verdad correspondiente a cada operación. 1.- En el programa anterior es solo un ejemplo de usar apropiadamente las instrucciones, ahora debemos darle sentido a nuestro programita: Tenemos 5 valores enteros: 1.- 1Ah 2.- 500 3.- 1C2h 4.- 13h 5.- 200
7
[RVLCN]
Haremos un programa que haga la siguiente operaci ón: 1Ah + 500 = X El resultado X restamos 1C2h: X – 1C2 = Y Guardamos el resultado Y en la pila o en una variable, y luego sumaremos las cantidades que todav ía no utilizamos de esta manera: 13h + 200 = Z Recuperamos el resultado Y, y lo restamos con la cantidad del resultado Z, el resultado final debe ser almacenado en el registro EAX. Soluci ón 1 prog002b.- En el archivo .inc declaramos la variable “Y” tipo DD. prog002b: mov eax,1Ah ; EAX = 1AH add eax,500 ; EAX = 1Ah + 500 = 526 sub eax,1C2h ;EAX = 526 – 1C2 = 76 mov Y, eax ;Y (variable) = EAX = 76 mov eax, 13h ; EAX = 13H add eax,200 ; EAX = 13H + 200 = 219 sub eax ,Y ; EAX = 219 - Y (76) = 143 El resultado final es EAX =143. Soluci ón 2 prog002c.- todas las cantidades están declaradas en el archivo .inc de nuestro programa donde: Valor_1 DD 1Ah Valor_2 DD 500 Valor_3 DD 1C2h Valor_4 DD 13h Valor_5 DD 200 prog002c: mov eax,Valor_1 ; EAX = 1Ah add eax,Valor_2 ; EAX = 1Ah + 500 = 526 sub eax,Valor_3 ;EAX = 526 – 1C2 = 76 push eax ; Guardamos en la pila el contenido de EAX = 76 mov eax,Valor_4 ; EAX = 13H add eax,Valor_5 ; EAX = 13H + 200 = 219 pop ebx ; Recuperamos el contenido de EAX en EBX = 76 sub eax,ebx ; EAX = 219 - Y (76) = 143 Hay muchas soluciones no solo son estas dos, usted si quiere aprender mas debe desarrollar su propia soluci ón.
8
[RVLCN]
[ Mostrando Resultados ] En nuestro c ódigo anterior no mostramos el resultado de la operaci ón aritmética, para ello debemos saber las siguientes funciones de conversiones del masm32.lib
Librer ía MAsm32.lib
atodw,addr Numero_decimal Esta función convierte cadenas de texto (cantidades decimales), a su valor entero, la cantidad convertida ser á devuelta en EAX. Ejemplo: .data Numero_decimal db “10”,0 .code Invoke atodw,addr Numero_decimal mov ebx, eax ;EAX contiene el valor entero 10 o Ah Librer ía MAsm32.lib
htodw,addr Numero_Hexadecimal Esta función es similar a atodw pero trabaja con cantidades hexadecimales, y la convierte a su valor entero, la cantidad convertida ser á devuelta en EAX. Librer ía MAsm32.lib
dwtoa,Cantidad,addr Numero_Convertido_decimal Esta función convierte valores enteros en cadenas de texto decimal, seria lo contrario de la función atodw.
Cantidad.- En este par ámetro se puede utilizar variables, valores enteros y registros de Windows. Ejemplo: Caso1.- valor entero:
Invoke dwtoa,12, addr Numero_Convertido_decimal Caso2.- Variables tipo DD: Invoke dwtoa, Valor_1, addr Numero_Convertido_decimal Caso2.- Registros de Windows: Invoke dwtoa, EAX, addr Numero_Convertido_decimal
9
[RVLCN]
Librer ía MAsm32.lib
dw2hex, Cantidad,addr Numero_Convertido_Hex Esta función contiene los mismos par ámetros de la funci ón dwtoa, con la diferencia que el resultado es una cantidad de texto hexadecimal, viene hacer lo contrario de la funci ón htodw. En los siguientes ejemplos utilizaremos todas las funciones mencionadas, presta mucha atención cada detalle. 1.- En el ejercicio anterior mostraremos el resultado en decimal y Hexadecimal en un mensaje:
2.- Haremos un programa que sume cadenas de texto con cantidades decimal y hexadecimal, al final debe mostrar el resultado:
prog003.exe
10
[RVLCN]
En el ejemplo (prog003.exe), observamos que tenemos cantidades en decimal y hexadecimal (cadenas de texto), y luego para sumar dichas cantidades convertimos a valores enteros con las funciones atodw y htodw para que podamos operar con las instrucciones de procesador como la de sumar ( ADD) y mover (MOV), luego para mostrar el resultado debemos convertir los valores enteros a cadenas de texto con las funciones dwtoa y dw2hex respectivamente: Esquema de trabajo:
Veamos otro ejemplo de conversiones, recuerda siempre estar atento a cada detalle del video:
prog003a.exe
Se ha trabajado directamente con valores enteros declarados en nuestro archivo .inc, cuyas cantidades hemos sumado, luego para mostrar el resultado hemos convertido en cadenas de texto dwtoa y dw2hex, respectivamente.
11
[RVLCN]
Esquema de trabajo:
Eso tenemos en cuento a conversiones de valores enteros a cadenas y viceversa Nota: Nunca podemos mostrar valores enteros, para hacerlo debemos convertir a cadenas de texto.
[ Creando Tus propias Funciones ] 1.- Ahora crearemos una funci ón que muestre un mensaje, esta función tendr á un par ámetro donde ira la direcci ón de la etiqueta del mensaje, dentro de la función que vamos a crear se encontrara la APi MessageBox que ser á el encargado de mostrar el mensaje.
prog004.exe
12
[RVLCN]
Como observamos en el video primero declaramos la funci ón que vamos a utilizar: Funcion PROC MsgT:DWORD invoke MessageBox,NULL,MsgT,addr MsgTitulo, \ MB_OK + MB_ICONINFORMATION RET Funcion endp PROC.- Esta directiva sirve para definir un procedimiento o llamado que se va ha utilizar y su sintaxis es así: Nombre_Funcion PROC Argumento/s (si lo hubiera) RET Nombre_Funcion endp Si nuestra función necesita un par ámetro su sintaxis seria así: Nombre_Funcion PROC Parametro01: Tipo de variable RET Nombre_Funcion endp Si en nuestra funci ón necesitamos más de 1 par ámetro, es necesario separar por “,” (comas) cada par ámetro de esta manera:
Nombre_Funcion PROC Prmtr01: Tipo de variable, Prmtr02: Tipo de variable, etc… RET Nombre_Funcion endp Tipo de variable.- Aquí declaramos la longitud de bytes que se necesita ya sea DWORD, WORD, BYTE, por lo general siempre se declara la variable que tenga mayor longitud como DWORD. Nombre_Funcion.- Aquí escribimos nuestra etiqueta para el nombre de la función, recuerda que esta etiqueta no debe repetirse y la etiqueta de los par ámetros no deben ser declaradas en otra parte del código. RET (retorno)
Nº Bytes
Con esta Instrucci ón regresamos del procedimiento que hemos llamado también lo utilizamos para separar nuestros c ódigos, como en el primer RET
13
[RVLCN]
que esta debajo de la funci ón ExitProcess, en el operando Nº Bytes opcional ahí se especifica cuantos bytes debe retornar.
es
Otro punto importante es que si utilizamos algunos de las variables que hemos declarado en los par ámetros del procedimiento de la funci ón como por ejemplo MsgT ya no es necesario utilizar addr u offset , como por ejemplo la variable que he utilizado en el 3er par ámetro de la Api MessageBox : invoke MessageBox,NULL,MsgT ,addr MsgTitulo, \ MB_OK + MB_ICONINFORMATION Ya hemos creando nuestra función, y si queremos utilizarla con la directiva invoke como lo hicimos en el video: invoke Funcion,addr MsgTexto Es necesario declarar los prototipos con la directiva PROTO. PROTO.- Sirve para definir los prototipos de las funciones para que se pueda usar el invoke, también informa a MASM el número de argumentos y el tipo de variable que debe emplearse al momento de llamar a la funci ón, su sintaxis es de esta manera: Nombre_Funcion PROTO Argumento/s (si lo hubiera) Es similar a la directiva PROC y es por que trabajan juntos pero la diferencia es que solo se declara tipo de variables, el número de variables que declaramos depende de los par ámetros de la función por ejemplo: invoke Funcion,addr MsgTexto Solo contiene un par ámetro y lo definimos de esta manera: Funcion PROTO :DWORD
Si nuestra función tuviera más de un par ámetro se declara las variables separados por “,” (coma) por ejemplo la funci ón MessageBoxA que esta en el archivo user32.inc cuando nosotros la utilizamos nos damos cuenta que tiene 4 par ámetros: MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
Nota.-No olvides que se debe respetar las may úsculas y las minúsculas cuando nos referimos a la cualquier variable o l nombre de la funci ón, por que si no lo haces al momento de compilar masm32 nos devolver á error.
14
[RVLCN]
2.- Crearemos una funci ón que reste 2 cantidades, y adem ás al regresar de la función el resultado debe ser devuelto al registro EAX y al final debe mostrar el resultado en decimal.
Prog004a.exe Dentro de nuestra funci ón Resta, hemos puesto 2 instrucciones para poder restar dichas cantidades, nosotros ya sabemos como se utiliza estas instrucciones por lo cual esta de mas explicarlo, luego el resultado es almacenado en EAX y al retornar de la funci ón convertimos el valor entero a cadenas de texto (recuerda que la funci ón de conversión esta en la librer ía masm32.lib), para poder mostrar el resultado con la APi MessageBox. Nota.- En la funci ón que hemos creado no solo se puede usar valores, tambi én variables y registros de 8, 16, 32 bits por que todo eso abarca en DWORD.
[ Ejercicios ] 1.- Tenemos 3 cantidades 800, 400, 100 (decimales), en cadenas de texto y queremos un programa que haga la siguiente operaci ón: 800 – 450 = X Y el resultado X debe ser restado100 resultando Y, este resultado debe ser mostrado. 2.- Crear un programa que sume 5 cantidades y la sumatoria de dichas cantidades ser á restado por 225 en decimal, las 5 cantidades se puede usar cualquier valor entero que se te ocurra ya sea en decimal o hexadecimal, si deseas mostrar el resultado hazlo.
15
[RVLCN]
3.- Crear una funci ón que tenga 2 par ámetros para que muestre un mensaje por lo tanto: El primer par ámetro.- Aquí se colocara la direcci ón de la etiqueta del Mensaje que se va mostrar. El segundo par ámetro.- Se colocara la direcci ón de la etiqueta del titulo del mensaje.
[ Vocabulario ] Pila o stack.- La pila viene hacer un rango de memoria la cual puede ser utilizada para el almacenamiento temporal de datos, solo 2 instrucciones trabajan con la pila y son el PUSH (guarda) y POP (recupera).
[ Recordatorio ] No olvidar preguntar en lista MASM32-RadASM y enviar sus ejemplos del ejercicio que se ha dejado para subirlas al Site RVLCN, la duraci ón en este caso es de 2 semana la tercera semana empiezan los desaf íos de programaci ón.
Dudas, sugerencias, otros, hacerlas en lista.
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com www: http://RVLCNsecurity.com www: http://beam.to/RVLCN http://beam.to/REVOLUCION
Julio-2006
16
[RVLCN]
Copyright(c) 2005-2006 RVLCN
clases de ProgramaciOn CON MASM+Radasm Capitulo IV: Condiciones y bluces.
Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL
Masm32 también puede utilizar el bloque .if (condici ón) y tambi én .while, .repeat/.until (bluces) aprenderemos 2 formas de c ómo utilizarlas, la primera ser á utilizando bloques y la otra es usando instrucciones CMP y JXX.
[ Condiciones ] Usando el bloque .IF.- MASM puede hacer comparaciones simples y complejas en forma f ácil y su sintaxis es de esta manera: Una comparación simple seria de esta manera: Simple .if Condicion ; Si cumple la condici ón ara algo ac á. .endif
Simple mas .else .if Condicion ; Si cumple la condici ón ara algo ac á. .else ; Si no cumple la condici ón ara algo ac á. .endif
Si deseas hacer comparaciones secuenciales: Secuencial .if Condicion ; Si cumple la condici ón ara algo ac á .elseif Condicion ; Si cumple la condici ón ara algo mas. .endif
Secuencial mas .else .if Condicion ; Si cumple la condici ón ara algo ac á .elseif Condicion ; Si cumple la condici ón ara algo mas .else ; Si no cumple con ninguna condici ón ara algo acá. .endif
Antes de entrar con los ejercicios observemos la siguiente tabla de operadores para las comparaciones: Operadores de comparaci ón == != > >= < <= &&
igual No igual Mayor Mayor o igual Menor Menor o igual Operadores de Multi - comparaci ón Lógico AND “Y”
||
Lógico OR “ó” Operador para verificar el estado de las banderas (flags) del procesador CARRY? Carry bit set OVERFLOW? Overflow bit set PARITY? Parity bit set SIGN? Sign bit set ZERO? Zero bit set
En el siguiente ejercicio haremos una serie de comparaciones, pare ello utilizaremos la librer ía rvlcnrand.lib para generar valores enteros aleatorios, los algoritmos de generado fue creado por Randall hyde desarrollador del compilador HLA (high Level Assembly) y pasado a masm por mi persona.
Función randzime
random
range
uniform
urange
Librer ía rvlcnrand.lib Descripci ón Con esta función creamos un punto al azar o semilla para que puedan ser utilizado por las 4 funciones siguientes: random, range, uniform, urange. De esta manera siempre podr á generar en forma aleatoria. Genera números al azar uniformemente distribuido utilizando un algoritmo lineal, el resultado es devuelto en EAX. Invoke random Genera un número al azar usando la funci ón random, teniendo en cuenta el rango establecido, el resultado es devuelto en EAX. Invoke range, inicio, final Esta función genera un nuevo n úmero al azar en cada llamada uniformemente distribuido, el resultado es devuelto en EAX. Invoke uniform Genera un número al azar usando la funci ón urange, teniendo en cuenta el rango establecido, el resultado es devuelto en EAX. Invoke urange, inicio, final
Ejemplo:
prog005_ha_c.exe Analizando prog005.- Como ya habíamos visto en la ayuda “win32programmer ’s Referenced” la función Messagebox una vez ejecutado devuelve a EAX el valor del bot ón que hemos presionado, para recordar:
Fig.01 invoke MessageBox …. .if eax==IDYES ;Compara si EAX es igual a la Constante IDYES invoke MessageBox …. .endif Lo que hace es comparar si hemos presionado el bot ón Yes o Si en español, y si cumple la condici ón mostrara el mensaje que hemos puesto.
Analizando prog005a.- Este programa es id éntico al ejercicio anterior, solo hemos agregado el bloque .else en caso que la condici ón no se cumpliera. invoke MessageBox … .if eax==IDYES ;Compara si EAX es igual a la Constante IDYES invoke MessageBox …. .else ;Si no cumple con la condici ón: invoke MessageBox ….. .endif Si nuestra primera condici ón no se cumple mostrara el otro mensaje que esta debajo del bloque .else.
Analizando prog005b.- En este ejercicio hemos utilizado el bloque .elseif , para realizar varias comparaciones, por que la funci ón Messagebox contiene 3 botones diferentes y EAX puede tomar cualquiera de esos 3 valores. invoke MessageBox ….. .if eax==IDYES ;Compara si EAX es igual a la Constante IDYES invoke MessageBox ….. .elseif eax==IDNO ;Compara si EAX es igual a la Constante IDNO invoke MessageBox ….. .endif El botón Cancel no lo hemos tomado en cuenta en este ejercicio, pero si deseas lo puedes agregar. Analizando prog005c.- En este ejercicio hemos utilizado la librer ía rvlcnrand.lib, pare crear una serie de comprobaciones utilizando la mayor ía de operadores que hemos visto: invoke randzime invoke range,1,20 .if eax > 10 && eax <=15 ;Compara si EAX es mayor a 10 y si EAX es menor ;igual a 15 invoke MessageBox,…. . .elseif eax < 5 ;Compara si EAX es menor a 5 invoke MessageBox,..… .elseif eax == 15 || eax == 16 ;Compara si EAX es igual a 10 o EAX es igual a ;16 invoke MessageBox,…. .elseif eax >= 19 ;Compara si EAX es mayor o igual a 19. invoke MessageBox,…. .else ;Si no cumple con ninguna condici ón ara lo siguiente: invoke MessageBox,…. .endif
En el primer bloque .if eax > 10 && eax <=15 Si el valor de EAX es mayor a 10 y si es menor igual a 15 mostrara el mensaje, f í jate que el operador && es un enlazador para otra comparación y significa “y”, entonces para que pueda mostrar el mensaje debe cumplir con las 2 condiciones. En el 3er bloque: .elseif eax == 15 || eax == 16 Si el valor de EAX es igual a 15 o si EAX es igual a 16 mostrara el mensaje, también hay otro operador enlazador ||, y significa “ò”, entonces para que pueda mostrar el mensaje debe cumplir con cualquiera de las 2 condiciones. También podemos hacer comparaciones utilizando dos instrucciones: CMP (Compara)
Destino
Fuente
Destino.- Puede ser variables y registros de 8,16,32 bits Fuente.- puede ser variables, registros y valores enteros Esta instrucción compara los dos oper ándos, a su vez modifica las banderas el microprocesador AF, CF, OF, PF, SF, ZF. jxx (salta)
Etiqueta
Esta instrucción salta hacia una direcci ón, veamos la tabla de algunos saltos y significados: Instrucción JA JAE JB JBE JE JG JGE JL JLE JMP JNA JNAE JNB JNBE JNE JNG
Descripción Salta si esta sobre Salta si esta sobre o igual Salta si esta debajo Salta si esta debajo o igual Salta si es igual Salta si es mayor Salta si no es mayor Salta si es menor Salta si es menor o igual Salta directamente Salta si no esta sobre Salta si no esta sobre o igual Salta si no esta debajo Salta si no esta debajo o igual Salta si no es igual Salta si no es mayor
Estado de Bandera CF=0 y ZF=0 CF=0 CF=1 CF=1ó ZF=1 ZF=1 ZF=0 ó SF=OF SF=OF SF != OF ZF=1 ó SF != OF CF=1 ó ZF=1 CF=1 CF=0 CF=0 y ZF=0 ZF=0 ZF=1 ó SF != OF
JNGE JNL JNLE
Salta si no es mayor o igual Salta si no es menor Salta si no es menor o igual
SF != OF SF=OF ZF=0 y SF=OF
Te preguntaras que sirve el estado de bandera o Flag, cada instrucci ón de salto se ejecuta si cumple la condicion por ejemplo: JA se ejecutara cuando la bandera CF sea igual a 0 y ZF también sea igual a cero. JBE se ejecutara cuando bandera CF sea igual a 1 ó ZF sea igual a 1 SI te has fijado que Jmp no tiene condicion, eso significa que esa instrucci ón no necesita ninguna condicion para ejecutarse. Es por eso que la instrucci ón CMP modifica esas banderas para ejecutar el salto que le hemos puesto en la siguiente l ínea. Luego analicemos prog006 donde encontraremos lo siguiente: .code prog006: invoke MessageBox ....... cmp eax, IDYES ; Compara EAX con la constante IDYES jne Fin
; Salta a Fin si no son iguales.
invoke MessageBox,NULL,addr MsgIDYES,addr MsgTitulo,MB_OK Fin: invoke ExitProcess,0 end prog006 Primero utilizamos CMP para comparar EAX con la constante IDYES, si no son iguales saltara a la etiqueta Fin, si coinciden mostrara el mensaje. Este ejercicio seria lo mismo que el prog005 la diferencia es que no hemos utilizado el bloque .if , hagamos lo mismo con el prog005b con instrucciones: .code prog006a: invoke MessageBox,....... cmp eax, IDYES ; Compara EAX con la constante IDYES jne _ElseIF ; Salta a _ElseIF si no son iguales.
invoke MessageBox,NULL,addr MsgIDYES,addr MsgTitulo,MB_OK _ElseIF: cmp eax,IDNO ;Compara EAX con la constante IDNO jne Fin ; Salta a Fin si no son iguales. invoke MessageBox,NULL,addr MsgIDNO,addr MsgTitulo,MB_OK Fin: invoke ExitProcess,0 end prog006a Para hacer comparaciones con instrucciones debemos saber cada significado de los saltos. Ahora utilizaremos las librer ías rvlcnrand.lib para generar un valor aleatorio y la librer ía masm.lib por que se usara la funci ón dwtoa para mostrar el resultado.
.code prog006b: invoke randzime invoke urange,1,15 cmp eax,5 ; Compara EAX con 5 jg Mayor ; Salta si es Mayor invoke MessageBox... jmp Fin ; salta directamente Mayor: cmp eax,10 ; Compara EAX con 10 Jl Menor ; Salta si es menor invoke MessageBox........ jmp Fin ; salta directamente Menor: invoke dwtoa,eax,addr Cmp_03 invoke MessageBox,...... Fin: invoke ExitProcess,0 end prog006b ¿ Cuando Mostrara el Mensaje ?
Mostrara el Mensaje cuando EAX sea menor 5 Mostrara el Mensaje cuando EAX sea mayor 10
Mostrara el valor cuando no cumplan con ninguna condicion.
[ Bluces ] En bluces estudiaremos los bloques .while y el .repeat/.until, para crear lazos que se repita hasta que se cumpla o no la condición que hemos determinado. .while .- Este bloque creara un lazo o bluce siempre y cuando cumpla la condici ón, si en caso no se cumpla terminara el lazo y su sintaxis es as í: .while condicion ; codigo .endw Ejemplo: Mov eax,6 .while eax > 1 sub eax, 1 .endw Este lazo se repetir á siempre y cuando eax sea mayor que 1, si no la cumple el lazo se romper á, si no queremos hacerlo con bloques tambi én podemos hacer con puras instrucciones de esta manera: Mov eax,6 jmp comprueba bluce: sub eax, 1 ; restamos 1 al contenido de EAX comprueba: cmp eax, 1 ja bluce Como apreciamos el bloque .while se produce un salto directamente a la instrucción cmp, luego esta el salto JA (salta si esta sobre), en este caso salta si eax esta sobre 1, este lazo se romper á cuando eax sea 0. .repeat/ .until.- Este lazo funciona al contrario de .while, en este caso el lazo terminara cuando cumpla la condici ón y su sintaxis es as í: .repeat ;codigo .until condicion
Ejemplo: mov eax,0 .repeat add eax, 1 ; sumamos 1 al contenido de eax .until eax > 6
El lazo se romper á hasta que eax sea mayor a 6, como en el bloque .while también podemos hacerlo con instrucciones de esta manera: mov eax,0 bluce: add eax, 1 cmp eax, 6 jnb bluce Veamos el siguiente video con ejemplos de bluces:
prog007_ha_b.exe
Analizando el prog007: Creando bluce con el bloque .while: Librer í a User32.lib
FindWindow,NULL,addr Titulo_ventana
Fig.02 Esta función busca el titulo de la ventana o tambi én la clase de la ventana, y si lo encuentra devuelve el handle de la ventana al registro de EAX, para más información revisen la documentaci ón Win32Programmer Referenced Fig.02.
Línea 9.- Buscamos el titulo de la ventana, si la encuentra devolver á el handle a EAX. Linea10.- Creamos un bluce con el bloque . while, si EAX es mayor a 1 el bluce se realizara siempre y cuando EAX sea mayor a 1, es por eso que se ha puesto nuevamente la funci ón Findwindow antes de .endw en la l í nea 12 para que siga el bluce hasta que ya no encuentra el titulo de la ventana, si no la encuentra EAX sera 0 y el bluce se romper á.
Analizando el prog007a: Creando bluce con el bloque .repeat/.until:
Línea 9.- Creamos un punto al azar o semilla para que pueda crear valores al azar la funci ón range. Línea 10.- La función range devuelve a EAX un valor comprendido desde 0 hasta 100. Este bluce se repetir á hasta que el contenido de EBX sea mayor que EAX, es por eso que se suma 1 a EBX desde 0, como se sabe el valor de EAX se desconoce ese valor es determinado por la funci ón range.
Librer ía kernel32.lib wsprintf
wsprintf ,addr buffer ,addr Msgtexto, ebx Con esta función nosotros pasamos el contenido de ebx a formato ACSII, pero ese no es el único formato al cual podemos pasar. Veamos el siguiente ejemplo:
Ahora mostraremos 2 valores en decimal y hexadecimal, otra cosa importante la función wsprintf solo tiene 2 par ámetros fijos los otros son opcionales solo podemos agregarlos cuando queremos pasar de un formato a otro como por ejemplo estos:
%d para formato decimal %x para formato hexadecimal Nuestra cadena contiene 2 formatos: MsgTexto db "Decimal: %d ; hexadecimal: %x" ,0 Por eso es necesario colocar 2 par ámetros mas a nuestra funci ón en este caso es eax y ebx, veamos como se alinean cada registro con su formato:
En el siguiente ejemplo agregaremos un icono a nuestra aplicaci ón:
[ Agregando un icono ] Nosotros en algunos aplicaciones en nuestra pc hemos visto que tienen sus propios iconos, nosotros tambi én personalizaremos nuestro programa con su propio icono lo que debemos hacer es poner nuestro icono en un recurso. Y lo hacemos de esta manera:
Prog008.exe Nota.- Es importante que nuestro icono este dentro de la carpeta de nuestro proyecto.
[ Agregando una herramienta ] Alguna vez te has preguntado como saber que funciones pertenecen a cada librer ía?. Pues a nuestro RADASM le agregaremos un programa para buscar la función y nos muestre que librer ía agregar.
Add_tools.exe
[ Ejercicios ] 1.- Crea un bluce que se repita 1000 veces con .while y .repeat/.until: 3.- Crea un bluce para que muestre un mensaje 5 veces. 2.- Utilizando la funci ón wsprintf y generando un valor aleatorio, crea un programa muestra un mensaje mostrado el valor en decimal y en hexadecimal:
[ Vocabulario ] handle.- Es el manejador de la ventana, cada ventana de nuestro sistema tiene un handle diferente, es una valor para identificar cada ventana.
[ Recordatorio ] No olvidar preguntar en lista MASM32-RadASM y enviar sus ejemplos del ejercicio que se ha dejado para subirlas al Site RVLCN, en esta semana se estar á enviando las soluciones de los ejercicios anteriores
Dudas, sugerencias, otros, hacerlas en lista.
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM ( Redh@wk ) http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com www: http://RVLCNsecurity.com www: http://beam.to/RVLCN http://beam.to/REVOLUCION
Septiembre-2006 Copyright(c) 2005-2006 RVLCN
1
[RVLCN]
CLASES de ProgramaciOn CON MASM+Radasm Capitulo V: Nuestra primera Ventana. Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL
ó
2
[RVLCN]
[ Nuestra Primera Ventana ] Llego el momento de crear aplicaciones con ventanas y agregarle botones, imágenes y otros controles. Primero crearemos una ventana hecha con puras APIs como muestra el video presta mucha atención:
Prog009.exe Librer ía kernel32.lib
GetModuleHandle, NULL Esta función devuelve el handle del modulo o instancia del programa, todos los programas que utilizan ventanas utilizan esta funci ón, así que el valor devuelto a EAX lo guardamos en una variable en este caso llame Hinstance: mov Hinstance,eax Luego necesitamos utilizar la estructura WNDCLASSEX que contiene toda la información requerida para crear nuestra ventana, esa informaci ón nosotros la ponemos con la instrucci ón MOV, para utilizarla declaramos la etiqueta wc como WNDCLASSEX de esta manera: wc WNDCLASSEX <> Si observamos la ayuda Win32 Programmer ’s Referenced , para saber sobre cada miembro de la estructura mostrara lo siguiente:
3
typedef struct _ WNDCLASSEX { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; } WNDCLASSEX;
[RVLCN]
// wc
1.- cbSize es aquí donde especificamos el tama ño de la estructura cuando no la sabemos el tamaño utilizamos el operador SIZEOF: mov wc.cbSize, SIZEOF WNDCLASSEX 2.- style especificamos el estilo de nuestra ventana hay varios tipos (mirar la ayuda antes mencionada), como por ejemplo utilizamos CS_HREDRAW y CS_VREDRAW si quieres combinarlas podemos utilizar la instrucci ón OR: mov wc.style, CS_HREDRAW or CS_VREDRAW 3.- lpfnWndProc definimos la dirección de la etiqueta de los procedimientos: mov wc.lpfnWndProc, offset WinProC 4.- cbClsExtra especificamos el n úmero de bytes extra, para ubicar la siguiente estructura de la ventana, pero nosotros no la utilizamos y movemos el valor cero o NULL: mov wc.cbClsExtra,NULL 5.- cbClsExtra especificamos el n úmero de bytes extra, para ubicar la instancia de la ventana, igualmente que en el anterior no lo necesitamos y movemos el valor cero. mov wc.cbWndExtra,NULL 6.- hInstance especificamos el manejador (handle) de la instancia del modulo: push Hinstance pop wc.hInstance
4
[RVLCN]
7.- hIcon especificamos el manejador del icono, para ello hemos utilizado la funcion LoadIcon: invoke LoadIcon,Hinstance,IDI_APPLICATION mov wc.hIcon,eax 8.- hCursor especificamos el manejador del cursor, para ello hemos utilizado la funcion LoadCursor: invoke LoadCursor ,NULL,IDC_ARROW mov wc.hCursor,eax 9.- hbrBackground especificamos el color del fondo de nuestra ventana: mov wc.hbrBackground, COLOR_BTNFACE + 1 10.- lpszMenuName especificamos el manejador del Men ú. mov wc.lpszMenuName,NULL 11.- lpszClassName definimos la direcci ón de la etiqueta donde se encuentra el nombre (ACSII), de clase de la ventana. mov wc.lpszClassName, offset Classname 12.- hIconSm especificamos el manejador del icono peque ño. Esto nos ha servido para personalizar nuestra ventanita que vamos a crear, ahora falta registrar su clase, para ello necesitamos la funci ón RegisterClassEx: invoke RegisterClassEx,addr wc Al poner wc registramos todo los cambios que hemos hecho en los miembros de la estructura, esto es muy importante por que si no hacemos esto nuestra ventana no saldr á. Ya le hemos puesto las caracter ísticas de nuestra ventana y adem ás su clase esta registrado, ahora falta crear la ventana y lo hacemos con la siguiente función: Librer ía kernel32.lib CreateWindowEx, NULL, addr Classname, addr Appname, \ WS_OVERLAPPEDWINDOW, 150,210,300,200,NULL,NULL,Hinstance,NULL Esta API es la encargada de crear nuestra ventana y devuelve el manejador al registro EAX es recomendable guardarlo en una variable para cuando queremos referirnos a ella lo identifiquemos por medio de dicha variable, esta función no solo sirve para eso, tambi én puede crear controles de ventanas
5
[RVLCN]
llamadas hijas como botones, edit, static, listbox, etc, es por eso que vamos a analizar que rol cumple cada par ámetro de esta funci ón:
HWND CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ); 1.- dwExStyle Especificamos el estilo extra de nuestra ventana extendida, como por ejemplo: WS_EX_TOPMOST .- Crea una ventana por encima de todas. WS_EX_TRANSPARENT .- Crea una ventana transparente. WS_EX_TOOLWINDOW .- crea una ventana en herramienta. Si quieren comprobar pueden poner esos estilos en el primer par ámetro y la función quedar ía de esta manera: Invoke CreateWindowEx, WS_EX_TOPMOST, addr Classname..... Si quieres saber mas estilos vea Win32 Programmer ’s Referenced . 2.- lpClassName definimos la direcci ón de la etiqueta donde se encuentra el nombre (ACSII) de clase de la ventana. 3.- lpWindowName definimos la direcci ón de la etiqueta donde se encuentra el nombre de la ventana si no la tiene se puede usar el NULL. 4.-dwStyle En este par ámetro especificamos la apariencia de la ventana, nosotros hemos puesto WS_OVERLAPPEDWINDOW , por que combina varios estilos de apariencia como: WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_MINIMIZEBOX y WS_MAXIMIZEBOX
WS_THICKFRAME,
Si nosotros queremos una ventana que solo tenga el bot ón maximizar habilitado nuestra funci ón quedar ía así:
6
[RVLCN]
CreateWindowEx, NULL, addr Classname, addr Appname, WS_SYSMENU or WS_MAXIMIZEBOX,...... No olvidar que si queremos combinar estilos usamos la instrucci ón OR. 5.- X especifica la coordenada de la posici ón horizontal de la ventana cliente. 6.- Y especifica la coordenada de la posici ón vertical de la ventana cliente. Para que quede más observemos las imágenes:
Fig.1 Cuando creemos controles de ventana hija como por ejemplo un bot ón el rango de las coordenadas estar á dentro de la ventana padre:
Fig .2
7
[RVLCN]
7.- nWidth especificamos el ancho del control que hemos creado. 8.- nHeight especificamos el alto del control que hemos creado.
Fig.3 9.- hWndParent Identificamos la ventana padre si lo hubiera, cuando creamos controles de ventanas hijas este par ámetro es utilizado, por ejemplo si quieres crear un botón sobre la ventana padre Fig.3, debemos especificar el manejador de nuestra ventana y como recordamos nosotros lo guardamos en la variable hwnd. 10.- hMenu especificamos el manejador del men ú, este par ámetros solo la utilizamos con controles (ventanas hijas), por ejemplo si le quieres meter un menú al bot ón de la fig.3 empleamos este par ámetro, mas no cuando creamos ventanas tipo WNDCLASSEX por que tiene un miembro especifico que hace eso. 11.- hInstance especificamos la instancia del modulo asociado a la ventana. 12.- lpParam este puntero la usamos cuando creamos ventanas MDI, si no la utilizamos colocamos el valor NULL. .while TRUE invoke GetMessage,addr msg,NULL,NULL,NULL .break .if !eax invoke TranslateMessage,addr msg invoke DispatchMessage,addr msg .endw Como lo explique en el video este bluce siempre se esta ejecutando hasta que se cierre la ventana, en esta parte del código hemos visto un nuevo bloque el
8
[RVLCN]
.break este bloque es de interrupci ón al bluce sirve para terminar el bluce si cumple la condici ón su sintaxis es as í: .break condicion ;si cumple la condici ón saldr á del bluce. En nuestro programa la condici ón es .if !EAX que quiere decir compara si EAX es igual a cero, es equivalente si colocamos .if EAX == 0. Otro punto importante del bluce es que siempre esta cogiendo los mensajes del programa, cuando nosotros cerremos la ventana la funci ón GetMessage devolver á a EAX el valor 0 y saldr á del bluce para terminar el programa. Luego esta el procedimiento de la ventana, es ah í donde empleamos los mensajes para ponerle funciones: WinProC proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .if uMsg == WM_DESTROY invoke PostQuitMessage,NULL .else invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .endif xor eax,eax ret ret WinProC endp Todo lo que queramos que nuestro programa haga lo hacemos aqu í, como dije en el video este es el cerebro del programa, el responsable de ponerle diferentes funciones a nuestra ventana, el par ámetro uMsg es quien contiene el valor de los mensajes, la funci ón DefWindowProc recicla todos lo mensajes que no utilizamos. WM_DESTROY.- Este mensaje se env ía cuando la ventana es destruida o cuando se desaparece del escritorio. Haremos unos ejemplos sobre ventanas, pero primero crearemos una nueva planilla a partir de la que hay en el RadAsm y la modificaremos para que se vea mejor:
9
[RVLCN]
Plantilla02.exe
Si nos damos cuenta en la planilla que hemos visto sea creado una funci ón, con el fin de llenar los miembros de la estructura wc: invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT No tiene nada de nuevo, eso ya lo hemos visto en el capitulo III cuando creamos funciones nosotros llen ábamos los par ámetros de las APIS, en este caso esta llenando los miembros de la estructura. Lo que es nuevo en el c ódigo son como se declara las variables locales, este tipo de variables solo puede ser usado desde en inicio del procedimiento hasta el final de el, como muestra la siguiente imagen:
Fig.3 Su sintaxis es de esta manera:
10
[RVLCN]
LOCAL Etiqueta : tipo de Variable/Estructura Otra cosa importante que observamos son estos tipos de variables: HWND UINT WPARAM LPARAM HINSTANCE LPSTR Pues no vayan a creer que son nuevas variables, estas tienen diferente nombre pero son del mismo tipo y son DWORD, si quieres comprobar buscan en el archivo Window.inc y encontrar algo así: HWND EQU DWORD El operador EQU significa equivalente o igualdad, en otras palabras HWND es igual a DWORD. Ya hemos analizado todo el c ódigo para crear nuestra ventana, ahora crearemos un par de ventanas con botones y edit. Adem ás le agregaremos funciones al botones. Para empezar haremos esta ventana:
Fig. 4 Luego esta:
Fig.5
11
[RVLCN]
Solución Fig.4:
prog010.exe En el video encontramos el mensaje WM_CREATE, este mensaje se envía antes de que muestre la ventana y como su nombre indica sirve para crear nuevas ventanas hijas pero tambi én puedes usarlo con otros fines. .ELSEIF uMsg==WM_CREATE invoke CreateWindowEx,NULL,addr Class_boton,addr Texto_boton01,\ WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\ 10,75,100,25,hWnd,NULL,hInstance,NULL mov hwnd_boton01,eax Nosotros ya sabemos para que sirve cada par ámetro de esta funci ón, lo nuevo que encontramos una nueva clase de ventana hija y que tambi én hemos llenado el 9no par ámetro. La clase nueva de la ventana hija es: Class_boton db "button",0 Con esta clase se crea un boton. El 9no par ámetro lo hemos puesto hWnd, por que contiene el handle de la ventana padre y sirve para crear otros controles (ventanas hijas) sobre la ventana principal. Si vamos a crear varios botones solo declaramos una sola vez la clase de ventana, otra cosa importante es que cuando crea el control si vamos hacer algo con el, es necesario guardar su handle, en una variable como en mi caso:
12
[RVLCN]
mov hwnd_boton01,eax He movido el contenido del registro EAX ah hwnd_boton01, para que en el futuro pueda identificar y utilizarlo. Luego encontramos otro tipo de mensaje WM_COMMAND, este otro se envía cuando se toca o cuando pulsamos alg ún ítem o control, y el manejador del objeto tocado o pulsado se encuentra en lParam, también existe wParam y ahí se encuentra el ID mas el c ódigo de notificaci ón eso lo veremos mas adelante cuando entremos a ventanas con dialog. .elseif uMsg== WM_COMMAND mov edx,lParam Entonces movemos el handle que contiene lParam ah EDX por que como se sabe no se puede comparar variables con variables. .if edx == hwnd_boton01 .elseif edx== hwnd_boton02 .endif En estas comprobaciones comparamos todos los manejadores de nuestros botones, para que cuando se presiona solo uno ser á igual, luego ah esos botones le ponemos diferentes funciones. if edx == hwnd_boton01 invoke MessageBox,hWnd,........ . elseif edx== hwnd_boton02 invoke DestroyWindow,hWnd .endif Aquí le dimos a cada bot ón una función, en este caso el botón 01 mostrara un mensaje y el bot ón 02 cerrara el programa. Nota: si vas agregar un nuevo mensaje lo haces con .elseif uMsg== MI_MENSAJE.
Librer ía kernel32.lib DestroyWindow,hWnd Con esta función destruimos la ventana padre.
13
[RVLCN]
Seguimos con el programa de la figura 5.
prog011.exe
Hemos encontrado 2 APIs nuevas: Librer ía kernel32.lib GetWindowText, hwnd_edit01,addr buffer ,100 Esta función coje el texto de las ventanas tiene 3 par ámetros y son las siguientes: hWnd.- Identificamos la ventana colocando el manejador del control. lpString.- Dirección de la memoria donde se almacenara el texto. nMaxCount.- Numero máximo de caracteres que se va ha cojer.
Librer ía kernel32.lib SetWindowText, hwnd_edit02,addr buffer Con esta función enviamos el texto a las ventanas, contiene 2 par ámetros. hWnd.- Identificamos la ventana colocando el manejador del control. Lpsz.- Dirección de la memoria donde se encuentra el texto.
14
[RVLCN]
En ambos programas hemos puesto diferente icono a nuestras ventanas, la sección .const sirve para colocar constantes y es solo de lectura, cuando declaramos un objeto que esta en el recurso es importante colocar el mismo ID del recurso que hemos puesto por ejemplo: Sintaxis: Etiqueta equ valor
app equ 100 ;programa fig4 Icono equ 100 ;programa fig5 Nos damos cuenta que la etiqueta no importa lo que en verdad sirve es el valor 100 que es el ID de nuestro icono en el recurso. Utilizando el mensaje WM_CLOSE: Fuente \prog012 Vamos ah crear una ventana, que cuando nosotros le demos clic en muestre este mensaje:
,
Fig.06 Con la condici ón que si presionamos el bot ón Si para cerrar y No para no cerrar la ventana, en la planilla que tenemos debemos agregar este mensaje: WM_CLOSE Este mensaje se envía cuando la ventana esta por terminar pero todav ía muestra la ventana en el escritorio, despu és de este mensaje sigue: WM_DESTROY, Para que muestre el mensaje de la figura Fig.06, llamamos a la funci ón MessageBox de esta manera: invoke MessageBox,hWnd,addr MsgSalir ,addr TitSalir , MB_YESNO+ MB_ICONINFORMATION Luego para comparar que bot ón se ha presionado llamamos al bloque .if y nuestro código quedara as í:
15
[RVLCN]
.elseif uMsg == WM_CLOSE invoke MessageBox,hWnd,addr MsgSalir ,addr TitSalir , MB_YESNO+ MB_ICONINFORMATION .if eax == IDYES invoke DestroyWindow,hWnd .endif Con eso comprobamos el bot ón que se ha presionado.
[ Ejercicios ] 1.- Cree una ventana del tama ño de tu escritorio. 2.- Cree una ventana con 5 botones, cada bot ón debe mostrar diferentes mensajes. 3.- Cree un programa igual ha este:
Nota: al presionar el bot ón Enviar debe enviar el titulo de la ventana, no olvides determinar el handle de nuestra ventana padre a la Funci ón SetwindowText, el icono puede elegirlo usted.
[ Recordatorio ] No olvidar preguntar en lista MASM32-RadASM y enviar sus ejemplos del ejercicio que se ha dejado para subirlas al Site RVLCN, en esta semana se estar á enviando las soluciones de los ejercicios anteriores, se adjunta 3 funciones traducidas al espa ñol gracias ah desacatado por postear en la lista: http://winapi.conclase.net/curso/index.php?tab=Funciones
Dudas, sugerencias, otros, hacerlas en lista.
16
[RVLCN]
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM ( Redh@wk ) http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com www: http://RVLCNsecurity.com www: http://beam.to/RVLCN http://beam.to/REVOLUCION Noviembre-2006
Copyright(c) 2005-2006 RVLCN
1
[RVLCN]
CLASES de ProgramaciOn CON MASM+Radasm Capitulo VI: Cajas De dialog. Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL
ó
2
[RVLCN]
[ Cajas de Dialog ] Esta es otra manera de crear ventanas, utilizando el editor de recursos que viene con el RadASM se puede crear en forma f ácil y r ápida veamos el siguiente video:
Prog13.exe
Como observamos el video el c ódigo para mostrar una ventana simple utilizando las cajas de dialog es m ás sencillo que cuando lo hacemos con puras APIS, veamos el c ódigo en el archivo prog13.inc: Librer ía user32.lib
DialogBoxParam, hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL Esta función es la principal en nuestro programa, por que es la causante de mostrar la ventana que esta en el recurso y además ubicar la direcci ón donde se encuentra los procesos de ella, veamos para que sirva cada uno de los par ámetros:
hInstance.- Especificamos el manejador de la instancia del modulo. lpTemplate.- Especificamos el ID de nuestra caja de dialog, ese ID nosotros la podemos determinar en las propiedades de la caja:
3
[RVLCN]
Fig.1 El ID de nuestra caja es 101 y el nombre es IDD_DIALOG1, con esos datos debemos declarar en nuestro archivo INC en la secci ón const:
Fig.2
hWndParent.- Definimos el handle de donde pertenece la ventana, aqu í ponemos NULL por ser nuestra ventana principal, si en caso fuera la segunda ventana especificaremos el handle de la primera ventana (padre). lpDialogFunc.- Definimos la direcci ón de la etiqueta donde se encuentra los procedimientos: DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM Mov eax,uMsg .if eax==WM_INITDIALOG .elseif eax==WM_COMMAND .elseif eax==WM_CLOSE invoke EndDialog,hWin,0 .else Mov eax,FALSE ; movemos a EAX el valor 0 para reciclar los mensajes que no ; utilizamos si no hacemos esto, no ser á compatible con window Xp y NT ret .endif Mov eax,TRUE ret DlgProc endp
4
[RVLCN]
Como observamos este procedimientos nos resulta familiar a los procesos de la ventanas a puras APiS que hemos creado en el capitulo anterior, por que toda ventana maneja los mismo mensajes con excepci ón de algunos que son solo para Dialog como por ejemplo WM_INITDIALOG, este mensaje se env ía antes de mostrar la caja de dialog en el escritorio, como se diferenciamos que mensajes son solo para cajas de di álogos, pues es simple y lo hacemos por la palabra DIALOG al final del mensaje. dwInitParam.- Definimos con que valor queremos que tenga al inicio el par ámetro lParam, esto no se usara en nuestro programa y colocaremos el valor NULL. Seguimos practicando y esta vez crearemos una ventana con 2 botones y tendr án diferentes funciones, el primer bot ón ser á para mostrar un mensaje y el segundo ser á para salir.
prog14.exe
Nosotros ya sabemos por el capitulo V en que momento se env ía el Mensaje WM_COMMAND si no lo has leído el concepto esta en la pagina 12, cuando trabajamos con cajas de dialog y sus controles ( ítems), siempre lo identificamos con un ID, si nosotros queremos trabajar con un control especifico lo identificamos con ID, la constante que tiene todos los ID de control en el proceso de la ventana es wParam, además de contiene el c ódigo de notificación, para que quede mas claro f í jense en el siguiente cuadro:
5
[RVLCN]
wParam CONTROLES (botones, edit,static, etc.) Menú
lParam
HIGH Contiene el Código de notificación
LOW
Contiene el ID Sin Utilidad
Contiene el manejador de la ventana hija (handle). Sin Utilidad
Ejemplo supongamos que wParam contenga el valor 12345678 entonces: El código de notificación: 1234 El ID del control: 5678 Este es un ejemplo de c ómo extraer el código de notificación: mov eax,wParam mov edx,eax shr edx,16 .IF dx==BN_CLICKED .if ax == boton01 .elseif ax == boton02 .endif .endif SHR (Cambio de puesto a la derecha)
Destino
Contador
Esta instrucción SHR cambia de puestos hacia la derecha, los bits mas significativos desaparecen y las posiciones que se crearon a la izquierda se llenan de 0. Para no enredarnos con esta instrucci ón es igual que dividir por 2 elevado por el Contador ejemplo: mov eax,12345678 shr eax,16 Equivale ah: Contador = 16 12345678h : 2 12345678h : 10000h = 00001234 EAX = 00001234 De esa manera podemos sacar el c ódigo de notificaci ón, si se va a trabajar con ello.
6
[RVLCN]
BN_CLICKED este código de notificaci ón se envía cuando pulsamos cualquier botón, yo no lo utilizo por que este valor de notificaci ón es 0 a la izquierda. Por ejemplo el ID del boton01 es 1001 en decimal (3E9 en hex.), cuando nosotros pulsamos el boton01 el valor de wParam ser á igual a 00003E9h donde: El código de notificaci ón: 0000 igual BN_CLICKED. El ID del control: 03E9. mov eax,wParam ; EAX = 0000 3E9h mov edx,eax ; Movemos el contenido de EAX a EDX = 0000 3E9h shr edx,16 ; EDX = 0000 0000 .IF DX==BN_CLICKED ; Compara si DX es igual a CERO .endif Comparamos si el valor del c ódigo de notificaci ón es igual a 0, es por eso que yo me ahorro todo ese c ódigo y de frente comparo los ID por que se que el código de notificaci ón cuando pulsamos es 0 y esta a la izquierda de nuestro valor total, como dicen cero a la izquierda no sirve. Excepto si en nuestro programa queremos utilizar el c ódigo de notificaci ón y colocarles una funci ón a todos los botones cuando lo pulsamos. A continuación vamos ha trabajar con algunos campos editables:
Prog15.exe
7
[RVLCN] Librer ía user32.lib
GetDlgItemText, hWin,edit01,addr buffer ,225 Esta función trabaja con cajas de dialog, esta funci ón es igual GetWindowText pero la diferencia es que para coger el texto del control necesitamos el manejador de nuestra caja de dialog y el ID del control que queremos coger el texto. Par ámetros: hDlg.- Identificamos el manejador de nuestra caja de dialog. nIDDlgItem.-Identificamos el ID de nuestro Control. lpString.- Dirección de la memoria donde se almacena el texto. nMaxCount.- Número máximo de caracteres que se va a coger. Librer ía user32.lib
SetDlgItemText, hWin,edit01,addr buffer Al igual que la función SetWindowtext coge texto, pero con la diferencia que identificamos el ID del control. Par ámetros: hwndDlg.- Identificamos el manejador de nuestra caja de dialog. idControl.- Identificamos el ID de nuestro Control. lpsz.- Dirección de la memoria donde se encuentra el texto.
[ Agregando Icono ] Ahora agregaremos un icono a nuestra aplicaci ón:
Prog16.exe
8
[RVLCN] Librer ía user32.lib
SendMessage, hWin,edit01,addr buffer Esta función envía mensajes específicos a nuestras ventanas siempre y cuando tengamos el manejador de la ventana. Par ámetros: hwnd.- Identificamos el manejador de la ventana que enviaremos el mensaje. uMsg.- Especificamos el mensaje que se va enviar. wParam.- especificamos informaci ón adicional del mensaje. lParam.- especificamos informaci ón adicional del mensaje. Por ejemplo si queremos enviar un icono a nuestra ventana especificamos el manejador de la ventana, el tipo de mensaje, el tama ño del icono, y el manejador del icono. De esta manera declaramos la funci ón SendMessage para enviar un icono a nuestro programa: SendMessage, hWin.- Manejador de la ventana. WM_SETICON.- Tipo de mensaje. ICON_BIG.- Tamaño del Icono. h_icono.- handle del icono. Si nosotros queremos cerrar nuestra ventana principal uno de tantos m étodos seria enviamos el mensaje WM_CLOSE ejemplo: SendMessage.hWin.- Manejador de la ventana. WM_CLOSE.- Tipo de mensaje. 0.- No especificamos. 0.- No especificamos.
Haremos un ejemplo mas con esta funci ón, para ello creamos un programa igual al de la imagen:
Fig.2
9
[RVLCN]
Estos dos botones cierran la ventana, y su funcionamiento es lo siguiente: el primer botón envía un mensaje a la ventana para que se ejecute la funci ón del botón 2 y a su vez env ía un mensaje para cerrar el programa. Te preguntaras como se hace eso y lo hacemos con el siguiente c ódigo:
.elseif eax==WM_COMMAND mov edx,wParam .if edx == boton01 invoke SendMessage,hWin,WM_COMMAND,boton02,0 .elseif edx == boton02 invoke SendMessage,hWin,WM_CLOSE,0,0 .endif .elseif eax==WM_CLOSE invoke EndDialog,hWin,0 En el boton01 colocamos la funci ón SendMenssage donde se declaro de la siguiente manera: hWin.- Manejador de la ventana. WM_COMMAND.- Este tipo de mensaje es donde se producen las funciones de lo botones. boton02.- Especificamos el valor que debe tener wParam cuando enviamos el mensaje. 0.- No especificamos nada. Este ejemplo es muy sencillo y esta adjunto en este documento.
[ Ejercicios ] 1.- Cree un programa que cuando presione el bot ón “enviar ” muestre un mensaje con el texto que pusimos en el campo edit como muestra la imagen:
10
[RVLCN]
2.- Cree una calculadora que sume 2 cantidades, debe tener 3 campo edit donde: El primer y segundo campo edit.- se ingresara los valores que se va a sumar. El tercer campo edit.- mostrara el resultado. Además debe tener 3 botones con las siguientes funciones: El primer bot ón.- Debe hacer la suma. El segundo bot ón.- Debe borrar todo los campos edit. El tercer botón.- cerrar la ventana. Para desarrollar este programa es necesario usar lo siguiente: 1.- la funciones atodw y dwtoa descritas en el capitulo III. 2.- Debes usar la instrucci ón add (suma). Se pide el resultado en decimales, la idea es algo parecido a esta:
3.- Desarrolle un programa que convierta n úmeros decimales a hexadecimales. Pude usar combinando las funciones del masm atodw , dwtoa y dw2hex o usando una sola funci ón que es la wsprintf.
11
[RVLCN]
[ Recordatorio ] No olvidar preguntar en lista MASM32-RadASM y enviar sus ejemplos del ejercicio en un archivo comprimido mas el nick para poder identificar, en esta semana se estar á enviando las soluciones de los http://winapi.conclase.net/curso/index.php?tab=Funciones
Dudas, sugerencias, otros, hacerlas en lista.
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com http://RVLCNsecurity.com http://beam.to/RVLCN http://beam.to/REVOLUCION Julio-2006
Copyright(c) 2005-2006 RVLCN
1
[RVLCN]
CLASES de ProgramaciOn CON MASM+Radasm Capitulo VI: Manejo de Cadenas . Macros. Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL
ó
2
[RVLCN]
[Cadenas de texto] Llego la hora de trabajar con cadenas de texto nuestra primera tarea ser á concatenar, copiar y comparar, utilizando las APIS de Windows despu és utilizando la funciones de masm32 y por ultimo con instrucciones. 1.- Utilizando las funciones de Windows.- para trabajar con cadenas de texto podemos emplear 4 funciones espec íficas y son las siguientes: Librer ía kernel32.lib
lstrcat, addr Cadena01, addr Cadena02 Esta función se encarga de concatenar (unir) las cadenas y formar una sola, el resultado de la uni ón se almacena en el primer par ámetro ejemplo: .data CadTexto01 db "Yo programo en",0 CadTexto02 db " masm + radasm",0 MsgTitulo db " RVLCN - 2006",0 .code invoke lstrcat,addr CadTexto01 ,addr CadTexto02 invoke MessageBox,NULL,addr CadTexto01,addr MsgTitulo,MB_OK + \ MB_ICONINFORMATION invoke ExitProcess,0 .end El mensaje que muestra nuestro programa es el resultado de la uni ón:
Fig.01 Vea la fuente del programa “prog.18 ”.
3
[RVLCN]
Librer ía kernel32.lib lstrcmp, addr CadTexto01, addr CadTexto02 Esta función compara las cadenas de texto entre sus dos par ámetros, si las cadenas no son iguales el valor devuelto a EAX ser á 1 por ejemplo: .data CadTexto01 db "HOLA",0 CadTexto02 db "hola",0 MsgTexto db "Las 2 cadenas comparadas son diferentes", 0 MsgTitulo db " RVLCN - 2006",0 .code invoke lstrcmp,addr CadTexto01,addr CadTexto02 .if eax==1 invoke MessageBox,NULL,addr MsgTexto,addr MsgTitulo,MB_OK + \ MB_ICONINFORMATION .endif invoke ExitProcess,0 end Como podemos darnos cuenta no diferencia may úscula ni minúscula al momento de comparar, pero hay una funci ón derivada de esta que si omite las mayúsculas y lo que debemos hacer es agregarle una i al final del nombre de la función dando como resultado lstrcmpi si hacemos esto ya no mostrara el mensaje dando como resultado igualdad entre cadenas. Vea la fuente del programa “prog.19”. Librer ía kernel32.lib
lstrcpy, addr buffer , addr CadTexto01 Esta función copia todo la cadena de texto que se encuentra en la direcci ón del segundo par ámetro CadTexto01 hacia el primero buffer . .data CadTexto01 db "BiENVENiDO AL CURSO DE MASM + RADASM", 0 MsgTitulo db " RVLCN - 2006",0 .data? buffer db 100 dup (?)
4
[RVLCN]
.code invoke lstrcpy lstrcpy,,addr addr buffer, buffer,addr addr CadTexto01 CadTexto01 invoke MessageBox MessageBox,NULL, ,NULL,addr addr buffer, buffer,addr addr MsgTitulo, MsgTitulo,MB_OK MB_OK + \ MB_ICONINFORMATION invoke ExitProcess ExitProcess,0 ,0 end El mensaje que muestra nuestro programa es el contenido del buffer que anteriormente le copiamos la cadena de texto.
Fig.2
Si deseamos copiar solo una parte de nuestra cadena de texto por decir solo la palabra “BiENVENiDO ” le agregamos la letra n al final del nombre de la funci ón de esta manera lstrcpyn lstrcpyn,, y se abre un 3 par ámetro que es para colocar la longitud que quieres copiar por ejemplo: invoke lstrcpy lstrcpy,,addr addr buffer, buffer,addr addr CadTexto01, CadTexto01, 9 Solo se copiaran 9 caracteres. Vea la fuente del programa “prog.20”.
Librer í ía kernel32.lib
lstrlen ,addr MsgTexto Esta función devuelve a EAX la longitud de nuestra cadena .data MsgTexto db "BiENVENiDO AL CURSO DE MASM + RADASM",0 RADASM ",0 MsgTitulo db " RVLCN - 2006",0 2006",0 fmo db "la "la longitud de nuestra cadena es %d caracteres ",0 .data? buffer db buffer db 100 dup (?)
5
[RVLCN]
.code invoke lstrlen, lstrlen,addr addr MsgTexto MsgTexto invoke wsprintf ,addr addr buffer, buffer,addr addr fmo, fmo,eax eax invoke MessageBox MessageBox,NULL, ,NULL,addr addr buffer, buffer,addr addr MsgTitulo, MsgTitulo,MB_OK MB_OK + \ MB_ICONINFORMATION invoke ExitProcess ExitProcess,0 ,0 end Utilizamos la funci ón wsprintf wsprintf para para convertir el valor de EAX ha decimales y mostrar el resultado:
Fig.3 Vea la fuente del programa “prog.21”. 2.- Utilizando las funciones de masm32.- Estas funciones de masm32 hacen lo mismo que las funciones de Windows, pero son diferentes al momento de utilizarlas. Vamos a crear un programa que utilice las 4 funciones similares a las anteriores.
Prog22.exe
6
[RVLCN]
En este ejercicio se ha utilizado las siguientes funciones: Librer í í a masm32.lib
szCmp,, addr CadTexto01 szCmp addr CadTexto01,, addr CadTexto02 addr CadTexto02 Esta función la utilizamos para comparar las 2 cadenas de texto que indicamos en sus par ámetros si son diferentes el resultado de EAX ser á igual a CERO por ejemplo: invoke szCmp,addr szCmp,addr CadTexto01, CadTexto01,addr addr CadTexto02 CadTexto02 .if eax .if eax == FALSE invoke MessageBox MessageBox,.... ,.... (Mensaje de desigualdad) desigualdad) .else invoke MessageBox MessageBox,... ,... (Mensaje de igualdad) .endif Comparamos si el valor de EAX es igual a Cero (FALSE (FALSE), ), si fuera as í mostrara el mensaje de desigualdad de lo contrario mostrara el mensaje de igualdad Librer í í a masm32.lib
szLen,, addr CadTexto01 szLen addr CadTexto01 Con esta función obtendremos la longitud de nuestra cadena de texto, despu és de ser invocada EAX ser á quien contenga el n úmero de caracteres de nuestra cadena. Librer í í a masm32.lib
szCopy,, addr CadTexto01 szCopy addr CadTexto01,, addr buffer Esta función es utilizada para copiar nuestra cadena de texto CadTexto01 hacia la direcci ón de la etiqueta del segundo par ámetro buffer , los par ámetros de esta función están invertidos con respecto a la funci ón de Windows lstrcpy Librer í í a masm32.lib
szCatStr , addr buffer addr buffer , addr CadTexto01 addr CadTexto01 Con esta función uniremos (concatenar), la cadena de texto que esta en el segundo par ámetro CadTexto01 hacia el primer buffer primer buffer . Veamos otro ejercicio para que quede mas claro sobre estas funciones:
7
[RVLCN]
Prog23.exe La mayor parte del c ódigo ya sabemos lo que es nuevo es lo siguiente: invoke GetWindowText,hwndEdit1,addr CadTexto01,50 push eax invoke GetWindowText,hwndEdit2,addr CadTexto02,50 pop ebx La función GetWindowText como explique en el capitulo V coje el texto y además devuelve la longitud de la cadena a EAX. Te preguntaras que diferencia hay en usar las funciones de Windows con las funciones de masm32, solo hay una diferencia y es que cuando usamos las funciones de masm32 se agrega c ódigo a nuestro programa y esto puede variar en cuanto al tamaño del ejecutable. 3.- Utilizando las instrucciones.- Esta parte de las clases es un poco complicado por que vamos a trabajar de byte en byte, pero are lo mas simple y entendible posible. Nosotros conocemos los c ódigos ACSII ( American Standard Code For Information Interchange) en castellano Americano Estandarizado para el Intercambio de Información, si no sabes mucho sobre esto no importa, solo tienes que saber lo siguiente: cada letra, numero, s ímbolo es representado por un c ódigo ACSII para su identificaci ón, estos códigos están representados por valores numéricos.
8
[RVLCN]
Nuestro IDE RADASM contiene una tabla ACSII con algunos s ímbolos, letras y números. Para usar esta herramienta debemos ir al men ú herramientas/acsii table, si damos clic en la letra A aparece abajo su valor ACSII en hexadecimal:
Para borrar el car ácter seleccionado presionamos clic derecho. Eso es todo lo básico que debemos saber en cuanto a los c ódigos acsii. Ahora, tenemos el texto “MASM32 + RADASM” Caracteres Código ACSII en hexadecimal Posición
M 4D
A 41
S 53
M 4D
0
1
2
3
20
+ 2B
4
5
20
R 52
A 41
D 44
A S M 41 53 4D
6
7
8
9
10 11 12
En el cuadro se puede observar los valores ACSII de cada letra nuestro texto incluyendo el espacio y adem ás las posiciones de cada letra que empieza desde CERO, si nosotros queremos coger la primera letra de esa palabra debemos definir la posici ón cero. Bueno vasta de un poco de teor ía por que yo creo más en la pr áctica que en la teor ía y es hora de los ejercicios:
9
[RVLCN]
3.1 Copiar un texto hacia una variable.- vamos a copiar un texto que esta en una variable hacia otra. Para copiar del texto de un lugar a otro lo haremos de 2 maneras. a.- Crearemos un bluce donde mueva car ácter por car ácter hacia la variable buffer y colocaremos un contador que ser á comparado con la longitud m áxima de la cadena: .data CadTexto01 db "CLASES DE MASM + RADASM",0 MsgTitulo db " RVLCN - 2007",0 .data? buffer db sizeof CadTexto01 dup (?) .code invoke lstrlen,addr CadTexto01 mov ebx,eax xor ecx,ecx .repeat mov al, byte ptr [CadTexto01+ecx] mov byte ptr [buffer+ecx],al inc ecx .until ecx ==ebx Como observamos en el código, primero obtenemos la longitud de la cadena y lo guardamos en un registro en mi caso EBX, también podemos guardarlo en una variable, luego limpiamos el contenido del registro ECX igual a CERO por que lo utilizaremos como contador y as í coger desde el primer car ácter de nuestra cadena. mov al, byte ptr [CadTexto01+ecx] Lo que hace es mover un byte de la variable CadTexto01 hacia AL, pero si queremos especificar que car ácter queremos mover, debemos sumarle la posici ón donde esta dicho car ácter, como vamos a copiar todo el texto debemos empezar desde la posici ón cero y ir sumando 1 o incrementado 1 a nuestro contador en mi caso es el registro ECX hasta que llegue a la longitud máxima del texto y as í va cogiendo nuevos caracteres seg ún la posición. mov byte ptr [buffer+ecx],al Aqui movemos el contenido de Al que debe ser un car ácter de nuestro texto hacia el buffer , también debemos colocar la posici ón donde se mover á el car ácter nuevo es por eso que agregamos ECX para que vaya posicionando cada car ácter en su respectivo lugar. Vea la fuente del programa “prog.24” y “prog.24b ”.
10
[RVLCN]
b.- la diferencia de este m étodo es que no utilizamos la longitud m áxima para terminar de copiar toda la cadena, emplearemos el m étodo de comprobación de caracteres. Como sabes cada cadena de texto que declaramos en una variable termina en el valor 0, esto es lo que debemos comparar para que termine de copiar todo el texto. xor ecx,ecx xor eax,eax .repeat mov al,byte ptr [CadTexto01+ecx] mov byte ptr [buffer+ecx],al inc ecx .until byte ptr [CadTexto01+ecx] == 0 Podemos observar lo siguiente: byte ptr [CadTexto01+ecx] == 0 Aqui comparamos si el car ácter es igual a 0 que significar ía el final de la cadena de texto, si es igual terminar ía de copiar todo el texto. Vea la fuente del programa “prog.25” y “prog.25b ”. 3.2 Mostrar la longitud de nuestra cadena.- Para saber la longitud de la cadena debemos colocar un contador que vaya increment ándose hasta que llegue al ultimo car ácter. .data CadTexto01 db "ESTAMOS EN EL CAPITULO VII",0 MsgTitulo db " RVLCN - 2007",0 MsgTexto db "La longitud de la cadena es %d",0 .data? buffer db 50 dup (?) .code xor ecx,ecx .while byte ptr [CadTexto01 + ecx] != 0 inc ecx .endw invoke wsprintf ,addr buffer,addr MsgTexto, ecx En este bluce va ir incrementado ECX siempre y cuando el car ácter de nuestro texto sea diferente de cero. Vea la fuente del programa “prog.26” y “prog.26b ”.
11
[RVLCN]
3.3 Sumar todos los Caracteres de nuestro texto.- Aqui vamos a crear un programa que sume todo nuestro c ódigo acsii de un texto y mostrar el resultado.
Prog27.exe En este programa lo único de nuevo es lo siguiente: .repeat mov al, byte ptr [CadTexto01+ ecx] add ebx,eax inc ecx .until byte ptr [CadTexto01+ ecx] == 0 Hemos agregado la instrucci ón add para sumar cada valor acsii de nuestro texto que esta en el registro eax y luego es almacenado en el registro ebx. 3.4 Comprobar caracteres de un texto.- Para ello debemos ubicar las posiciones de cada car ácter y luego compararlas, vamos a ver 2 tipos de comprobaci ón la total y la parcial. a.- comprobaci ón total.- Aquí comprobaremos todo los caracteres de una cadena de texto: .data CadTexto01 db "MASM + RADASM",0 CadTexto02 db "MASM + RADASM",0 MsgTexto db "Los caracteres son iguales",0 MsgTitulo db " RVLCN - 2007",0
12
[RVLCN]
.code xor ecx,ecx .repeat mov al,byte ptr [CadTexto01 + ecx] .break .if byte ptr [CadTexto02 + ecx]!=al inc ecx .until ecx == 14 .if ecx == 14 invoke MessageBox,NULL... .endif Encontramos el bloque .break que sirve para provocar una interrupci ón en el bluce si cumple su condici ón. Su sintaxis es de esta manera: .break .if condicion No olvidemos que para utilizar el .break debe estar dentro del bluce. .break .if byte ptr [CadTexto02 + ecx]!=al Recordemos que AL contiene el valor acsii de uno de los caracteres de nuestro texto, y la comprobaremos con uno de los valores acsii de la otra cadena, si es diferente se saldr á del bluce y el contenido de ECX ser á la posición del car ácter que no coincide. .if ecx == 14 invoke MessageBox,NULL... .endif Si nuestro contador ECX contiene el valor máximo de la cadena de texto que es 14 significa que todos los caracteres son iguales. Vea la fuente del programa “prog.28” y “prog.28b ”. b.- comprobaci ón parcial.- En este tipo de comprobaci ón comparamos algunos caracteres de nuestra cadena por ejemplo: .data CadTexto01 db "MASM + RADASM",0 MsgTexto db "Comprobado el 5to caracter es +",0 MsgTitulo db " RVLCN - 2007",0
13
[RVLCN]
.data .if byte ptr [CadTexto01+ 5 ]== '+' invoke MessageBox...... .endif Como observamos en el código, primero escribimos donde se encuentra la cadena de texto y sumamos su posici ón en mi caso es el car ácter +. Vea la fuente del programa “prog.29” y “prog.29b ”.
[ MACROS ] Las macros es un conjunto de funciones o instrucciones que pueden simplificar nuestro código y evitar que el programador vuelva a tener que repetir cierto código del programa. Si vamos a la carpeta donde tenemos el masm32 instalado observamos una carpeta llamada macro con un archivo macro.asm, al abrirlo podemos observar varios tipos de macro con diferentes funciones. Nuestra primera macro que vamos ah utiliza ser á la que simplificar la funci ón MessageBox, nosotros para utilizar esta funci ón necesitamos declarar las variables y luego colocar esas variables en sus par ámetros de esta funcion. Podemos simplificar todo eso con una macro y colocar el texto y el titulo de la función MessageBox directamente en sus par ámetros por ejemplo: fn MessageBox,NULL,"BiENVENiDO AL CURSO DE MASM + RADASM", \ " RVLCN - 2007",MB_OK + MB_ICONINFORMATION Claramente podemos observar que ya no hemos utilizado el invoke sino la macro fn que dentro de ella esta el invoke, pero para que podamos utilizar las macros debemos declarar en nuestro c ódigo o si ya esta declarados en un archivo como en nuestro caso debemos incluirla: include \MASM32\macros\macros.asm Vea el programa prog30.rap. A medida que vamos avanzando en el curso vamos aprendiendo mas sobre las macros.
14
[RVLCN]
[ Ejercicio ] 1.- Crea un programa con 3 cajas editables: La primera caja edit es para escribir el nombre del usuario La segunda caja edit es para escribir el apellido del usuario La tercera caja debe mostrar la suma del código acsii del nombre de usuario seguido de un guión “-“mas la suma del c ódigo acsii del apellido del usuario.
2.- Cree un programa que genere un c ódigo a partir del nombre del usuario y luego comparar ese c ódigo con el ingresado: Para genera un código a partir del nombre podemos sumar todo los valores acsii del nombre y luego el resultado multiplicar, sumar, dividir por otro valor. Si el código ingresado esta correcto debe mostrar un mensaje afirmativo y si es incorrecto debe mostrar un mensaje de negaci ón.
3.- Cree un programa que encripte nuestra cadena de texto ingresada y la muestre en otra caja edit. Para pode encriptar la cadena de texto debemos encriptar cada car ácter del texto, podemos utilizar la instrucci ón xor por ejemplo:
15
[RVLCN]
Mov al, byte ptr [CadTexto + ECX] xor eax,55 El valor de eax movemos a un buffer para guardarlo:
Nota: lo que se muestra en las im ágenes de los ejercicios es solo un ejemplo no significa que los resultados sean iguales.
[ Recordatorio ] No olvidar preguntar en lista MASM32-RadASM no olvide de enviar sus ejemplos a los correos:
[email protected] [email protected] Lista sobre funciones en espa ñol: http://winapi.conclase.net/curso/index.php?tab=Funciones
Dudas, sugerencias, otros, hacerlas en lista.
[ El autor puede ser contactado ] eMail:
[email protected] [email protected]
Lista MASM32-RadASM http://groups.google.es/group/MASM32-RadASM www: http://RVLCN.com http://RVLCNsecurity.com http://beam.to/RVLCN http://beam.to/REVOLUCION
16
[RVLCN]
Febrero-2007
Copyright(c) 2005-2006 RVLCN
1
[RVLCN]
CLASES de ProgramaciOn CON MASM+Radasm Capitulo VIII: Librerias de enlace Dinamico. & Array
Escrito por: ^A|An M0r3N0^ Consejero: RedH@wk DESCARGO LEGAL
ó
2
[ Librer ía s de enlace dinámico
[RVLCN] “DLL”]
En nuestro sistema operativo y otros programas que tenemos instalado en windows hemos visto librer ías de enlace din ámico su extensión es .dll Windows tiene su propia colecci ón como por ejemplo user32.dll, kernel32.dll, gdi32.dll y como esas hay un mont ón, cada una de ellas tiene funciones que utiliza windows y nosotros durante las clases de masm32 la hemos utilizado también. Lo primero que vamos hacer es crear nuestra propia librer ía y luego mostrare 2 métodos para utilizar las funciones de nuestra DLL. 1.- Estructura de una DLL.-
.386 .model flat,stdcall option casemap:none
include windows.inc include user32.inc include kernel32.inc includelib user32.lib includelib kernel32.lib .data .code Punto_de_Inicio proc hInstance: DWORD, reason:DWORD, rsrvd1:DWORD mov eax,TRUE ret Punto_de_Inicio Endp // Aquí se programara las funciones.
End Punto_de_Inicio
La estructura de la DLL es similar a un ejecutable, pero hay una diferencia, se trata de que toda librer ía necesite un punto de inicio o de entrada como lo dicen algunos, Es necesario darle un valor EAX como por ejemplo si es TRUE queremos decir que la DLL se ha cargado correctamente y si pusi éramos FALSE a EAX estaremos diciendo que se cargo incorrectamente. Otra cosa que observamos es que par ámetros:
la funci ón
Punto_de_Inicio tiene 3
3
[RVLCN]
hInstance.- Aquí encontramos el manejador de nuestra DLL (handle). reason.- Este par ámetro puede tomar 4 valores seg ún la direcci ón del proceso: DLL_PROCESS_ATTACH.- Se recibe este valor cuando se carga la librer ía en el
proceso. DLL_PROCESS_DETACH.- Se recibe este valor cuando se descarga la librer ía
en el proceso. DLL_THREAD_ATTACH.- Se recibe este valor cuando se crea un hilo de
proceso. DLL_THREAD_DETACH.- Se recibe este valor cuando se ha destruido el hilo del
proceso. rsrvd1.- Par ámetro utilizado por windows, normalmente no se utiliza. Toda DLL necesita un archivo de modulo para definir el nombre de la librer ía y las funciones que se exportara a otros programas. EL Archivo tiene como extensi ón .def donde su contenido es por ejemplo lo siguiente: LIBRARY EXPORTS
Nombre_de_la_libreria Funcion_01 Funcion_02 Funcion_03
Eso es todo lo que debemos saber antes de programar nuestra primera DLL en masm32. Antes de seguir necesito que agregues la plantilla Libreria.tpl a nuestro IDE RadASM, solo debes copiar el archivo en donde tienes el RadASM, en su carpeta Masm\Templates por ejemplo: C: \RadASM\Masm\Templates Una vez hecho eso vea el siguiente video:
4
[RVLCN]
MI_DLL_01.exe Cuando se programa una DLL se hace de igual manera que un ejecutable se puede usar variables, funciones etc. la única diferencia es en el proceso de ensamblado cuando se crea la DLL es necesario enlazar tambi én el archivo .def , además al compilar se ha creado un archivo importante para llamar a las funciones de una DLL, este archivo es necesario para emplear el primer método del uso de una funci ón que tenga una DLL, por eso es importante copiar el archivo que tiene la extensi ón .LIB “MI_DLL_01.lib”, a la carpeta donde vamos a crear el programa ejecutable. El siguiente paso es crear un programa para llamar a nuestras funciones que esta en la DLL y les ense ñare dos métodos. 1º Metodo “Utilizando el archivo .LIB”.- Este método se basa en llamar a la función con el operador invoke para ello debemos agregar el archivo .lib y declarar las funciones exportadas que vamos a utilizar. He creado un video para que vean de qu é se trata este método:
5
[RVLCN]
prog31.exe Es sencillo utilizar funciones de una DLL cuando se tiene el archivo .LIB, en el capitulo II explique para que serv ían ese tipo de archivos en un programa, pero si te haz olvidado, pues sirven para enlazar nuestra DLL con el ejecutable y además contiene informaci ón sobre el nombre y la direcci ón donde se encuentra las funciones. Ahora, que pasar ía si no tienes el archivo .lib de una DLL, en este caso lo primordial es tener el nombre de la funci ón y lo puedes saber utilizando alg ún desamblador de programas como W32dasm o el de tu preferencia. Mas adelante te ense ñare a crear un archivo .lib de una DLL si en caso no lo tuvieras, pero eso no lo vamos ha ver en este capitulo. 2º Metodo “Utilizando las Funciones LoadLibrary, GetProcAddress y Freelibrary”.Con este método es un poco lioso pero tal vez alg ún día te pueda servir, lo primero que debemos hace es cargar la librer ía con la función LoadLibrary y luego necesitamos la direcci ón de la funci ón para poder llamarla, para ello utilizamos la funci ón GetPorcAdress. He preparo un video sobre este m étodo espero que se pueda entender:
6
[RVLCN]
prog32.exe Librer ía Kernel32.lib
LoadLibrary,addr Nombre_DLL Con esta función cargamos la DLL, debemos especificar el nombre de la DLL en su primer par ámetro, si la librer ía fue cargada correctamente devolver á a EAX el manejador (Handle), luego lo almacenane en la variable handle_DLL, si no tu éxito en cargar la DLL la función devolver á 0 a EAX. mov handle_DLL,eax .if EAX== NULL invoke MessageBox,… .else invoke GetProcAddress,… .endif En esta parte del c ódigo comprobamos si EAX es igual a 0, si lo fuera as í mostrara un mensaje para informar sobre este error, de lo contrario llamaremos a la función GetProcAddress.
7
[RVLCN]
Librer ía kernel32.lib
GetProcAddress,addr handle_DLL ,addr Nombre_DLL Con esta API podemos saber la direcci ón en la memoria donde se encuentra dicha función para luego ser llamada con la instrucci ón CALL. En esta función es importante indicar el manejador de la DLL y el nombre de la función. Si existe la función en la DLL devolver á la dirección a EAX para ser almacenado en la variable Direccion_Funcion , de lo contrario devolver á 0. mov Direccion_Funcion, eax .if eax == NULL invoke MessageBox,… .else Call Direccion_Funcion .endif Debemos comparar EAX si es igual a 0 para saber si la funci ón realmente existe en dicha DLL si no existiera mostrara un mensaje de advertencia, de lo contrario llamara a la función: Call Direccion_Funcion Librer ía Kernel32.lib
FreeLibrary,addr handle_DLL Con esta función descargamos la librer ía de la memoria, eso lo hacemos cuando ya no la necesitemos o cuando terminamos el programa. En su par ámetro es importante indicarle el manejador de la DLL que vas a descargar. En el siguiente ejemplo que presentare a continuaci ón declararemos una función que tenga uno o mas par ámetros, esto ya lo hemos hecho en el capitulo III - pagina 11 sobre como crear tus propias funciones, se hace igual forma que con una DLL.
8
[RVLCN]
prog33AyB.exe
En el primer método que acabamos de ver en video no hay problema por que ya lo hemos explicado anteriormente. Con el segundo m étodo, siempre que queremos definir algún par ámetro de la función necesitamos usar la instrucci ón PUSH en forma ordena. Por ejemplo si nuestra función fuera de esta manera: Funcion01 PROC P1:DWORD, P2:DOWRD, P3:DWORD Si queremos definir sus par ámetros al momento de usar esa funci ón, el orden para hacerlo seria as í: PUSH P3 PUSH P2 PUSH P1 CALL Funcion01 Nótese que el primer PUSH es el último de la funci ón declara arriba, ese seria el orden correcto de hacerlo.
9
[RVLCN]
[ Array ] Si alguna vez has escuchado array en programaci ón sabr ás de que se trata este tema, pero para los que no saben es un grupo de variables del mismo tipo con una etiqueta en com ún. Cada array est á en diferentes posiciones de la memoria contiguas, así que la dirección más baja corresponde al primer elemento.
prog34AyB.exe
1.- En el ejemplo prog34A hemos visto como hacemos para utilizar un sola variable para cambiar el texto del mensaje cada vez que presionamos el bot ón del programa. Es importante saber que la posici ón mas baja es cero, y es el primer mensaje que pusimos, no olvidemos que debemos multiplicar por 4: Posición Variables
0 MsgTexto01
1 MsgTexto02
2 MsgTexto03
3 MsgTexto04
invoke MessageBox,NULL, Todo_MsgTexto[ebx * 4] El registro EBX es quien tiene las posiciones de los textos, es importante saber que ya no fue necesario agregar el operador addr .
10
[RVLCN]
2.- En el ejemplo prog34B, se ha elaborado un programa que al presionar cualquier bot ón nos lleva a la misma funci ón, comprobando cada uno de los botones desde una variable en com ún. Aquí también se determino en que posiciones estaban las ID de los botones de esta manera: .if (edx==Botones[0 * 4]) || (edx==Botones[1 * 4]) || (edx ==Botones[2 * 4]) || \ (edx==Botones[3 * 4]) || (edx==Botones[4 * 4]) Las posiciones de los botones est án marcadas con azul.
[ Ejercicios ] 1.- Tienes el archivo .inc y .lib de la librer ía de valores aleatorios: rvlcnrand.Inc rvlcnrand.lib Con 5 funciones randzime PROTO random PROTO uniform PROTO range PROTO :DWORD,:DWORD urange PROTO :DWORD,:DWORD Cree una DLL, para que se pueda exportar esas 5 funciones a cualquier programa de Windows. 2.- Utilice una variable tipo array con mas de 7 cadenas de texto, al presionar un botón, el titulo de mi ventana debe ser cualquiera de las 7 cadenas de texto. Para cambiar el titulo de una ventana puede utilizar las siguientes funciones. SetWindowText para ventanas hechas con APis. SetDlgItemText para ventanas hechas con cajas de dialog.