Título: Introduccion a APIs y como evitar el uso de MSWINSCK.OCX con APIs Publicado por: Achernar en 5 Julio 2007, 23:17 pm Bueno no espero que esto sea una enciclopedia api, pero espero que esto pueda ser el
primer paso para empezar a usar apis en VB de muchos y dejar de lado el tedioso trabajo de llevar archivos .OCX a cada lugar donde llevamos nuestra aplicación. Además en mi caso el haber usado mucho las apis desde VB6 me facilito muchísimo pasar a MASM32 desde el tasm para ms-dos.... bla bla bla ya parezco una vieja... como dijeron The Ramones jei jou! letsgou! ;) *********************************************************************************************** PRIMER EJEMPLO: Un ejemplo sencillo *********************************************************************************************** ACLARACION!!!: todo los ejemplos están hechos en VB6 1) creamos un nuevo proyecto con un formulario Form1 y copiamos el siguiente código Código: '<el codigo empieza justo despues de esta etiqueta> 2) listo... le damos F5 para ejecutarlo y voila... un msgbox con un texto hermoooossssso ¿no? a mi me parece muy lindo y esta hecho con una sencilla api... que no te gusta, hey no me presiones que estoy ebrio y puedo llegar a decir cosas como que detrás de la simpleza de una margarita se haya todo el poder de la naturaleza, pero no te lo voy a decir :P Bueno dejo mi vaso y vamos a analizar un poco esto Primero tenemos lo de "Private Declare Function MessageBox..." acá estamos avisando que función vamos a usar y en que librería esta (user32 --> user32.dll dentro de System32), si usamos Alias quiere decir que dentro de la dll la función se llama MessageBoxA, pero nosotros la vamos a llamar MessageBox para que VB sepa que estamos diciendo cuando llamemos a una función MessageBox. Este alias por ejemplo se usa en la función Winsock select para verificar el estado de un socket si esta en alguna combinacion de lectura/escritura/error. Como No se puede usar una función select en vb (porque es una palabra reservada "Select Case") se la puede llamar vbSelect Volviendo a MessageBox vemos que a la derecha esta los parametros hwnd, lpText, lpCaption y WType hwnd: este es el MANEJADOR (o handle) de la ventana padre (la que crea la ventanita msgbox hija). en este ejemplo la ventana padre seria el form1. En windows las ventanas son creadas en algún momento (no existe una ventana dios que existe y existirá por siempre... a menos que Bill nos haya ocultado algo), bueno y cuando se crea una ventana, esta tiene un numero que la identifica como cuando creamos un archivo algo así: Open "archivo.txt" for Random as #1 Len = Len(Registro) Put #1,,Registro close #1 puede verse que para grabar un registro en el archivo o cerrarlo no usa "archivo.txt" para referirse al archivo, sino el numero #1 que es el MANEJADOR del archivo Volviendo al ejemplo del msgbox... este argumento hwnd puede ser nulo indicando que el msgbox no tiene ventana padre (no genera ningún problema). lpText: este argumento es el mensaje propiamente dicho, en vb se pasa una cadena, pero vale aclarar este detalle: si ven el nombre de la variable comienza con lp eso se usa en otros lenguajes (como masm32) para destacar que dicha variable es un puntero y en dichos lenguajes no se pasa una cadena, sino la dirección de memoria donde esta guardada la cadena, en este caso, en VB ,se facilita bastante, pero muchas veces hay problemas con las apis porque VB no permite manipular tan bien la memoria como C++ o MASM32 entonces hay que recurrir a ciertos artilugios. lpCaption: similar al anterior fíjense que también empieza con lp, es un puntero, pero nosotros solo pasamos una cadena y listo... casi me olvido, este es el titulo de la ventana wType: esto indica el tipo de ventana msgbox... o sea.. con solo un botón OK o Yes/NO o Yes/No/Cancel etc el valor cero = solo OK, podemos experimentar agregando las siguientes constantes a nuestro proyecto anterior y sustituyéndolas por el ultimo termino Private Const MB_OK = 0 Private Const MB_OKCANCEL = 1 Private Const MB_ABORTRETRYIGNORE = 2 Private Const MB_YESNOCANCEL = 3 Private Const MB_YESNO = 4 Private Const MB_RETRYCANCEL = 5 luego la llamada a la función podría quedar algo así MessageBox Me.hwnd, "Este Es El Primer Ejemplo", "Ejemplo API", MB_ABORTRETRYIGNORE Título: Re: Introduccion a APIs y como evitar el uso de MSWINSCK.OCX con APIs Publicado por: Achernar en 5 Julio 2007, 23:20 pm Bueno como al primer ejemplo de api lo llevamos fácil como nene para la escuela, antes de
que se enfríen las articulaciones vamos a meter un ejemplo un poco mas elaborado pero facilito *********************************************************************************************** SEGUNDO EJEMPLO: Un ejemplo mas elaborado ;) *********************************************************************************************** lo que vamos a hacer acá es un programa para cambiarle el titulo a otra ventana cualquiera si... podes hacer eso... a cualquier programa le podes hacer lo que quieras... como dijo el DR. Octopus en SpiderMan II "The power of the sun in the palm of my hand" 1) lo de siempre creamos un proyecto con un formulario Form1, un botón Command1 y un timer Timer1 y le copiamos el siguiente código Código: '<el codigo empieza justo despues de esta etiqueta> 2) le damos F5 para ejecutar... si hacemos click en el botón se abre el block de notas y cada segundo va a sonar un beep, luego de 5 segundos (5 beeps) el titulo de la ventana del block de notas se va a modificar por otro texto. esto me hace acordar un programa que hice y fue como me di cuenta que la fuerza bruta no no ayuda de mucho... era un programa de fuerza bruta para un programa que se llama UniversalShield y sirve para guardar archivos y carpetas bajo un password. Cuando el UniversalShield pide el pass no hace como otros que luego de unos errores cierra la ventana, lo cual demoraría la fuerza bruta así que no era muy difícil de programar. Otra cosa era que el botón ok del UniversalShield para aceptar el pass estaba deshabilitada y se habilitaba cuando se escribía el pass correcto. Mi programa tenia 256 o 255 checkboxs con distintos símbolos ascii, de ahí elegía los que me parecía que podría contener el pass, por ejemplo solo los 10 numero, ingresaba el caption de la ventana que me pedía el pass. El programa buscaba una ventana (acá ya se mostró como buscar la foreground window) con el caption ingresado. En esa ventana buscaba el textbox y le mandaba pulsaciones de teclas sintetizadas (también se puede simular con apis) cada vez que el programa tecleaba un posible pass verificaba si el botón estaba enabled o disabled (también se puede hacer con apis) y si el botón estaba enabled (habilitado) era que había encontrado el password Era un programa muy pobre pero era bueno para practicar el uso de apis y en esa época estaba viendo los mensajes entre ventanas y era el modo en que sintetizaba las pulsaciones sobre el textbox. Título: Re: Introduccion a APIs y como evitar el uso de MSWINSCK.OCX con APIs Publicado por: Achernar en 5 Julio 2007, 23:28 pm Al igual que se usan estas funciones, windows tiene infinidad (bueno, no lo tomes literal...
muchas, muchisimas) funciones para hacer una cantidad impresionante de cosas. Todo lo que hacen los archivos OCX es llamando a apis asi que es posible sustituir estos archivos por código hecho por nosotros con llamadas a apis. Lo que voy a explicar es como usar apis para evitar el uso del Microsoft winsock Control 6.0 (MSWINSCK.OCX) con no mas de 11 apis WOW!!!! XDD *********************************************************************************************** UN POCO DE TEORIA EMINENTEMENTE PRACTICA ¿? ;) (la música de fondo es "Children of the Grave" de Black Sabbath) *********************************************************************************************** Acá es donde la cosa se complica... porque yo estudio Ingeniería Mecánica XDDDD Mejor no me voy a poner a explicar que es un socket porque sino la cago :P supongo que si alguien venia usando el control winsock de VB debe conocer algo de esto... personalmente conocí winsock vía api y nunca use dicho control :/ .Todas estas funciones explicadas de acá en adelante están en wsock32.dll que esta dentro de la carpeta System32 Creo que lo voy a explicar mejor con un diagrama así funciona un cliente: 1) iniciamos una sesión Winsock (avisamos que vamos a usar winsock) Esto se hace con la funcion WSAStartp 2) creamos un socket (digamos una terminal de entrada y salida de datos) Esto se hace con la funcion soket 3) conectamos el socket a una dirección remota en un cierto puerto Esto se hace con la función Connect, pero son necesarias un par de funciones mas para condimentar un poco el asunto 4) si la conexión se realizo ya se pueden enviar mensajes, pero también hay que verificar si hay mensajes entrantes para leer Leer se hace con la función recv Escribir se hace con la función send 5) para terminar se puede cerrar el socket y terminar la sesión winsock o directamente terminar la sesion winsock y esta elimina todos los sockets creados por el proceso que llame a esta función Un socket se cierra con la función closesocket Una sesión se termina con WSACleanup Un servidor es levemente distinto, el paso 3 no es conectarse, sino poner el socket en modo escucha para esto se usa la función bind para enlazar el socket con la IP local y el puerto donde se quiere dar el servicio y luego la función listen para poner el socket a la espera de una conexión A explicar un poco como funcionan estas funciones ("FUNCINAN ESTAS FUNCIONES" que recursivo!!!XDDD ah a propósito de esto leí que la RAE no acepta este termino tan utilizado en informática, por ejemplo GNU es un acrónimo recursivo o sea una especie de sigla que hace referencia a si misma --> GNU = GNU is Not Unix, la RAE propone otra palabra para sustituir por recursivo que ahora no recuerdo) * WSAStartup: (avisa que este proceso inicia una sesión winsock) Declare Function WSAStartup Lib "WSOCK32" (ByVal wVersionRequired As Long, _ lpWSADATA As WSAData) As Long wVersionRequired es la versión mas alta que soporta quien llama a esta función y esta se pasa teniendo en cuenta lo siguiente supongamos la versión ficticia v5.7, 5 es la versión y 7 la revisión, bueno como las variables que empezaban con lp eran punteros ahora puede verse que wVersionRequired empieza con w es un word, o sea, un par de bytes de los cuales el de mayor orden va a representar la revisión y el de menor orden la versión casi nunca vas a tener error si usas la versión de de Windows Sockets 2.2 o sea pasarle el valor &H202 como primer argumento a esta función lpWSADATA Seria un puntero a una estructura tipo WSAData, pero como en VB es mas fácil directamente pasamos el nombre de la estructura este tipo se declara de este modo Type WSAData wVersion As Integer wHighVersion As Integer szDescription As String * 257 szSystemStatus As String * 129 iMaxSockets As Integer iMaxUdpDg As Integer lpVendorInfo As Long End Type Generalmente todo esto no nos va a importar mucho.. digo, si estas por crear un cliente de IRC solo queres iniciar winsock y nada más Si la llamada a esta función es satisfactoria, el valor de retorno será CERO * WSACleanup: (avisa que este proceso termina una sesión winsock) Declare Function WSACleanup Lib "WSOCK32" () As Long no tiene argumentos * socket: (crea un socket) Declare Function socket Lib "wsock32.dll" (ByVal af As Long, _ ByVal s_type As Long, _ ByVal protocol As Long) As Long af es AddressFamily (la familia de direccion) s_type es el tipo de socket protocol es el protocolo que operara con el socket valores comunes (troyanos, bots, clientes para keyloggers remotos, no se.. cosas comunes) son af = AF_INET = 2 s_type = SOCK_STREAM = 1 protocol = IPROTO_TCP = 6 Si la llamada a la función es satisfactoria retorna un valor mayor a cero que es el manejador del socket (ese valor para operar sobre el socket como con los archivos y las ventanas) y si hay algún error y no se puede crear retorna -1 * closesocket: (cierra un socket) Declare Function closesocket Lib "wsock32.dll" (ByVal s As Long) As Long s es el manejador del socket que se quiere cerrar ahora viene una explicación peque peque para la conexión esta es la declaración de la función connect, la que establece la conexión, así esta en la Api Guide (después voy a dar la dirección para que busque quien quiera la api que quiera... también toda la info sobre esto esta en el msdn de microsoft pasen por ahí que siempre atienden bien con café, torta, constantes, estructuras, funciones y códigos fuente ;) Declare Function Connect Lib "wsock32.dll" Alias "connect" (ByVal s As Long, addr As sockaddr, _ ByVal namelen As Long) As Long que tenemos... s = manejador del socket (ya usamos manejadores como si en lugar de nombres tuviesemos manejadores no?) despues... addr = es otra estructura... muchas veces se usan estructuras con las apis tanto para pasar info a la función como para recibir info. A veces esta info no es importante y por ejemplo en masm32 suelo crear un buffer sin nada y y en lugar de declarar tantas estructuras directamente paso la dirección de memoria del buffer... dirección de memoria... mmm si!! punteros!!! esta estructura se declara de este modo Type sockaddr sin_family As Integer sin_port As Integer sin_addr As Long sin_zero As String * 8 End Type en sin_family va la familia del socket, ¿como que socket? el que vamos a conectar, el que creamos con la función socket mas arriba y como argumento AddressFamily le pasamos 2 que es AF_INET, acá también. Que dolores de cabeza me estas dando niño!!! tu madre que dice de todo esto???!!! XD! en sin_port va el puerto, pero acá empieza a haber algunos detalles extras, porque si te vas a conectar al puerto 6667 por ejemplo de un servidor de IRC no hay que pasar el numero así como así. hay ciertos tipos de ordenamientos de bytes (byte order) uno es el de red (network) y el otro es el de host (JOST XDDD, lo de este paréntesis es broma no se confundan) para pasar de ordenamiento de red al de host se usa la función ntohs y para lo opuesto htons hey siempre me habían parecido letras a azar pero miren ntohs = Network to Host.. y la s? :S nosotros vamos a hacer que estos datos viajen a través de la red para hacer una petición de conexión y tenemos que cambiar el ordenamiento a NetWork con htons, pero antes viene uno de esos problemitas con el tamaño de la variable que no sucede en otros lenguajes, antes de usar la función htons hay que modificar el valor del puerto del siguiente modo If Not Valor <= 32767 Then Valor = Valor - 65536 End If o sea la función para cambiar el ordenamiento podría ser así (sin la declaración de htons) Private Function CambiarOrdenamiento(ByVal Valor As Long) As Integer If Not Valor <= 32767 Then Valor = Valor - 65536 End If CambiarOrdenamiento = htons(Valor) End Function continuando con la estructura sockaddr tenesmos la variable sin_addr, para la cual también hay que hacer ciertas cositas. Como se sabe una maquina en una red puede ser referida mediante un Hostname o una direccion IP, el primero es algo como achernar.com y el segundo es algo como 207.46.104.20. 1) partiendo de una ip: suponiendo 207.46.104.20 --> --> sin_addr = 20 * 256^0 + 104 * 256^1 + 46 * 256^2 + 207 * 256^3 2) partiendo de un hostname: aca hay que usar una api para manipular memoria (RtlMoveMemory) esta funcion guarda en una variable, una cierta cantidad de bytes copiados a partir de una direccion de memoria. Vamos a tener que usar esto porque hay funciones que retornan punteros y ahí es donde los VBoys estamos medio en p#lotas. la función gethostbyname toma una cadena con el hostname y retorna un puntero a una estructura HOSTENT, o sea los datos que queremos estan en alguna parte de la memoria y esta función nos da dicha dirección... después con RtlMoveMemory copiamos estos datos a una variable para poder manipular mejor estos datos. la estructura HOSTENT es esta Private Type HOSTENT Nombre As Long Alias As Long TipoDeDireccion As Integer Longitud As Integer ListaDeDirecciones As Long End Type en ListaDeDirecciones hay un puntero (una dirección de memoria) que apunta a un lugar donde hay otro puntero mas... si es una locura... y este ultimo puntero apunta a un lugar de la memoria donde esta la IP del host que estamos buscando lista para guardar en la variable sin_addr de la estructura sockaddr porque es para eso que estamos haciendo esto.. ya te habías olvidado... no te culpo... todo esto es para poder hacer una simple conexión TCP A causa de tener que manipular tantos punteros se usa varias veces RtlMoveMemory. NOTA: creo que, no estoy muy seguro, gethostbyname puede tomar también cadenas tipo IP (xxx.xxx.xxx.xxx) pero quería mostrar la transformación por potencias que puse antes. (a la IP 127.0.0.1 si la acepta perfectamente) volviendo a la estructura sockaddr queda ver el ultimo termino que es sin_zero y esto es fácil sencillamente no se toca... porque esta reservado. las declaraciones de estas funciones son las siguientes Declare Function Connect Lib "wsock32.dll" Alias "connect" (ByVal s As Long, _ addr As sockaddr, _ ByVal namelen As Long) As Long Declare Function htons Lib "wsock32.dll" (ByVal hostshort As Long) As Integer Declare Function gethostbyname Lib "WSOCK32" (ByVal szHost As String) As Long Private Declare Sub RtlMoveMemory Lib "kernel32" (hpvDest As Any, _ ByVal hpvSource As Long, _ ByVal cbCopy As Long) con esto ya podemos conectarnos por ejemplo a un servidor telnet... o por ejemplo cuando el netcat da una shell directa (no inversa) nos podemos conectar y hacernos una interfaz con letras tipo Papyrus (me encanta, me imagino revisando el correo en una carabela :P ) ahora luego de conectarnos tenemos que tener algún método para ver si hay algún mensaje entrante o si el host remoto se desconecto o si podemos escribir Hello Internet! la función que se utiliza para esto es select * select: ( retorna el estado del socket en cuestión [lectura/escritura/error] ) Declare Function vbselect Lib "ws2_32.dll" Alias "select" (ByVal nfds As Long, _ ByRef readfds As Any, _ ByRef writefds As Any, _ ByRef exceptfds As Any, _ ByRef timeout As Long) As Long esta función se usa de la siguiente manera... primero los 3 argumentos declarados tipo any son 3 estructuras fd_set que son así Private Type fd_set Contador As Long 'Cuantos sockets están en este estado? Arreglo(1 To 64) As Long 'Arreglo con los manejadores en cuestión. End Type son 3 estructuras una para información de lectura otra para escritura y otra para error cuando llamamos la función en el arreglo de cada una de estas estructuras metemos el manejador de nuestro socket (supongo que se pueden meter mas) y después de llamar la función leemos los contadores de estas estructuras... si el contador de la estructura de escritura esta en 1 (uno) es que hay datos para leer en el socket, si esta en 0 (cero es que no hay nada para leer) igual con la estructura de escritura o error. esta función me ha dado buenos resultados con error... cuando el host remoto se desconecta me responde como si tuviera un mensaje para leer, pero con la diferencia que cuando lo leo me dice que la longitud del mensaje es cero bytes... así que así hago para ver si se terminó la conexión con el host remoto. a los otros dos parámetro que quedan para llamar a esta función les pasamos cero como valor bueno ahora tenemos una conexión y sabemos fehacientemente que tenemos un mensaje para leer como hacemos? ahora lo explico, pero esperen unos minutos que tengo un llamado urgente de la naturaleza que no puedo eludir.................. ... ... .. . .. . ... . listo... uhh que alivio :P bueno acá vamos a terminar con la recepción y envío de datos con send y recv * recv: (recibe la data y la guarda en un buffer) Declare Function recv Lib "wsock32.dll" (ByVal s As Long, _ buf As Any, _ ByVal buflen As Long, _ ByVal flags As Long) As Long s = el manejador del socket buf = un buffer, una matriz tipo byte que yo suelo usar de 1 a 8192 buflen = tamaño del buffer... 8192 bytes flags = se pone a cero si todo sale bien retorna un valor que es la cantidad de bytes leídos, si retorna cero hubo algún error y ya explique que es como yo verifico si se corto la conexión con el host remoto. fácil no? hay un detallito... como la data la recibimos en un buffer tipo bytes hay que pasarla a una cadena de texto... y se hace asi StringBuffer = StrConv(ByteBuffer, vbUnicode) StringBuffer = Left$(StringBuffer, BytesRecibidos) acá no hay ninguna api StrConv, Left$ y vbUnicode son dos funciones y una constante todas de VB6 ufff y acá tomamos la recta final.... de esta TEORIA EMINENTEMENTE PRACTICA * send: (envía datos al host remoto tomándolos de un buffer) Declare Function Send Lib "wsock32.dll" Alias "send" (ByVal s As Long, _ buf As Any, _ ByVal buflen As Long, _ ByVal flags As Long) As Long funciona igual que send s = el manejador del socket buf = un buffer, una matriz tipo byte que yo suelo usar de 1 a 8192, pero ahora tomamos datos de este buffer.... buflen = tamaño del buffer... 8192 bytes flags = se pone a cero listo ya esta todo explicado como para hacer un cliente en una conexión TCP Título: Re: Introduccion a APIs y como evitar el uso de MSWINSCK.OCX con APIs Publicado por: Achernar en 5 Julio 2007, 23:30 pm el siguiente es el código que debe ponerse en un modulo de VB y se agrega a cada
proyecto que se quiera usar winsock y así no usamos fastidiosos OCX's Código: '<el codigo empieza justo despues de esta etiqueta> hay un par de funciones que tienen cosas al pedo pero funcionan igual como la de conectar y la de ver el estado del socket... le puse un par de cosas mas para mostrarlas, pero no son necesarias para que funcione Título: Re: Introduccion a APIs y como evitar el uso de MSWINSCK.OCX con APIs Publicado por: Achernar en 5 Julio 2007, 23:41 pm ahora pongo un código para un formulario que use este modulo...
es una terminal multipropósito... seria como una especie de telnet Código: '<el codigo empieza justo despues de esta etiqueta> Título: Re: Introduccion a APIs y como evitar el uso de MSWINSCK.OCX con APIs Publicado por: Achernar en 5 Julio 2007, 23:43 pm DIRECCIONES PARA INVESTIGAR MAS Y MAS Y.... BUENO
Esta es la api guide es un programa que contiene muchisimas apis Con ejemplos y declaraciones para VB http://www.soft-ware.net/hobby/programmierung/referenz/p03951.asp acá estan las funciones winsock en el MSDN de Microsoft… si aprenden a no perderse en ese mar de información les va a servir de mucho, http://msdn2.microsoft.com/en-us/library/ms741394.aspx y como siempre …. http://www.google.com.ar bufff que largo... esta es la despedida... hagámoslo rápido que no estamos en un aeropuerto. Salu2. |