Introducción
Esta vez vamos a analizar los CrackMes de un antiguo colaborador de Karpoff Spanish Tutor, CrkViZ. En estas cinco soluciones vamos a pelearnos con Visual Basic 5/6 nativo y Pcode, con el registro de Windows y tendremos que parchear algúna rutina antidebug. Los CrackMes son del año 2000 y aunque algunos estaban ya solucionados, los analizaremos igualmente para ver la diferencia que existe con los análisis realizados en aquellos años, sí, estamos hablando del Softice.
Herramientas disponibles
Cuando hablamos de Visual Basic 5/6, podemos destacar 3 herramientas que nos facilitan mucho la vida, VB Decompiler, VB Reformer y ExDec. Las dos primeras se defienden bien tanto con código nativo como pcode y ExDec solamente nos sirve para pcode. Aún así, si todo lo demás falla, Ollydbg nos sacará de apuros.
CrkViz-1


Este primer crackme está compilado en Pcode y hoy día, con las herramientas de que disponemos no supone ninguna dificultad. Tan solo debemos abrirlo con VB Decompiler y ya nos encontramos con el serial válido.

Los opcodes obtenidos con ExDec se ven de la siguiente manera.
......
402F14: 04 FLdRfVar local_008C
402F17: 21 FLdPrThis
402F18: 0f VCallAd 7b3fc340
402F1B: 19 FStAdFunc local_0088
402F1E: 08 FLdPr local_0088
402F21: 0d VCallHresult 7b3fbe88
402F26: 6c ILdRf local_008C
402F29: 1b LitStr: 57230198 <--------------
402F2C: Lead0/30 EqStr
402F2E: 2f FFree1Str local_008C
402F31: 1a FFree1Ad local_0088
402F34: 1c BranchF: 403012
402F37: 21 FLdPrThis
402F38: 0d VCallHresult 7b3fc2b0
402F3D: 3a LitVarStr: ( local_00AC ) Gracias por Registrar!!
402F42: Lead2/00 FStVarCopy
402F46: 27 LitVar_Missing
402F49: 27 LitVar_Missing
402F4C: 3a LitVarStr: ( local_00AC ) CrkViz
402F51: 4e FStVarCopyObj local_00BC
402F54: 04 FLdRfVar local_00BC
402F57: f5 LitI4: 0x40 64 (...@)
402F5C: 04 FLdRfVar local_009C
402F5F: 0a ImpAdCallFPR4: _rtcMsgBox
402F64: 36 FFreeVar
402F6D: 27 LitVar_Missing
402F70: 25 PopAdLdVar
402F71: 27 LitVar_Missing
......
CrkViz-2

Este segundo crackme también está compilado en pcode. La rutina del serial es muy sencilla pero al introducir un número aleatorio nos obliga a parchear. Cargamos el crackme en VB Decompiler y nos muestra esto:

Básicamente vemos que genera un número aleatorio entre 1 y 999999999 y luego le suma 1. La forma de afrontar esto es parcheando. Nos fijamos en el offset aproximado (4037F2) y abrimos el crackme en un editor hexadecimal. La forma de convertir el offset que nos muestra VB Decompiler a lo que nos muestra un editor hexadecimal es la siguiente.
VBdec_offset - Image Base - VirtualOffset + RawOffset = Offset_Editor.H
4037F2 - 400000 - 1000 + 400 = 2BF2

Una vez localizados los bytes, los cambiamos por ceros y guardamos.

Una vez parcheado, el serial correcto es 1.
CrkViz-3

En esta tercera entrega, CrkViz aumentó la dificultad. El crackme está compilado en código nativo y nos enfrentamos a un serial asociado a un nombre y a una rutina antidebug que en realidad es una Nag, ya que se muestra siempre.
Afrontar la nag es muy sencillo, basta con localizarla y parchear la llamada.
CPU Disasm
Address Hex dump Command Comments
004058E2 8D4D DC LEA ECX,[EBP-24]
004058E5 C785 BCFDFFFF B MOV DWORD PTR SS:[EBP-244],CrkMeViz-3.004033B8 ; UNICODE " Debugger detectado!!! "
004058EF C785 B4FDFFFF 0 MOV DWORD PTR SS:[EBP-24C],8
004058F9 FFD7 CALL EDI
004058FB B9 04000280 MOV ECX,80020004
00405900 B8 0A000000 MOV EAX,0A
00405905 898D FCFDFFFF MOV DWORD PTR SS:[EBP-204],ECX
0040590B 898D 0CFEFFFF MOV DWORD PTR SS:[EBP-1F4],ECX
00405911 8D95 B4FDFFFF LEA EDX,[EBP-24C]
00405917 8D8D 14FEFFFF LEA ECX,[EBP-1EC]
0040591D 8985 F4FDFFFF MOV DWORD PTR SS:[EBP-20C],EAX
00405923 8985 04FEFFFF MOV DWORD PTR SS:[EBP-1FC],EAX
00405929 C785 BCFDFFFF 8 MOV DWORD PTR SS:[EBP-244],CrkMeViz-3.00403188 ; UNICODE "Error"
00405933 C785 B4FDFFFF 0 MOV DWORD PTR SS:[EBP-24C],8
0040593D FF15 C8914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarDup>]
00405943 8D85 F4FDFFFF LEA EAX,[EBP-20C]
00405949 8D8D 04FEFFFF LEA ECX,[EBP-1FC]
0040594F 50 PUSH EAX
00405950 8D95 14FEFFFF LEA EDX,[EBP-1EC]
00405956 51 PUSH ECX
00405957 52 PUSH EDX
00405958 8D45 DC LEA EAX,[EBP-24]
0040595B 6A 10 PUSH 10
0040595D 50 PUSH EAX
0040595E FF15 50914000 CALL DWORD PTR DS:[<&MSVBVM50.#595>] ; rtcMsgBox - NOPear para evitar la NAG
00405964 8D8D F4FDFFFF LEA ECX,[EBP-20C]
Antes de llegar al keygen vemos que realiza unas llamadas al registro de Windows, ponemos un breakpoint «bp RegOpenKeyW» y ejecutamos.
CPU Disasm
Address Hex dump Command Comments
00405677 |. 8B8D B8FDFFFF MOV ECX,DWORD PTR SS:[EBP-248]
0040567D |. B8 54334000 MOV EAX,CrkMeViz-3.00403354 ; UNICODE "<Unregister>"
00405682 |. 68 B4304000 PUSH CrkMeViz-3.004030B4 ; UNICODE "Serial number"
00405687 |. 894A 04 MOV DWORD PTR DS:[EDX+4],ECX
0040568A |. 8985 BCFDFFFF MOV DWORD PTR SS:[EBP-244],EAX
00405690 |. 68 84304000 PUSH CrkMeViz-3.00403084 ; UNICODE "Register"
00405695 |. 68 58304000 PUSH CrkMeViz-3.00403058 ; UNICODE "CrkMeViz3"
0040569A |. 8942 08 MOV DWORD PTR DS:[EDX+8],EAX
0040569D |. 8B85 C0FDFFFF MOV EAX,DWORD PTR SS:[EBP-240]
004056A3 |. 8942 0C MOV DWORD PTR DS:[EDX+0C],EAX
004056A6 |. FF15 C0914000 CALL DWORD PTR DS:[<&MSVBVM50.#689>] ; rtcGetSetting - Lee el numero de serie del registro
........
0040574F |. 68 9C304000 PUSH CrkMeViz-3.0040309C ; UNICODE "User Name"
00405754 |. 68 84304000 PUSH CrkMeViz-3.00403084 ; UNICODE "Register"
00405759 |. 68 58304000 PUSH CrkMeViz-3.00403058 ; UNICODE "CrkMeViz3"
0040575E |. 8948 08 MOV DWORD PTR DS:[EAX+8],ECX
00405761 |. 8B8D C0FDFFFF MOV ECX,DWORD PTR SS:[EBP-240]
00405767 |. 8948 0C MOV DWORD PTR DS:[EAX+0C],ECX
0040576A |. FF15 C0914000 CALL DWORD PTR DS:[<&MSVBVM50.#689>] ; rtcGetSetting - Lee el Usuario del registro
Reconstruyendo la llamada al registro vemos que lee de esta ruta: HKEY_CURRENT_USER\Software\VB and VBA Program Settings\CrkMeViz3\Register el contenido de User Name y del Serial number.
Quizá uno de los fallos de éste crackme, es que no comprueba la autenticidad de estos parámetros y si los modificas parece que estás registrado. Un ejemplo:

La rutina de comprobación del serial no es para nada complicada pero recordemos que estamos tratando con VB y éste delega el trabajo duro en otras librerias de modo que tenemos que «meternos» a tracear las llamadas para ver los valores que multiplica y divide.
CPU Disasm
Address Hex dump Command Comments
00405A86 FF15 3C914000 CALL DWORD PTR DS:[<&MSVBVM50.#518>] ;MSVBVM50.rtcLowerCaseVar
00405A8C 8D95 14FEFFFF LEA EDX,[EBP-1EC]
00405A92 8D8D ACFEFFFF LEA ECX,[EBP-154]
00405A98 FFD6 CALL ESI
00405A9A 8D95 ACFEFFFF LEA EDX,[EBP-154]
00405AA0 8D8D 4CFEFFFF LEA ECX,[EBP-1B4]
00405AA6 FFD7 CALL EDI
00405AA8 8D95 4CFEFFFF LEA EDX,[EBP-1B4]
00405AAE 8D8D 7CFFFFFF LEA ECX,[EBP-84]
00405AB4 FFD7 CALL EDI
00405AB6 8D85 14FEFFFF LEA EAX,[EBP-1EC]
00405ABC 8D8D 7CFFFFFF LEA ECX,[EBP-84]
00405AC2 50 PUSH EAX
00405AC3 6A 01 PUSH 1
00405AC5 8D95 04FEFFFF LEA EDX,[EBP-1FC]
00405ACB 51 PUSH ECX
00405ACC 52 PUSH EDX
00405ACD C785 1CFEFFFF 0 MOV DWORD PTR SS:[EBP-1E4],1
00405AD7 C785 14FEFFFF 0 MOV DWORD PTR SS:[EBP-1EC],2
00405AE1 FF15 68914000 CALL DWORD PTR DS:[<&MSVBVM50.#632>] ;MSVBVM50.rtcMidCharVar (Esto lo hace 6 veces, lo omito para abreviar.)
........
00405CE1 FF15 34914000 CALL DWORD PTR DS:[<&MSVBVM50.#516>] ;MSVBVM50.rtcAnsiValueBstr (Lo mismo, otras 6)
........
00405E7C C785 BCFDFFFF 2 MOV DWORD PTR SS:[EBP-244],52E
00405E86 C785 B4FDFFFF 0 MOV DWORD PTR SS:[EBP-24C],2
00405E90 50 PUSH EAX
00405E91 FF15 84914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
|
->MSVBVM50.__vbaVarMul
........
741C19D3 0FB745 FE MOVZX EAX,WORD PTR SS:[EBP-2] ;Valor1
741C19D7 0FB74D F2 MOVZX ECX,WORD PTR SS:[EBP-0E] ;Valor2
741C19DB 6BC0 12 IMUL EAX,EAX,12 ;Valor1*Valor2
........
00405E97 8D8D 04FEFFFF LEA ECX,[EBP-1FC]
00405E9D 50 PUSH EAX
00405E9E 51 PUSH ECX
00405E9F FF15 84914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00405EA5 8D95 F4FDFFFF LEA EDX,[EBP-20C]
00405EAB 50 PUSH EAX
00405EAC 52 PUSH EDX
00405EAD FF15 84914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00405EB3 50 PUSH EAX
00405EB4 8D85 E4FDFFFF LEA EAX,[EBP-21C]
00405EBA 50 PUSH EAX
00405EBB FF15 84914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00405EC1 8D8D D4FDFFFF LEA ECX,[EBP-22C]
00405EC7 50 PUSH EAX
00405EC8 51 PUSH ECX
00405EC9 FF15 84914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00405ECF 50 PUSH EAX
00405ED0 8D95 B4FDFFFF LEA EDX,[EBP-24C]
00405ED6 8D85 C4FDFFFF LEA EAX,[EBP-23C]
00405EDC 52 PUSH EDX
00405EDD 50 PUSH EAX
00405EDE FF15 94914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarDiv>]
|
->MSVBVM50.__vbaVarDiv
........
741C8094 DD43 08 FLD QWORD PTR DS:[EBX+8] ;Recupera el resultado de las multiplicaciones anteriores
741C8097 0FBF47 08 MOVSX EAX,WORD PTR DS:[EDI+8] ;EAX = 1326 (52E)
741C809B 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
741C809E DA75 F8 FIDIV DWORD PTR SS:[EBP-8] ;Divide los dos resultados
741C80A1 DD5E 08 FSTP QWORD PTR DS:[ESI+8]
........
00405F44 FF15 24914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaLenBstr>] ;Len(nombre)
........
00405F85 FF15 94914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarDiv>] ;Resultado anterior / Len(nombre)
........
En resumen:
- Pasa nuestro nombre a minúsculas.
- Obtiene el valor ascii de los 6 primeros dígitos del nombre.
- Los multiplica entre sí y divide el resultado acumulado entre 1326 (52E).
- Divide el resultado anterior entre el tamaño del nombre.
Ejemplo para deurus
64*65*75*72*75*73 = 1A605D70EB8
1A605D70EB8 / 52E = 5179FBF4
5179FBF4 / 6 = D9454A9

Al estar correctamente registrados desaparece el botón de registrar.
CrkViz-4

El cuarto crackme es prácticamente igual que el tercero salvo que en vez de nag ahora contamos con limitación de ejecuciones. Del mismo modo utiliza el registro de Windows para guardar los datos de registro y las ejecuciones que llevamos.
Ponemos un breakpoint «bp RegOpenKeyW» y llegamos a la conclusión de que la ruta es HKEY_CURRENT_USER\Software\VB and VBA Program Settings\ODBC\Register y los valores se guardan en Counter, User Name y Serial number respectivamente. Este crackme hereda el fallo del anterior y si alteramos los valores el crackme nos muestra como usuarios autorizados, aunque sabemos que no estamos registrados ya que seguimos limitados por ejecuciones. Ni que decir tiene que lo mismo que modificamos el nombre y número de serie, podemos modificar el contador a nuestro favor. Crear un archivo «Reiniciar_contador.reg» con el siguiente contenido sería suficiente.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\VB and VBA Program Settings\ODBC]
[HKEY_CURRENT_USER\Software\VB and VBA Program Settings\ODBC\Register]
"Counter"="0"
"User Name"="deurus"
"Serial number"="12345"
El keygen es prácticamente igual que en el crackme anterior, solo cambia el divisor.
CPU Disasm
Address Hex dump Command Comments
........
00404BD2 C785 BCFDFFFF C MOV DWORD PTR SS:[EBP-244],6C1
00404BDC C785 B4FDFFFF 0 MOV DWORD PTR SS:[EBP-24C],2
00404BE6 FF15 A0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
|
->MSVBVM50.__vbaVarMul
741C19F9 0FBF4F 08 MOVSX ECX,WORD PTR DS:[EDI+8] ;Valor1
741C19FD 0FBF43 08 MOVSX EAX,WORD PTR DS:[EBX+8] ;Valor2
741C1A01 0FAFC8 IMUL ECX,EAX ;Valor1*Valor2
........
00404BEC 8D8D 04FEFFFF LEA ECX,[EBP-1FC]
00404BF2 50 PUSH EAX
00404BF3 51 PUSH ECX
00404BF4 FF15 A0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00404BFA 8D95 F4FDFFFF LEA EDX,[EBP-20C]
00404C00 50 PUSH EAX
00404C01 52 PUSH EDX
00404C02 FF15 A0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00404C08 50 PUSH EAX
00404C09 8D85 E4FDFFFF LEA EAX,[EBP-21C]
00404C0F 50 PUSH EAX
00404C10 FF15 A0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00404C16 8D8D D4FDFFFF LEA ECX,[EBP-22C]
00404C1C 50 PUSH EAX
00404C1D 51 PUSH ECX
00404C1E FF15 A0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarMul>]
00404C24 50 PUSH EAX
00404C25 8D95 B4FDFFFF LEA EDX,[EBP-24C]
00404C2B 8D85 C4FDFFFF LEA EAX,[EBP-23C]
00404C31 52 PUSH EDX
00404C32 50 PUSH EAX
00404C33 FF15 B0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarDiv>]
|
->MSVBVM50.__vbaVarDiv
741C8094 DD43 08 FLD QWORD PTR DS:[EBX+8] ; Recupera el resultado de las multiplicaciones anteriores
741C8097 0FBF47 08 MOVSX EAX,WORD PTR DS:[EDI+8] ; EAX = 1729 (6C1)
741C809B 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
741C809E DA75 F8 FIDIV DWORD PTR SS:[EBP-8]
00404C39 8BD0 MOV EDX,EAX
........
00404CA0 FF15 3C914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaLenBstr>] ;Len(nombre)
........
00404CF1 FF15 B0914000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVarDiv>] ;Resultado anterior / Len(nombre)
En resumen:
- Pasa nuestro nombre a minúsculas.
- Obtiene el valor ascii de los 6 primeros dígitos del nombre.
- Los multiplica entre sí y divide el resultado acumulado entre 1729 (6C1).
- Divide el resultado anterior entre el tamaño del nombre.
Ejemplo para deurus
64*65*75*72*75*73 = 1A605D70EB8
1A605D70EB8 / 6C1 = 3E7C594A
3E7C594A / 6 = A6A0EE2
CrkViz-5

Este último crackme está compilado en código nativo y simplemente se trata de una comparación lineal. La única diferencia reside en que no hay botón de registro, la comprobación la gestiona un evento «On Change«, de modo que está comprobando el tamaño del serial que introducimos y cuando éste tiene 8 dígitos llegamos aquí.
........
0040A64F . C745 9C CDD4DD02 MOV DWORD PTR SS:[EBP-64],2DDD4CD ;2DDD4CD = 48092365
0040A656 . C745 94 03800000 MOV DWORD PTR SS:[EBP-6C],8003
0040A65D . FF15 08C14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaVa> ;MSVBVM50.__vbaVarTstEq
0040A663 . 66:85C0 TEST AX,AX
0040A666 . 0F84 BA000000 JE CrkMeViZ.0040A726 ;Si salta BAD BOY
........
Luego el serial correcto es 48092365.
Notas finales
¿Ha sido indoloro no?, claro que sí, Visual Basic es un coñazo de tracear pero hay que reconocer que con el tiempo las herramientas han mejorado mucho y nuestra vida es mucho más sencilla. Bueno, pués esto ha sido todo, como siempre os dejo todo el material utilizado y un Keygen.

Enlaces