Karpoff Spanish Tutor 2001

Programa:

Absolute Security 3.9


 

PROTECCION: Un serial distinto para cada día..
Objetivo:

Hacer un Keygen.

Descripcion:

Utilidad para encriptar archivos.

Dificultad: Aficionado
DOWNLOAD:

http://www.pepsoft.com/absecpro.zip

Herramientas:

Softice,MAsm32.

CRACKER: CaoS ReptantE   FECHA: 18/11/2001

 

 INTRODUCCION

 Este tutorial sigue al de 5 StarWinzip. En ese programa me encontré con que el serial correcto cambiaba de un día para otro y resolví el tema de una manera muy complicada, actuando sobre el registro (se trata de aprender ¿no?). Aquí vamos a operar sobre otro programa de la misma empresa con una protección casi idéntica y buscaremos la manera de hacer un keygen. El interés que pueda tener este tutorial está en el uso de la función GetLocalTime y por supuesto en remarcar el hecho de que con obtener un serial para registrarnos, es posible que no hayamos terminado nuestro trabajo.

 

 AL ATAKE

 
Procederemos como en otras ocasiones. Con el SoftIce cargado, llegamos a la ventana de registro, ponemos unos datos chungos, antes de aceptar entramos en el SIce y colocamos nuestro bpx favorito (hmemcpy), salimos del SIce y pulsamos OK. Salta el SIce porque el programa ha leído el nombre, le damos a F5 para que lea la clave y después le damos a F12 siete veces para llegar al programa. Aparecemos aquí:

:0042C1DD 5E                      pop esi

Ahora es cuestión de ver cuando el programa lee nuestro nombre para ver que hace con él (instrucción s 0 l ffffffff 'nombre' y a continuación bpm o bpr de la dirección o direcciones obtenidas). Ahora empieza un largo peregrinaje para llegar a la rutina de generación del serial. Durante este largo camino veremos como el nombre va pasando de un sitio a otro, lo que nos obligará a poner más instrucciones bpr (como sólo podemos utilizar cuatro instrucciones bpm, ya se nos han acabado). También es conveniente repetir la búsqueda con la instrucción s... por si alguno de estos movimientos nos ha pasado desapercibido. Llegamos a un punto interesante:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406310(C)
|
:004062FD 8A02                    mov al, byte ptr [edx]
:004062FF 3C61                    cmp al, 61
:00406301 7206                    jb 00406309
:00406303 3C7A                    cmp al, 7A
:00406305 7702                    ja 00406309
:00406307 2C20                    sub al, 20

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00406301(C), :00406305(C)
|
:00406309 8806                    mov byte ptr [esi], al
:0040630B 42                      inc edx
:0040630C 46                      inc esi
:0040630D 4B                      dec ebx
:0040630E 85DB                    test ebx, ebx
:00406310 75EB                    jne 004062FD

Como podéis ver, pasa todas las minúsculas a mayúsculas. Los números y otros caracteres, entre ellos la ñ, la ç y las letras acentuadas, quedan como estaban. Tened en cuenta que ahora hay que buscar nuestro nombre con mayúsculas. Tras otro buen rato de tracear llegamos a:

:0040393D 8B0E                    mov ecx, dword ptr [esi]
:0040393F 8B1F                    mov ebx, dword ptr [edi]
:00403941 39D9                    cmp ecx, ebx
:00403943 7558                    jne 0040399D

Aquí el programa compara el nombre con mayúsculas con el nombre tal como lo hemos entrado. Este mismo código se utiliza para varias comparaciones, entre ellas la del serial chungo con el correcto. Esto hace que el parcheado del programa sea algo problemático :-( Continuamos, y llegamos por fin a la madre del cordero:

:0048C70C 0FB63E                  movzx edi, byte ptr [esi]

Pone en EDI la dirección del texto: "CAOS REPTANTECA". Si el nombre introducido tuviera quince o más caracteres, aparecería completo. Como en este caso no es así, aparecen los trece caracteres del nombre introducido, más los dos primeros, que hacen una longitud total de quince caracteres.

:0048C70F 8B45F8                  mov eax, dword ptr [ebp-08]
:0048C712 0FB64418FF              movzx eax, byte ptr [eax+ebx-01]

Coloca en EAX la dirección de: "ZZMd5elXW69mPqR".

:0048C717 6603F8                  add di, ax
:0048C71A B8E4C74800              mov eax, 0048C7E4
:0048C71F 0FB64418FF              movzx eax, byte ptr [eax+ebx-01]
:0048C724 6603F8                  add di, ax

El programa suma los códigos ASCII del primer carácter de los textos anteriores. A continuación coloca en EAX la dirección del texto: "110101v3.9ABSECPRO" (las seis cifras que están al principio corresponden al día de la fecha en formato mmddaa), y suma el código de su primer carácter a la suma anterior.

:0048C727 33C0                    xor eax, eax
:0048C729 8A85FBFBFFFF            mov al, byte ptr [ebp+FFFFFBFB]
:0048C72F 6603F8                  add di, ax

Pone en AL el código ASCII de la cifra de las decenas correspondientes al día de la fecha y lo suma.

:0048C732 33C0                    xor eax, eax
:0048C734 8A85FCFBFFFF            mov al, byte ptr [ebp+FFFFFBFC]
:0048C73A 6603F8                  add di, ax

Pone en AL el código ASCII de la cifra de las unidades correspondientes al día de la fecha y lo suma.

:0048C73D 0FBFC7                  movsx eax, di
:0048C740 B917000000              mov ecx, 00000017
:0048C745 99                      cdq
:0048C746 F7F9                    idiv ecx

Finalmente coloca la suma total en EAX y la divide por 23 (17h)

:0048C748 B8FCC74800              mov eax, 0048C7FC

EAX señala al texto: "ABCDEFGHJKLMNPQRTUVWXYZ".

:0048C74D 8A1410                  mov dl, byte ptr [eax+edx]

Ya tenemos en DL la primera letra del serial. Corresponde al resto de la división (en EDX) y puede ser desde la "A" (0) hasta la "Z" (22).

Sigue el código pero ya sabemos lo que nos interesa sobre la generación del serial. Este bucle se repite quince veces, hasta completar el serial con las letras que forman los textos que hemos visto. Lo único que no varía son las cifras del día de la fecha, que siempre son las mismas: 0 y 1 (os recuerdo que estamos a 1 de noviembre). En resumen:

      (C)      (A)      (O)      (S)               (A)
       43       41       4F       53      ...       41
      (1)      (1)      (0)      (1)               (C)
       31       31       30       31      ...       43
      (Z)      (Z)      (M)      (d)               (R)
       5A       5A       4D       64      ...       52

       30       30       30       30      ...       30

    +  31       31       31       31      ...       31
      ___      ___      ___      ___               ___

      12F      12D      12D      149      ...      137

:17h    D        D        D        E      ...        D

resto:  4        2        2        7      ...        C

letra:  E        C        C        H      ...        N

Bueno, pues ya está. Ahora vamos a por el Msam y nos montaremos dos archivos: el de recursos rsrc.rc en el que definiremos la ventana del keygen y los elementos que van en ella, y el de código Absolute.asm en el que estarán las instrucciones de nuestro programa. Os recomiendo los tutoriales: Como Craquear con Ensamblador para Win32 de Mr. Crimson (los podéis encontrar en la Compilación de Tutoriales 2000 4.0 del Pr@fEsOr X). Espero que os sean tan útiles como a mí ;-)

#include "\masm32\include\resource.h"

#define IDD_DIALOG         1000
#define IDC_NOMBRE         1001
#define IDC_SERIAL         1002
#define IDC_GEN            1003
#define IDC_INFO           1004
#define IDC_EXIT           1005
#define IDC_STATIC         -1

app ICON key.ico

IDD_DIALOG DIALOG 100,100,147,121

STYLE WS_CAPTION | DS_CENTER | WS_SYSMENU |WS_MINIMIZEBOX

CAPTION "CaoS ReptantE"

FONT 10, "MS Sans Serif"

BEGIN

    GROUPBOX         "Programa",IDC_STATIC,8,6,131,20
    LTEXT            "Absolute Security PRO 3.9",IDC_STATIC,12,14,115,8,ES_CENTER
    GROUPBOX         "Website",IDC_STATIC,8,28,131,20
    LTEXT            "www.pepsoft.com",IDC_STATIC,12,36,115,8,ES_CENTER
    GROUPBOX         "Registro",IDC_STATIC,8,50,131,44
    LTEXT            "Nombre",IDC_STATIC,18,61,25,8
    EDITTEXT         IDC_NOMBRE,45,60,80,11,ES_AUTOHSCROLL | ES_CENTER
    LTEXT            "Serial",IDC_STATIC,18,78,25,8
    EDITTEXT         IDC_SERIAL,45,77,80,11,ES_CENTER | ES_READONLY
    PUSHBUTTON       "Generar",IDC_GEN,8,101,37,14
    PUSHBUTTON       "Info",IDC_INFO,55,101,37,14
    PUSHBUTTON       "Salir",IDC_EXIT,102,101,37,14

END

Lo dicho, ahí está la ventana y los elementos que hay en ella, con sus dimensiones y características. No parecen necesarias más explicaciones. Ahora vamos a por el archivo de código.

.386

.model flat,stdcall

option casemap:none

include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\advapi32.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\advapi32.lib
includelib c:\masm32\lib\kernel32.lib

.const

IDD_DIALOG           EQU 1000
IDC_NOMBRE           EQU 1001
IDC_SERIAL           EQU 1002
IDC_GEN              EQU 1003
IDC_INFO             EQU 1004
IDC_EXIT             EQU 1005

DlgFunc PROTO :DWORD,:DWORD,:DWORD,:DWORD
Operacion PROTO
Subrutina PROTO

El procedimiento principal y las dos subrutinas que vamos a utilizar.

.data

Icono     db "app",0
Iconimage db "app",0
error1    db "¡Error!",0
error2    db "¡Mínimo cinco caracteres!",0
txt1      db "El serial que proporciona este programa sólo es válido ",\
             "para el día de hoy.",13,10,\
             "¡Date prisa! ¡Antes de que den las 12!",13,10,13,10,\
             "Saludos de CaoS ReptantE :o)",0
txt2      db "Información",0
nomorig   db "CaoS ReptantE",12 dup (0),0
nombre    db 25 dup (0),0
serial    db 15 dup (0),0
campo     db 16 dup (0),0
fecha     db 8 dup (0),0
dia       db 0,0,0
cadena1   db "ZZMd5elXW69mPqR",0
cadena2   db 6 dup (0),"v3.9ABSEC",0
abc       db "ABCDEFGHJKLMNPQRTUVWXYZ",0
hInstance dd 0
hIcon     dd 0
hWnd      dd 0

La variable nomorig debe tener 25 caracteres como la variable nombre, por lo que acabamos de llenarla con ceros. En la variable cadena2 dejamos seis espacios al principio, para poder poner la fecha.

.code

start:

invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_DIALOG,NULL,ADDR DlgFunc,NULL
invoke ExitProcess,NULL

DlgFunc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

.if uMsg==WM_INITDIALOG
      mov eax,hDlg
      mov hWnd,eax
      invoke LoadIcon,hInstance,ADDR Icono
      mov hIcon,eax
      invoke SendMessage, hDlg, WM_SETICON,1,hIcon
      invoke SetDlgItemText,hDlg,IDC_NOMBRE,ADDR nomorig

Condiciones de partida: la ventana, el icono y nuestro nombre.

.elseif uMsg==WM_CLOSE
      invoke EndDialog,hDlg,NULL

Si cerramos desde la parte superior derecha, salimos del programa.

.elseif uMsg==WM_COMMAND
      mov eax,wParam
      mov edx,eax
      shr edx,16
      .if dx==BN_CLICKED
         .if ax==IDC_EXIT
            invoke EndDialog,hDlg,NULL
         .elseif ax==IDC_INFO
            invoke MessageBox,hDlg,ADDR txt1,ADDR txt2,MB_ICONINFORMATION
         .elseif ax==IDC_GEN
            invoke GetDlgItemText,hDlg,IDC_NOMBRE,ADDR nombre,26
            invoke GetDlgItemText,hDlg,IDC_NOMBRE,ADDR nomorig,26
            invoke Operacion
            .if eax==1
               invoke MessageBox,hDlg,ADDR error2,ADDR error1,MB_ICONSTOP
            .else
               invoke SetDlgItemText,hDlg,IDC_SERIAL,ADDR serial
               invoke SetDlgItemText,hDlg,IDC_NOMBRE,ADDR nomorig
            .endif
            ret
         .endif
      .endif
.endif

Si le damos a un botón, el programa actúa en consecuencia. Si es el de salir, cierra el programa; si es el de info, muestra una pantalla con la información que hemos definido; y si es el de generar, lee el nombre de la ventana (he utilizado la misma instrucción dos veces para pasar el nombre a dos campos distintos: el campo nombre con el que vamos a trabajar y el campo nomorig que es el que mostrará la ventana del nombre al volver de Operacion) y nos manda a Operacion, que es el núcleo del programa. A la vuelta, si no se ha producido un error, nos muestra el nombre y el serial correspondiente.

ret

DlgFunc endp

Operacion proc

      pushad

Guardamos los registros por si acaso...

      xor eax, eax
      invoke GetLocalTime, Offset campo

La función GetLocalTime nos devuelve en la variable campo, 16 bytes con la siguiente información:

    A  A  M  M  ds ds  D  D  h  h  m  m  s  s  ms ms

Donde el año está en formato de cuatro cifras, ds es el día de la semana empezando por el domingo (0) y ms son milisegundos.

      mov ecx, Offset cadena2
      mov ebx, Offset campo+2
      invoke Subrutina

Vamos a Subrutina para calcular el mes.

      mov ebx, Offset campo+6
      invoke Subrutina

Ahora el día.

      mov ax, word ptr [ecx-2]
      mov edx, Offset dia
      mov word ptr [edx], ax
      mov ebx, Offset campo
      invoke Subrutina

Y finalmente, el año.

      mov ebx, Offset nombre
      invoke lstrlen, offset nombre
      .if eax<5
            popad
            mov eax, 1
            ret
      .endif

Si el nombre tiene menos de cinco caracteres, recuperamos los registros, volvemos y mostramos el mensaje de error, ya que el programa sólo admite nombres de cinco o más caracteres.

      mov edx, eax
      push ebx
completar:
      .if eax<15
            mov cl, byte ptr [ebx]
            mov byte ptr [ebx+edx], cl
            inc eax
            inc ebx
            jmp completar
      .endif

Si el nombre tiene menos de quince caracteres, lo completamos con las primeras letras, hasta llegar a quince.

      pop ebx
      xor eax, eax
      xor ecx, ecx
bucle1:
      mov cl, byte ptr [ebx+eax]
      .if ecx==0
            jmp seguir
      .endif
      .if ecx>96
            .if ecx<123
            sub ecx, 32
            .endif
      .endif
      mov [ebx+eax], cl
      inc eax
      jmp bucle1

Si el nombre contiene letras minúsculas, las pasamos a mayúsculas. Como antes he comentado, esto no vale para la ñ, la ç, ni las vocales acentuadas.
Ahora ya tenemos todas las cosas en su sitio, es el momento de sumarlo todo.

seguir:
      mov esi, Offset cadena1
      mov edi, Offset cadena2
      mov edx, offset dia
      mov ebp, offset abc
      mov eax, offset serial
bucle2:
      push eax
      movzx eax, byte ptr [ebx]
      mov cl, byte ptr [esi]
      .if cl==0
            pop eax
            jmp final
      .endif

Como tanto el serial como cadena1 tienen 15 caracteres, controlando el final de cadena1, sabremos que hemos llegado también al final del serial.

      add eax, ecx
      mov cl, byte ptr [edi]
      add eax, ecx
      mov cl, byte ptr [edx]
      add eax, ecx
      mov cl, byte ptr [edx+1]
      add eax, ecx
      push edx
      xor edx, edx
      mov ecx, 23
      idiv ecx
      mov cl, byte ptr [ebp+edx]
      pop edx
      pop eax
      mov [eax], cl
      inc esi
      inc edi
      inc eax
      inc ebx
      jmp bucle2      

Hemos sumado, hemos dividido, hemos encontrado cada letra y la hemos ido poniendo en su sitio.

final:
      popad

Recuperamos los registros, y estamos de vuelta.

      ret

Operacion endp

Subrutina proc

      movzx eax, word ptr [ebx]
      push ecx
      mov ecx, 10
      xor edx, edx
      idiv ecx
      add dl, 48
      mov byte ptr [ebx+10], dl
      xor edx, edx
      idiv ecx
      add dl, 48
      mov byte ptr [ebx+11], dl

Esta parte se encarga de obtener los códigos ASCII de las dos últimas cifras decimales de la parte de la variable campo2 que nos interesa (correspondientes al mes, día y año respectivamente) y de colocarlas en un lugar de la misma variable, en el que los datos que contiene no nos son de utilidad.

      mov al, byte ptr [ebx+11]
      pop ecx
      mov [ecx], al
      inc ecx
      mov al, byte ptr [ebx+10]
      mov [ecx], al
      inc ecx

Pasamos los códigos obtenidos al lugar correspondiente de cadena2 y regresamos.

      ret

Subrutina endp

end start

Como siempre, quiero recordaros que debéis pagar por los programas que utilicéis regularmente, así cuando llamen a vuestra puerta, podréis abrir con la seguridad de que no vais a encontraros con unos señores vestidos con traje gris, mostrando unas brillantes placas y unas caras muyyyyy serias ;-)

Para terminar, quiero saludar a Act MagO, Pr@fEsOr X, ByTESCRK, DeK_Oin, Karpoff, KuaTo_ThoR y Silver Storm y por supuesto a todos los que habéis llegado hasta aquí.

Si queréis alguna aclaración sobre mis tutos, mi dirección de e-mail es: caos_reptante@hotmail.com

 

Karpoff Spanish Tutor: Pagina dedicada a la divulgacion de informacion en Castellano, sobre Ingenieria Inversa y Programacion. Email "Colabora con tus Proyectos"
www.000webhost.com