Cómo crackear mi primer programa legalmente (parte II)

Tamaño de letra:

Encontrando el código al pulsar un botón

Si echas un vistazo al tutorial anterior, te empezarás a dar cuenta que depurar y analizar un programa, te puede servir también para entender el modo de programar un software (en este caso para Windows a 32 bits). Ahora estás viendo las API de Windows, los parámetros que le hemos pasado a la función DialogBoxParamA que está en user32.dll, y cómo capturar lo mensajes de la nueva ventana creada, que en definitiva, es la ventana que estás viendo en el programa (la interfaz):

Interfaz CrackMe

Lo último que hicimos fue observar el código cuando la ventana es iniciada con el mensaje de Windows WM_INITDIALOG que corresponde al valor hexadecimal 110. Ahora voy a hacer que busques todos los mensajes capturados de Windows y analices el código del programa desde el inicio de esta subrutina hasta su final:

 
0040102E   /.  push ebp
0040102F   |.  mov ebp,esp
00401031   |.  mov eax,dword ptr ss:[ebp+C]
00401034   |.  cmp eax,110
00401039   |.  jnz short 004010BA
...
 

¡No mires la siguiente tabla! e intenta buscar los mensajes principales de Windows por ti mism@. ¿Qué mensajes de Windows has encontrado? Yo he encontrado los siguientes:

Mensajes de Windows encontrados

Dirección

Código

Mensaje de Windows

00401034 cmp eax,110 WM_INITDIALOG
004010BA cmp eax,111 WM_COMMAND
004011A3 cmp eax,10 WM_CLOSE

Mensaje WM_COMMAND

El mensaje WM_COMMAND, según Microsoft, es enviado cuando:

Sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.

El mensaje WM_COMMAND es enviado cuando el usuario selecciona un comando de un ítem de un menú, cuando un control envía un mensaje de notificación a su ventana padre, o cuando una pulsación de un acelerador es traducida.

Como podrás pensar, al pulsar el botón "Probar" 2, enviaremos el mensaje WM_COMMAND, por lo tanto, nos centraremos en este mensaje. Ahora vuelve a analizar el código dentro de la comparación 111. Te pongo el inicio:

 
004010C5   |.  mov eax,dword ptr ss:[ebp+10]
004010C8   |.  cmp eax,3EC
004010CD   |. jnz short 004010D6
...
 

¿Qué significa esto?

Voy a explicar el significado del siguiente código, donde el registro eax va a tomar un determinado valor:

004010C5  mov eax,dword ptr ss:[ebp+10]

Si has leído el anterior artículo, hablamos que en la dirección

 
0040102E   /.  55                  push ebp
...
 

Comenzaba una función que es el procedimiento del diálogo, donde se procesan los mensajes que estamos viendo, enviados al cuadro de diálogo. Dicha función tiene 4 parámetros y la definimos así:

DialogProc(
    HWND hwndDlg,  // Manipulador de cuadro de diálogo
    UINT uMsg,     // Mensaje
    WPARAM wParam, // Parámetro adicional
    LPARAM lParam  // Parámetro adicional
  );

Si depuramos con OllyDBG y ponemos un Breakpoint en:

004010C5  mov eax,dword ptr ss:[ebp+10]

Y ahora, por ejemplo, haces clic en el textbox, es posible que veas que eax va a tomar DWORD parecidos a estos:

Stack ss:[0012F868]=010003EA
eax=00000111

En tu caso puede ser diferente, olvida tu resultado y observa mi ejemplo. El registro eax vale 111 (WM_COMMAND) y va cargarse con 010003EA. ¿Qué significa 010003EA? Esto es muy importante y realmente lo que el código está haciendo dentro de DialogProc es esto:

eax = wParam

Bueno, pensarás, ¿y qué significa wParam en DialogProc? wParam es un DWORD que contiene dos WORD. El WORD de más peso se escribe con el prefijo HI mientras que el de menor peso se escribe comenzando por LO. Los voy a separar para que lo veas muy claro:

wParam = 010003EA
HIWORD(wParam) = 0100
LOWORD(wParam) = 03EA

Muy sencillo. Ahora que están separados veamos sus definiciones:

Te puedes ayudar del enlace que he puesto más arriba en la cita de WM_COMMAND de Microsoft. Allí hay una tabla que explica estos datos y otros valores cuando se trata de un menú o acelerador.

  • HIWORD(wParam): Código de notificación.
  • LOWORD(wParam): Identifica al control.

En este ejemplo, el valor LOWORD es 03EA que en decimal es 1002. Para ver a qué control corresponde, abre de nuevo asm02.exe en Resource Hacker, ve a Dialog > 101 > 1033 y observa ese:

CONTROL "", 1002 EDIT

Resource Hacker

Y el valor HIWORD es 0100. Para un control Edit, el código de notificación 0x100hex corresponde a:

EN_SETFOCUS //El textbox recibe el foco

Si tienes instalado C++ o C#, puedes abrir el archivo winuser.h y verás todos los valores de cada constante (o buscar el archivo por la Red).

Ahora ya está claro:

wParam = 010003EA

Significa que el textbox donde escribimos la contraseña en el CrackMe, ha recibido el foco. ¿Y cómo podemos encontrar el código del botón "Probar"?

Localizar el código del botón Probar

Como acabamos de ver, el código tras haber pulsado un botón, carga wParam en eax:

eax = wParam

Que es exactamente esto:

 
004010C5   mov eax,dword ptr ss:[ebp+10]
 

Después compara directamente eax con 3EC, 3EF y 3EB:

 
004010C8   cmp eax,3EC
...
004010D6   cmp eax,3EF
...
004010F1   cmp eax,3EB
...
 

En principio, puede parecerte un poco extraño porque sobre estas líneas hemos visto que wParam está compuesto de 2 WORD. ¿Cómo es posible que se compare directamente el DWORD? Esta es una muy buena pregunta. Las comparaciones 3EC (1004 decimal), 3EF (1007 decimal) y 3EB (1003), corresponden a los identificadores de 3 controles. Abre asm02.exe en Resource Hacker y búscalos. Verás que corresponden a:

3EC (1004): Es el botón de la "X" que cierra la aplicación.
3EF (1007): Es el botón del "?" que muestra una ventana con información.
3EB (1003): Es el botón "Probar".

Los 3 controles tienen una cosa en común: son 3 botones. Pensemos en el botón "Probar". Significa que el valor LOWORD(wParam) tiene que ser 03EB, por lo tanto, tenemos que:

HIWORD(wParam) = 0000
LOWORD(wParam) = 03EB
wParam = 000003EA

Y esto nos hace deducir que el valor HIWORD es cero. Ahora viene la pregunta... ¿Cuál es el código de notificación de un BUTTON que valga 0000? Echo un vistazo al archivo antes mencionado y observo que:

BN_CLICKED = 0

Enviado cuando un usuario hace clic en un botón. Por lo tanto, el código cuando se hace clic en el botón Probar 2, es el siguiente:

 
004010F1   >> cmp eax,3EB
004010F6   |.  jnz 004011BD
004010FC   |.  push 200
00401101   |.  push 403004
00401106   |.  push 3EA
0040110B   |.  push dword ptr ss:[ebp+8]
0040110E   |.  call 004011EA                      ; <jmp.&user32.GetDlgItemTextA>
00401113   |.  cmp eax,3
00401116   |.  je short 0040111D
00401118   |.  jmp 004011A1
0040111D   |.  push 402040                        ; ASCII "luZ"
00401122   |.  push 403004
00401127   |.  call 004011D2                      ; <jmp.&kernel32.lstrcmpA>
0040112C   |.  or eax,eax
0040112E   |.  jnz short 004011A1
00401130   |.  push 402044                        ; ASCII "nombreimagen"
00401135   |.  push dword ptr ds:[403000]         ; asm02.00400000
0040113B   |.  call 004011F0                      ; <jmp.&user32.LoadBitmapA>
00401140   |.  or eax,eax
00401142   |.  jnz short 0040115A
00401144   |.  push 0
00401146   |.  push 402064                        ; ASCII "Error carga de imagen"
0040114B   |.  push 402051                        ; ASCII "Ha habido un error"
00401150   |.  push dword ptr ss:[ebp+8]
00401153   |.  call 004011FC                      ; <jmp.&user32.MessageBoxA>
00401158   |.  jmp short 004011A1
 

En C++, todo este código para la pulsación de un botón, de se suele hacer algo similar a esto:

 
LRESULT CALLBACK karmany_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
     switch (message) {
          case WM_COMMAND:
               if((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == MI_BOTON)) {
                    //Código dentro del botón que es el que vamos a buscar ahora.
               }
         break;
     }
}
 

Espero que se haya entendido bien la forma de conseguir llegar y depurar el código al pulsar un botón. En el siguiente artículo analizaremos detenidamente dicho código.

Última actualización: Martes, 23 Diciembre 2014
Comentarios  
+2 # Elektro 24-01-2015 16:39
Acabo de descubrir tu blog, es excelente la forma en que explicas los pasos a seguir, hasta el más novato se entera bien, simplemente genial, gracias por estos tutos de ing. inversa y también por el de la recuperación manual (abriendo la carcasa) de un HDD. Saludos
0 # karmany 25-01-2015 13:27
Es todo un alago oír esas palabras y más de ti, del que tengo que aprender un montón. Solo hace falta ver tu contribución al foro y muchas veces compartiendo el código fuente como con Imgur Uploader.Net.
Un saludo

No tiene privilegios para responder a los comentarios.


 
Visitas: 8487646