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

Tamaño de letra:

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

En la parte II de esta serie de tutoriales, vimos cómo encontrar y acceder al código ensamblador que se ejecuta cuando pulsamos el botón Probar 2. Para encontrar dicho código, me ha hecho falta tener a mano estas informaciones:

Interfaz

  • Un depurador o desensamblador, en este caso, como el programa ha sido realizado en ensamblador a 32 bits y usa directamente las API de Windows, he decidido usar la herramienta OllyDBG.
  • El editor de recursos "Resource Hacker" nos ha ayudado a conocer las ID de los diversos controles.
  • La tabla de los mensajes de Windows ha sido muy importante para entenderlos.
  • Finalmente, entender las API de Windows y los parámetros de ellas.

Voy a escribir de nuevo, para tenerlo de referencia, el código asm (ensamblador) que es ejecutado al pulsar el botón Probar 2.

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.&amp;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.&amp;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.&amp;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.&amp;user32.MessageBoxA>
00401158   |.  jmp short 004011A1
...
 

Función GetDlgItemTextA

La primera parte del código (las 4 primeras líneas), nos llevan a una conocida API de Windows: GetDlgItemTextA. Veamos el código:

004010FC   |.  push 200
00401101   |.  push 403004
00401106   |.  push 3EA
0040110B   |.  push dword ptr ss:[ebp+8]
0040110E   |.  call 004011EA                      ; <jmp.&amp;user32.GetDlgItemTextA>
...
 

La función es muy sencilla de entender (GetDlgItemTextA: Recupera el título o el texto asociado a un control en un cuadro de diálogo) y hay que pasarle 4 parámetros:

GetDLGItemTextA(
HWND hwndDlg, // Manipulador del cuadro de diálogo del control
int nIDDlgItem, // Identificador del control
LPTSTR lpString, // Búfer que recibe la información
int nMaxCount // Máximo número de caracteres
);

Usando OllyDBG, depura el crackme y pon un breakpoint en la dirección 0040110E call 004011EA. Para que se detenga ahí, tendrás que escribir cualquier cosa en el textbox (yo he escrito karmany.NET, como se ve en la imagen 1 y pulsar el botón Probar 2). Ahora observa la pila para ver los parámetros que vamos a pasarle a la función:

CPU Stack
Address Value Comments
0018F8D4 /00180380 ; |hDialog = 00180380, class = #32770
0018F8D8 |000003EA ; |ItemID = 1002.
0018F8DC |00403004 ; |String =
0018F8E0 |00000200 ; \MaxCount = 512.

Como vimos en el anterior tutorial al abrir el crackme con Resource Hacker, el ID 1002 corresponde al control textbox (la caja donde he escrito karmany.NET). Por lo tanto, y en resumen, estas primeras 4 líneas lo que hacen es obtener el texto que hay escrito en el cuadro de texto 1. El texto, como ves en el código sobre estas líneas, va a ser almacenado en la dirección 00403004, así que en OllyDBG paso la función GetDlgItemTextA pulsando F8 y veo esto:

CPU Dump
Address Hex dump ASCII
00403004 6B 61 72 6D|61 6E 79 2E|4E 45 54 00|00 00 00 00| karmany.NET

Otro tema importante es que la función GetDlgItemTextA, devuelve en el registro eax el número de caracteres obtenidos. karmany.NET tiene 0B caracteres.

Verifica el número de caracteres

...
00401113   |.  cmp eax,3
00401116   |.  je short 0040111D
00401118   |.  jmp 004011A1
0040111D   |.  push 402040                        ; ASCII "luZ"
...
 

Compara si el número de caracteres es igual a 3. Si la longitud del texto escrito es distinta de 3, nos saca fuera de la subrutina (jmp 004011A1). Ahora ya sé que karmany.NET no va a ser un serial válido, así que lo cambio y pongo solamente kar.

Función lstrcmpA

Lo siguiente que nos encontramos es esto:

...
0040111D  push 00402040                            ; /String2 = "luZ"
00401122  push 00403004                            ; |String1 = "kar"
00401127  call 004011D2                            ; \KERNEL32.lstrcmp
0040112C  or eax,eax
0040112E  jnz short 004011A1
...
 

lstrcmpA es una función muy conocida que tiene solo dos parámetros y compara dos cadenas de texto. Como puedes observar, compara nuestro kar con luZ y si son diferentes, nos saca de la subrutina. La comparación la hace distinguiendo mayúsculas de minúsculas, por lo tanto, reinicio todo y escribo exactamente luZ 1 y pulso otra vez el botón Probar 2.

Carga de un Bitmap

...
00401130   |.  push 402044                        ; ASCII "nombreimagen"
00401135   |.  push dword ptr ds:[403000]         ; asm02.00400000
0040113B   |.  call 004011F0                      ; <jmp.&amp;user32.LoadBitmapA>
 

El código sobre estas líneas, carga una imagen (gráfico) en formato bitmap. Para ello hace uso de la función LoadBitmapA que se define así:

HBITMAP LoadBitmap(
HINSTANCE hInstance, ;Manejador de la instancia de la aplicación
LPCTSTR lpBitmapName ;Cadena de texto que define al recurso buscado
);

Si la función tiene éxito, la función devuelve en eax el handle al recurso (a la imagen). Para que conozcas qué imagen va a ser cargada, abre asm02.exe en Resource Hacker y despliega Bitmap, verás lo siguiente:

Resource Hacker, recurso Bitmap

Si la imagen se carga correctamente, el código se sigue ejecutando en 0040115A:

...
0040113B   |.  call 004011F0                      ; <jmp.&amp;user32.LoadBitmapA>
00401140   |.  or eax,eax
00401142   |.  jnz short 0040115A
...
 

Envía la imagen con SendMessageA

SendMessage es posiblemente una de las funciones más utilizadas, principalmente por la versatilidad de su uso, me explico: muchas veces querrás realizar una determinada acción y es posible que no recuerdes o no conozcas la función que necesitas. Pues bien, para estos casos, puedes utilizar SendMessage pasándole un determinado mensaje (como su nombre indica, SendMessage es Enviar Mensaje.) En nuestro caso:

...
0040115A  push eax                                 ; /lParam = DB050C7E
0040115B  push 0                                   ; |wParam = IMAGE_BITMAP
0040115D  push 172                                 ; |Msg = STM_SETIMAGE
00401162  push dword ptr ds:[403804]               ; |hWnd = 003007C8, class = Static, text = #1111
00401168  call 00401202                            ; \USER32.SendMessageA
...
 

El mensaje enviado es STM_SETIMAGE que significa que se va a asociar una nueva imagen (un mapa de bits) con un control estático, es decir, que la imagen que se ha cargado se va a poner en un control estático. El registro eax lleva el handle de la imagen y el control estático tiene de texto 1111. Observa a qué corresponde en Resource Hacker, desplegando Dialog.

Las 4 últimas funciones ShowWindow

ShowWindow, como podrás imaginar, lo que hace es mostrar u ocultar una ventana. El código en OllyDBG, viene muy bien explicado:

...
0040116D  push 0                                   ; /Show = SW_HIDE
0040116F  push dword ptr ds:[403808]               ; |hWnd = 004D0564, class = Static
00401175  call 00401208                            ; \USER32.ShowWindow
0040117A  push 0                                   ; /Show = SW_HIDE
0040117C  push dword ptr ds:[40380C]               ; |hWnd = 004006F0, class = Button, text = Probar
00401182  call 00401208                            ; \USER32.ShowWindow
00401187  push 0                                   ; /Show = SW_HIDE
00401189  push dword ptr ds:[403810]               ; |hWnd = 00160280, class = Edit
0040118F  call 00401208                            ; \USER32.ShowWindow
00401194  push 5                                   ; /Show = SW_SHOW
00401196  push dword ptr ds:[403814]               ; |hWnd = 001C07C6, class = Button, text = X
0040119C  call 00401208                            ; \USER32.ShowWindow
 

SW_HIDE oculta la ventana, mientras que SW_SHOW la muestra. Los manejadores fueron obtenidos en otra parte del código mediante GetDlgItem. Por orden de ejecución, el código hace lo siguiente:

  1. Oculta el control estático que está en la parte inferior
  2. Oculta el botón Probar 2
  3. Oculta el textbox donde se escribe
  4. Muestra el botón X

Espero que toda esta explicación te haya servido para entender el código. Aunque en este momento no es seguro, es posible que continúe hablando sobre este interesante CrackME, por ejemplo, para modificarlo y hacer que acepte cualquier serial o hacer otras cosas un poco más avanzadas. Ya veremos...

Última actualización: Sábado, 07 Febrero 2015
Comentarios  
+1 # hackyy 25-08-2017 20:46
Excelente tuto, estoy empezando y me ha servido mucho.
Gracias
0 # Max 11-10-2016 08:37
Guapissimo tutorial , tio , gracias
0 # richard 12-04-2015 23:48
Estupenda Web, muy buena explicación del código ensamblador.
0 # Juan 07-04-2015 04:17
Un tutorial claro y sencillo, felicitaciones, una consulta tienes algun tuto sobre desempacado del PECompact 2.x
+2 # Editor 07-04-2015 07:22
Recuerdo que hay uno bueno en la web de Ricardo Narvaja. Busca en Google:
Buscador Ricardo narvaja
Y en ese buscador busca por PECompact
0 # Jose 07-03-2015 15:32
Excelentísimo tutorial, felicitaciones

No tiene privilegios para responder a los comentarios.


 
Visitas: 8567613