Intro
Hoy nos enfrentamos a un crackme realizado en Delphi con un algoritmo bastante sencillo. Está empacado con UPX pero aquí no vamos a explicar como desempacarlo ya que UPX es un reductor de tamaño más que un empacador, incluso con el propio empacador podemos desempacarlo.
Nota: Si queréis ver el proceso completo de desempacado ver el siguiente video (http://youtu.be/c4CNY902SAE).
El algoritmo
Abrimos Olly y vamos a las string references, localizamos los mensajes de error y éxito y pulsamos sobre cualquiera.
Encima de los mensajes tenemos la rutina de comprobación del serial. En la primera imagen vemos que comprueba que no dejemos ningún campo vacío y a continuación se mete de lleno con el serial.
Analicemos la rutina del serial.
00454882 |> /8B15 4C6C4500 /MOV EDX,DWORD PTR DS:[456C4C] ; Concatena name + ECloZion + pronom <--- 00454888 |. |8B0D 506C4500 |MOV ECX,DWORD PTR DS:[456C50] 0045488E |. |0FB6540A FF |MOVZX EDX,BYTE PTR DS:[EDX+ECX-1] ; Coje el dígito que toque 00454893 |. |8916 |MOV DWORD PTR DS:[ESI],EDX ; Mueve EDX a TEMP (inicialmente vale FFFFFFFF) 00454895 |. |833E 5F |CMP DWORD PTR DS:[ESI],5F 00454898 |. |75 06 |JNZ SHORT ECloZion.004548A0 0045489A |. |C706 20000000 |MOV DWORD PTR DS:[ESI],20 004548A0 |> |8B17 |MOV EDX,DWORD PTR DS:[EDI] 004548A2 |. |3116 |XOR DWORD PTR DS:[ESI],EDX ; TEMP = TEMP xor digito 004548A4 |. |8136 CE9A5614 |XOR DWORD PTR DS:[ESI],14569ACE ; TEMP = TEMP xor 14569ACE 004548AA |. |8B16 |MOV EDX,DWORD PTR DS:[ESI] 004548AC |. |8917 |MOV DWORD PTR DS:[EDI],EDX 004548AE |. |FF05 506C4500 |INC DWORD PTR DS:[456C50] 004548B4 |. |48 |DEC EAX ; EAX = longitud del concatenado = contador del bucle. 004548B5 |.^\75 CB \JNZ SHORT ECloZion.00454882 ; Bucle ---> 004548B7 |> 8137 F0BD6434 XOR DWORD PTR DS:[EDI],3464BDF0 ; TEMP 0 TEMP xor 3464BDF0
Ejemplo:
Nom: deurus Prenom: any d e u r u s E C l o Z i o n a n y 64 65 75 72 75 73 45 43 6C 6F 5A 69 6F 6E 61 6E 79 FFFFFFFF xor 64 = FFFFFF9B xor 14569ACE = EBA96555 EBA96555 xor 65 = EBA96530 xor 14569ACE = FFFFFFFE FFFFFFFE xor 75 = FFFFFF8B xor 14569ACE = EBA96545 EBA96545 xor 72 = EBA96537 xor 14569ACE = FFFFFFF9 FFFFFFF9 xor 75 = FFFFFF8C xor 14569ACE = EBA96542 EBA96542 xor 73 = EBA96531 xor 14569ACE = FFFFFFFF FFFFFFFF xor 45 = FFFFFFBA xor 14569ACE = EBA96574 EBA96574 xor 43 = EBA96537 xor 14569ACE = FFFFFFF9 FFFFFFF9 xor 6C = FFFFFF95 xor 14569ACE = EBA9655B EBA9655B xor 6F = EBA96534 xor 14569ACE = FFFFFFFA FFFFFFFA xor 5A = FFFFFFA0 xor 14569ACE = EBA9656E EBA9656E xor 69 = EBA96507 xor 14569ACE = FFFFFFC9 FFFFFFC9 xor 6F = FFFFFFA6 xor 14569ACE = EBA96568 EBA96568 xor 6E = EBA96506 xor 14569ACE = FFFFFFC8 FFFFFFC8 xor 61 = FFFFFFA9 xor 14569ACE = EBA96567 EBA96567 xor 6E = EBA96509 xor 14569ACE = FFFFFFC7 FFFFFFC7 xor 79 = FFFFFFBE xor 14569ACE = EBA96570 -------------------------------------------------- Resultado = EBA96570 EBA96570 xor 3464BDF0 = DFCDD880 = 3754809472 --> nuestra serial
KeyGen en C++
char Nombre[20]; GetWindowText(hwndEdit1, Nombre, 20); char prenom[20]; GetWindowText(hwndEdit2, prenom, 20); char Serial[20]; char concatenado[48]; wsprintf(concatenado,"%sECloZion%s",Nombre,prenom); int len = strlen(concatenado); unsigned int suma = 0xFFFFFFFF; for(int i = 0; i < len; i = i + 1) { suma = suma ^ concatenado[i]; suma = suma ^ 0x14569ACE; } suma = suma ^ 0x3464BDF0; wsprintf(Serial,"%u",suma); SetWindowText(hwndEdit3, TEXT(Serial));