Ejemplo 08Modificar el título de una ventana por uno más largo en VB6.
Sobre Visual Basic (III)Antes de nada quiero hacer una pequeña introducción que el que quiera puede saltarse:
Debido a la buena acogida que ha tenido el tutorial, y la cantidad de mensajes que recibo solicitando ayuda, sigo ampliándolo con nuevas ideas. Recibo preguntas que cada vez son más complicadas, pero intentaremos hacer todo lo más sencillo posible.
Antes de comenzar, hay que tener claras bastantes cosas y releer varias veces el tute porque puede ser difícil de entender.
Ya que hay mucha gente que pregunta por este tema, voy a modificar el título de un programa compilado con Visual Basic 6 por otro título mucho más largo.
1ª FORMA:Esta primera manera de hacerlo es la más complicada haciendo uso de una API.
Descargar el programa sol.exe (está como sol.zip) que está en el archivo .zip. El enlace está en el primer mensaje de este hilo.El título del programa original es "Sol":
Imagen44 y voy a modificarlo por "Título mucho más largo - karmany".
Para hacer esto, se podría intentar modificar el puntero de "Sol" pero en VB6 no es sencillo hacerlo. También se podría intentar modificar el título utilizando la misma función de VB pero también es una ardua tarea, así que, en principio se me ocurre que la forma más sencilla es hacerlo utilizando la API "SetWindowText".
SetWindowText requiere 2 datos: el puntero a la cadena "Título mucho más largo - karmany" y el handle de la ventana. Éste ultimo dato es el más complejo de encontrar pero VB6 en determinados momentos lo deja bien visible en la pila.
Bueno, sabiendo ya cómo lo voy a hacer, queda lo más importante: Y... ¿cómo se puede obtener la dirección de "SetWindowText" para poder utilizar dicha API?. Este es el dato más complicado de encontrar para todo Newbie y por este hecho se debe entender perfectamente:
Voy a insertar en la IAT (que en el programa original será toda de funciones de la librería de VB6) nuestra dirección de "SetWindowText". Por lo tanto, lo que voy a hacer es modificar la IMAGE IMPORT DESCRIPTOR la cual nos dará la dirección correcta de "SetWindowText". Como sé que habrá gente que no tiene ni idea de qué es la IMAGE IMPORT DESCRIPTOR pues me remito a los fantásticos tutoriales de Ricardo Narvaja en los que explica paso a paso qué es y para qué sirve.(Titulados: Import Tables lento y a mano). Puede ser difícil de entender si no se tiene práctica, pero voy a intentar explicarlo lo más sencillo que pueda...
Lo que voy a hacer para este ultimo caso es crear una nueva sección y ahí pondré la IID y la IAT. Para hacer esto de forma muy requetesencilla, voy a utilizar el programa ImportRE que hace siempre una labor importantísima.
De este modo, como en un programa compilado con Visual Basic 6, la IAT está normalmente en la dirección 401000 pues al cambiarla de sitio, tendré ahí espacio suficiente para hacer un injerto.
Bien con todo lo que acabo de explicar, ya estamos en condiciones de empezar:
El programa que he creado se llama "Sol.exe". No lo voy a poner de momento en descarga, pero si alguien realmente lo necesita que me lo pida.
Abro "Sol.exe" en el OllyDBG. Parado en el OEP. Voy a 401000 y veo la IAT:
00401000 DD MSVBVM60._CIcos ; 1º dato de la IAT
00401004 DD MSVBVM60._adj_fptan ; 2º dato de la IAT
00401008 DD MSVBVM60._adj_fdiv_m64 ; 3º dato de la IAT
....
....
00401070 DD MSVBVM60._CIexp ;29º dato de la IAT
00401074 00000000 ;Indica final
00401078 01000800
0040107C FA194000
00401080 FF25 20104000 JMP NEAR DWORD PTR DS:[401020] ;1º Salto a la IAT
....
Bien, para que después ImportRE nos diga que hay una función pero que no sabe cuál es voy a modificar los datos de 401078 y 40107C de este modo:
00401070 DD MSVBVM60._CIexp ;29º dato de la IAT
00401074 00000000 ;Indica final
00401078 77777777 ;pongo un número cualquiera
0040107C 00000000 ;0 para "decirle que es el final"
00401080 FF25 20104000 JMP NEAR DWORD PTR DS:[401020] ;1º Salto a la IAT
Pues ya podemos ejecutar ImportRE, seleccionamos "Sol.exe" y abajo a la izquierda ponemos los 3 datos siguientes:
OEP: 00001130 (Ya que el OEP es 00401130 y la Image Base 400000)
RVA: 00001000 (Ya la IAT comienza en 00401000)
Size:0000007C (Ya que como se ve antes, en 401078 hemos puesto 77777777)
Pulsamos en "Get Imports" y aparece lo siguiente:
+ msvbvm60.dll FThunk:00001000 NbFunc:1D (decimal:29) valid:YES
- ?FThunk:00001078 NbFunc:1 (decimal:1) valid:NO
rva:00001078 ptr:77777777
Perfecto. Como se observa ha reconocido nuestras 29 funciones de la librería de VB y nos dice que hay una función de otra librería que no reconoce y que la dirección es 77777777 que ya habíamos preparado para tal fin. Como ya sabemos qué API necesitamos: "SetWindowTextA", pues clickeamos 2 veces y seleccionamos dicha API. Y ya nos aparecerá lo siguiente:
+ msvbvm60.dll FThunk:00001000 NbFunc:1D (decimal:29) valid:YES
- user32.dll Fthunk:00001078 NbFunc:1 (decimal:1) valid:YES
rva:00001078 mod:user32.dll ord:0287 name: SetWindowTextA
Perfecto. Ahora pulsamos en "Fix Dump" seleccionamos "Sol.exe" y nos crea satisfactoriamente "Sol_.exe". El trabajo que hace ImportRE es fantástico.
TRUCO PARA HACERLO FUNCIONAR
.
De este modo hemos creado ya una nueva sección, y ahí hemos puesto la
IID y la
IAT.
Si se ejecuta da error, así que después de analizarlo detenidamente descubrí que el problema es culpa de un dato: "Bound Import". Para solucionarlo, hay que abrir "Sol_.exe" en un editor de PE y modificar tanto el dato "Bound Import RVA" como Bound Import Size" y poner los 2 a CERO. Ya funciona "Sol_.exe".
Ahora ya se observa que en 401000 ya no está la IAT y podemos utilizar este espacio para poner el código que nosotros queramos.
Lo primero que hago es ver qué eventos hay. Yo utilizo esta vez VB Decompiler Lite y obtengo que en 4019B0 comienza Form.Load.
Ahora lo que me interesa es buscar el handle de la ventana a la que quiero modificar el título.
Me pongo al final de esta subrutina(Form.Load):
...
00401A09 POP EDI
00401A0A POP ESI
00401A0B MOV DWORD PTR FS:[0],ECX
00401A12 POP EBX
00401A13 MOV ESP,EBP
00401A15 POP EBP
00401A16 RETN 4
Pongo un Breakpoint(BP) por ejemplo en 401A09. Pongo también un BP en la API "CreateWindowExA" y voy pulsando F9 hasta que para en "CreateWindowExA" y es por nuestra ventana: (Windows name: "Sol"). Traceo hasta el RET de "CreateWindowExA" para observar el handle y veo que en mi caso el handle (registro eax) es: 001105F2
Pulso F9 y para en 00401A09 y observo la pila encontrándome lo siguiente:
ESP 0013FB20
ESP+4 0013FBF0
ESP+8 00000001
ESP+C 00CF49C8
ESP+10 001105F2
¡Umm! parece ser que si paro en 401A09, tengo en ESP+10 el ¡handle de mi ventana!. Interesante. Pues con este dato ya podemos hacer el injerto.
Así que modifico el original código de 00401A09 por lo siguiente:
00401A09 JMP 00401000
00401A0E NOP
00401A0F NOP
00401A10 NOP
00401A11 NOP
00401A12 POP EBX
00401A13 MOV ESP,EBP
00401A15 POP EBP
00401A16 RETN 4
Me he comido 3 instrucciones.
Y en 00401000 hago el siguiente injerto:
00401000 PUSHAD ;Guardo todos los registros
00401001 PUSH 401020 ;1º dato "SetWindowTextA" Texto = "Título mucho más largo - karmany"
00401006 PUSH DWORD PTR SS:[ESP+34] ;2º dato "SetWindowTextA" handle ventana
0040100A CALL NEAR DWORD PTR DS:[404078] ;Call "SetWindowTextA"
00401010 POPAD ;restauro todos los registros
00401011 POP EDI ;1ª instrucción que me comí
00401012 POP ESI ;2ª instrucción que me comí
00401013 MOV DWORD PTR FS:[0],ECX ;3ª instrucción que me comí
0040101A JMP 00401A12 ;vuelve al código
Se observa que tras hacer los push el dato del handle que era [esp+10] se ha convertido en [esp+34].
También hay que observar que la dirección [404078] es de SetWindowTextA que es donde está la IAT.
Finalmente sólo queda insertar nuestro texto en 401020, terminado en cero:
00401020 54 ED 74 75 6C 6F 20 6D 75 63 68 6F 20 6D E1 73 Título mucho más
00401030 20 6C 61 72 67 6F 20 2D 20 6B 61 72 6D 61 6E 79 largo - karmany
00401040 00
.
Y asunto terminado.
El ejemplo final es el siguiente:
Imagen45 Si quieres analizar el resultado puedes descargar cómo me ha quedado a mí:
Descargar el programa sol_2.exe (está como sol_2.zip) que está en el archivo .zip. El enlace está en el primer mensaje de este hilo.Ya sé de antemano, que esto que acabo de explicar no es nada sencillo, pero es la forma que se me ha ocurrido de hacerlo.
2ª FORMA:Tras haber publicado la 1ª FORMA recibí varios mensajes en los que me comentabais que era posible hacerlo de una manera más sencilla, usando determinados programas que ya hemos analizado en ej. anteriores.
Realmente existen programas como VBReformer, del que ya hablé en el ejemplo 6, que nos permiten modificar directamente el título de la ventana que tenemos por defecto. Es decir, podemos abrir el programa en VBReformer, observar todo lo que ha analizado y tras seleccionar en el panel izquierdo el formulario que deseamos, nos aparecerá en el panel derecho los controles y propiedades de dicho formulario y podremos modificarlos. Después simplemente guardamos.
Realmente para una persona que no se quiere complicar o no tiene suficientes conocimientos para entender el ejemplo que propuse, pues es una muy buena opción y podría ser la primera opción que deberíamos usar.
Por contra, VBReformer no siempre compila adecuadamente o no siempre puede abrir todos los programas. Además si el título se modificara en algún evento, tampoco nos valdría... Bueno, todo es cuestión de probar, de gustos y de lo que nuestra imaginación proponga- Las dos formas explicadas son válidas.
Para cualquier duda...