Zoom Icon

Soluzione Crackme 33

From UIC

Crackme n.33 : Il primo CrackMe scritto da blAAd!

Contents


Infos
Author: ValerioSoft
Email: ValerioSoft(AT)tin.it
Website:
Date: 03/10/2007 (dd/mm/yyyy)
Level: Some skills are required
Language: Italian Image:Flag_Italian.gif
Comments: Chi semina in ottobre sotto la pioggia, raccoglie in giugno sotto il sole. :-D



Introduzione

Ciaoooooooooo, benvenuti al mio decimo tuteeeee!!! :-D


Tools


Notizie sul CrackMe N.33

Regolamento:
Patching solo per Anti_SICE. No Brute Forcing.


Essay

Dato che questo CrackMe risulta essere molto semplice darò molte cose per scontate!!!Premiamo il pulsante Check it in modo tale da far comparire il messaggio No No Try Again. Controlliamo se compare nelle Referenced Text String.

Bene eccolo qui insieme alle congratulazioni:

00401230  CMP     DWORD PTR DS:[ESI],343520D0
00401236  JNZ     SHORT 0040125E
00401238  CMP     DWORD PTR DS:[ESI+4],5E5730C0
0040123F  JNZ     SHORT 0040125E
00401241  CMP     DWORD PTR DS:[ESI+8],58BD5040
00401248  JNZ     SHORT 0040125E

0040124A  PUSH    0                     // Style = MB_OK|MB_APPLMODAL
0040124C  PUSH    00403009              // Title = "tOo MuCh blAAd! #1"
00401251  PUSH    004030F7              // Text = "G r e a t ,  Y o u  W i n  !  ! ----GAME OVER----"
00401256  PUSH    0                     // hOwner = NULL
00401258  CALL    USER32.MessageBoxA    // MessageBoxA
0040125D  RETN
0040125E  PUSH    0                     // Style = MB_OK|MB_APPLMODAL
00401260  PUSH    00403009              // Title = "tOo MuCh blAAd! #1"
00401265  PUSH    00403143              // Text = "No No Try Again!!"
0040126A  PUSH    0                     // hOwner = NULL
0040126C  CALL    USER32.MessageBoxA    // MessageBoxA

A quanto pare per far si che compaia la scritta G r e a t , Y o u W i n  !  ! ----GAME OVER---- occorre superare i tre JNZ senza saltare alla locazione 0040125E. Viene confrontato il contenuto della locazione 00403155 con dei valori fissi, cerchiamo adesso la funzione che acquisisce i caratteri inseriti da tastiera, quindi piazziamo un breakpoint sulla funzione USER32.GetDlgItemTextA. Osserviamo l'indirizzo di memoria che funge da buffer:

004010DC  PUSH    200                              // Count = 200 (512.)
004010E1  PUSH    00403155                         // Buffer = blaadme.00403155
004010E6  PUSH    0BB8                             // ControlID = BB8 (3000.)
004010EB  PUSH    [ARG.1]                          // hWnd
004010EE  CALL    USER32.GetDlgItemTextA           // GetDlgItemTextA

Come si può notare il buffer coincide con l'indirizzo trovato in precedenza, adesso ci basta tenerlo sotto controllo con un breakpoint on memory access.

00401215  XOR     EAX,EAX                          // azzera EAX
00401217  MOV     CL,DS:[EDI+8]                    // mette in CL il 9o byte del codice
0040121A  MOV     EBX,DS:[EDI+EAX*4]               // mette in EBX i primi 4 byte del codice
0040121D  XOR     DS:[ESI+EAX*4],EBX               // xora i primi 4 byte del serial inserito con i primi
                                                   // 4 byte del codice<br />
00401220  ADD     DS:[ESI+EAX*4],CL                // somma al primo byte del serial l'ottavo byte
                                                   // del codice<br />
00401223  AND     WORD PTR DS:[ESI+EAX*4],0F0F0    // fa un AND tra i primi 2 byte del serial e 0F0F0
00401229  INC     EAX                              // incrementa EAX
0040122A  CMP     BYTE PTR DS:[EDI+EAX*4],0        // confronta il quarto byte del codice con 00
0040122E  JNZ     SHORT 0040121A

L'algoritmo che modifica il serial inserito è molto semplice ma non basta infatti osservate l'istruzione 00401217 e 0040121D. Esiste un altro serial (io lo chiamo codice per differenziarlo dal serial inserito). Vediamo di che si tratta, piazziamo un breakpoint on memory access in modo tale da osservare quando ed in che modo viene creato.

004011C1  LEA     EDI,DS:[403356]
004011C7  MOV     ECX,6                     // mette 6 in ECX
004011CC  MOV     BL,DS:[EDI]               // mette in BL il primo byte della locazione 00403356
004011CE  ADD     BL,CL                     // somma 6 con 0 e memorizza il risultato in BL
004011D0  XOR     BL,DS:[EDI]               // xora BL con 0
004011D2  MOV     DS:[EDI],BL               // salva il valore di BL nella locazione 00403356
004011D4  INC     EDI                       // incrementa EDI
004011D5  DEC     ECX                       // decrementa ECX
004011D6  JNZ     SHORT 004011CC
004011D8  MOV     AX,DS:[EDI-6]             // mette in AX i primi 2 byte del codice
004011DC  SUB     AX,0A                     // sottrae 0A ad AX
004011E0  XOR     DS:[EDI],AX               // xora AX con il 7o e l'8o byte del codice
004011E3  MOV     AX,DS:[EDI-4]             // mette in AX il 3o e 4o byte del codice
004011E7  SUB     AX,9                      // sottrae 9 ad AX
004011EB  XOR     DS:[EDI+2],AX             // xora AX con il 9o e 10o byte del codice
004011EF  MOV     AX,DS:[EDI-2]             // mette in AX il 5o ed il 6o byte del codice
004011F3  SUB     AX,5                      // sottrae 5 ad AX
004011F7  XOR     DS:[EDI+4],AX             // xora AX con l'
11o e il 12o byte del codice
004011FB  XOR     EAX,EAX                   // azzera EAX
004011FD  LEA     ESI,DS:[403155]           // mette in ESI la locazione del serial inserito
00401203  LEA     EDI,DS:[403356]           // mette in EDi la locazione del codice
00401209  INC     EAX                       // incrementa EAX
0040120A  CMP     EAX,0D                    // confronta EAX con 13d
0040120D  JE      SHORT 00401215            // salta se sono uguali
0040120F  XOR     DS:[EAX+EDI-1],AL         // xora il primo byte del codice con AL
00401213  JMP     SHORT 00401209

Non è ancora finita, prima di questo pezzo di codice ci sarebbe la lettura del file blaad.xxx, poi questi valori vengono assegnati alla locazione 00403356. I byte assegnati vengono elaborati dall'algoritmo precedente. Nel caso in cui non esiste nessun file da leggere, la locazione 00403356 conterrà solo zeri. L'algoritmo elabora il codice ed alla fine in memoria si ottengono questi valori che vengono utilizzati per l'elaborazione del serial:


00403356 07 07 07 07 - 07 07 FB 0C - F2 08 F6 0C

Facciamo una prova, riavviamo tutto ed inseriamo come serial ValerioSoftX (12 caratteri), nella locazione 00403155 avremo:


00403155 56 61 6C 65 - 72 69 6F 53 - 6F 66 74 58 ValerioSoftX

Ora osserviamo cosa si ottiene tramite il piccolo algoritmo:


56 61 6C 65 xor 72 69 6F 53 xor 6F 66 74 58 xor
07 07 07 07 07 07 FB 0C F2 08 F6 0C
----------------- ----------------- -----------------
51 66 6B 62 + 75 6E 94 5F + 9D 6E 82 54 +
F2 F2 F2
---------------- ----------------- -----------------
43 66 6B 62 and 67 6E 94 5F and 8F 6E 82 54 and
F0 F0 F0 F0 F0 F0
---------------- ----------------- -----------------
40 60 6B 62 60 60 94 5F 80 60 82 54

Dopo l'elaborazione in memoria compare:

00403155 40 60 6B 62 - 60 60 94 5F - 80 60 82 54 @`kb``._.`.T

Come si può intuire:

62 6B 60 40 è diverso da 34 35 20 D0 (primo CMP)
5F 94 60 60 è diverso da 5E 57 30 C0 (secondo CMP)
54 82 60 80 è diverso da 58 BD 50 40 (terzo CMP)

Facendo il discorso a ritroso possiamo individuare il serial corretto:


D0 20 35 34 and C0 30 57 5E and 40 50 BD 58 and
F0 F0 F0 F0 F0 F0
----------------- ----------------- -----------------
D0 20 35 34 - C0 30 57 5E - 40 50 BD 58 -
F2 F2 F2
---------------- ----------------- -----------------
DE 20 35 34 xor CE 30 57 5E xor 4E 50 BD 58 xor
07 07 07 07 07 07 FB 0C F2 08 F6 0C
---------------- ----------------- -----------------
D9 27 32 33 C9 37 AC 52 BC 58 4B 54

Questo è il serial esatto nel caso in cui non utilizziamo il file blaad.xxx:

00403155 D9 27 32 33 C9 37 AC 52 BC 58 4B 54 Ù'23É7.R¼XKT

Questo serial ha l'inconveniente di essere difficile da ricordare e da scrivere, quindi vorrei continuare l'analisi del codice in modo tale da poter inserire nel keyfile Valerio-Soft (dato che occorrono 12 byte). Dopo la lettura del keyfile Valerio-Soft comparirà in memoria alla locazione 00403356 per poi essere elaborato.


00403356 56 61 6C 65 72 69 6F 2D 53 6F 66 74 Valerio-Soft

Guardiamo la prima elaborazione:

004011C1  LEA     EDI,DS:[403356]
004011C7  MOV     ECX,6                     // mette 6 in ECX
004011CC  MOV     BL,DS:[EDI]               // mette in BL il primo byte della locazione 00403356
004011CE  ADD     BL,CL                     // somma 6 con 0 e memorizza il risultato in BL
004011D0  XOR     BL,DS:[EDI]               // xora BL con 0
004011D2  MOV     DS:[EDI],BL               // salva il valore di BL nella locazione 00403356
004011D4  INC     EDI                       // incrementa EDI
004011D5  DEC     ECX                       // decrementa ECX
004011D6  JNZ     SHORT 004011CC

;( valore 1 + 6h ) xor ( valore 1 ) = memorizza in pos 1  =>(56h + 6h) xor ;(56h) = 0Ah
;( valore 2 + 5h ) xor ( valore 2 ) = memorizza in pos 2
;( valore 3 + 4h ) xor ( valore 3 ) = memorizza in pos 3
;( valore 4 + 3h ) xor ( valore 4 ) = memorizza in pos 4
;( valore 5 + 2h ) xor ( valore 5 ) = memorizza in pos 5
;( valore 6 + 1h ) xor ( valore 6 ) = memorizza in pos 6

;alla fine in memoria avremo:

;00403356  0A 07 1C 0D 06 03 6F 2D 53 6F 66 74              ......o-Soft

Guardiamo la secconda elaborazione:


004011D8 MOV AX,DS:[EDI-6] // mette in AX i primi 2 byte del codice
004011DC SUB AX,0A // sottrae 0A ad AX
004011E0 XOR DS:[EDI],AX // xora AX con il 7o e l'8o byte del codice
004011E3 MOV AX,DS:[EDI-4] // mette in AX il 3o e 4o byte del codice
004011E7 SUB AX,9 // sottrae 9 ad AX
004011EB XOR DS:[EDI+2],AX // xora AX con il 9o e 10o byte del codice
004011EF MOV AX,DS:[EDI-2] // mette in AX il 5o ed il 6o byte del codice
004011F3 SUB AX,5 // sottrae 5 ad AX
004011F7 XOR DS:[EDI+4],AX // xora AX con l'11o e il 12o byte del codice



(secondo-primo valore) - (quarto-terzo valore) - (sesto-quinto valore) -
0A 9 5
------------------------ ----------------------- -----------------------
risultato xor risultato xor risultato xor
(ottavo-settimo valore) (decimo-nono valore) (dodicesimo-undicesimo valore)

alla fine in memoria avremo:

00403356 0A 07 1C 0D 06 03 6F 2A 40 62 67 77 ......o*@bgw

Guardiamo la terza elaborazione:


00401209 INC EAX // incrementa EAX
0040120A CMP EAX,0D // confronta EAX con 13d
0040120D JE SHORT 00401215 // salta se sono uguali
0040120F XOR DS:[EAX+EDI-1],AL // xora il primo byte del codice con AL
00401213 JMP SHORT 00401209

valore 1 xor 1 = risultato in prima posizione
valore 2 xor 2 = risultato in seconda posizione

e così via fino alla dodicesima, alla fine in memoria avremo:

00403356 0B 05 1F 09 03 05 68 22 49 68 6C 7B ......h"Ihl{

Abbiamo ottenuto il keyfile elaborato, adesso però per risalire al serial tocca a noi elaborarlo con il metodo già utilizzato in precedenza:


D0 20 35 34 and C0 30 57 5E and 40 50 BD 58 and
F0 F0 F0 F0 F0 F0
----------------- ----------------- -----------------
D0 20 35 34 - C0 30 57 5E - 40 50 BD 58 -
49 49 49
---------------- ----------------- -----------------
87 20 35 34 xor 77 30 57 5E xor F7 50 BD 58 xor
0B 05 1F 09 03 05 68 22 49 68 6C 7B
---------------- ----------------- -----------------
8C 25 2A 3D 74 35 3F 7C BE 38 D1 23

Ora riproviamo con il nuovo serial:


00403155 8C 25 2A 3D 74 35 3F 7C BE 38 D1 23 Œ%*=t5?|¾8Ñ#


Ecco che compare la scritta G r e a t , Y o u W i n  !  ! ----GAME OVER----


Il KeyGen

Ecco il keygen il linguaggio C:

#include <stdio.h>
#include <string.h>      

#define DIM 24

// converte un'array di interi in esadecimale
void esadecimale(int nome[]);

// visualizza il numero convertito nella base scelta
void visualizza();  

// vettore per memorizzare le cifre del numero convertito
int vet[DIM];

int risultato;
int AL,AH;


int main()
{
    // vettore che contiene il nome inserito dall'utente
    char nomeC[12];
   
    // vettore di interi per il nome inserito dall'utente
    int nome[12];
   
    // Codice da ottenere per le congratulazioni
    int mappa[12] = {0xD0,0x20,0x35,0x34,0xC0,0x30,0x57,0x5E,0x40,0x50,0xBD,0x58};
                                                                 
    unsigned int i;
    int valore1,valore2;
    int primo,secondo;
   
        printf("\n\n\n                 Keygen CrackMe N.34 coded by ValerioSoft\n\n");
        printf("--------------------------------------------------------------------------\n");
        printf("ATTENZIONE: Inserisci il codice del keyfile!!!\n");
        printf("ATTENZIONE: Il sistema crea il keyfile con il nome inserito e ci mostra\n");
        printf("            il Serial da inserire nel box di registrazione!!!\n");
        printf("--------------------------------------------------------------------------\n\n");
        printf("Inserisci un codice di 12 caratteri: ");
        scanf("%s", nomeC);
       
    while (strlen(nomeC) != 12) {            
          printf("\nAttenzione il nome inserito non rispetta la lunghezza attesa!\n\n");
          printf("Inserisci un nome: ");
          scanf("%s", nome);
    }
   
    // Creo il keyfile con il nome inserito
    FILE *handle = fopen("blaad.xxx","w");
        fprintf(handle,"%s",nomeC);
    fclose(handle);
   
   
    // passo i caratteri del nome in un array di interi
    for(i=0; i<12; i++) {
            nome[i] = nomeC[i];
    }
     
    // Prima elaborazione
    for(i=0; i<6; i++) {
            nome[i] = (nome[i] + (6 - i)) ^ nome[i];
    }


    // Seconda elaborazione
    primo = nome[1] * 0x100;
    valore1 = nome[0] + primo;
    valore1 -= 0x0A;

    secondo = nome[7] * 0x100;
    valore2 = nome[6] + secondo;
    risultato = valore1 ^ valore2;
   
    __asm("mov _risultato,%ax");
   
    __asm("mov %al,_AL");
    __asm("mov %ah,_AH");
   
    nome[6] = AL;
    nome[7] = AH;

    primo = nome[3] * 0x100;
    valore1 = nome[2] + primo;
    valore1 -= 0x09;

    secondo = nome[9] * 0x100;
    valore2 = nome[8] + secondo;
    risultato = valore1 ^ valore2;
   
    __asm("mov _risultato,%ax");
   
    __asm("mov %al,_AL");
    __asm("mov %ah,_AH");
   
    nome[8] = AL;
    nome[9] = AH;

    primo = nome[5] * 0x100;
    valore1 = nome[4] + primo;
    valore1 -= 0x05;

    secondo = nome[11] * 0x100;
    valore2 = nome[10] + secondo;
    risultato = valore1 ^ valore2;
   
    __asm("mov _risultato,%ax");
   
    __asm("mov %al,_AL");
    __asm("mov %ah,_AH");
   
    nome[10] = AL;
    nome[11] = AH;

    // Terza elaborazione
    for(i=0; i<12; i++) {
            nome[i] = nome[i] ^ i+1;
    }
   
    printf("\n\nCodice del keyfile elaborato: ");
    esadecimale(nome);
    visualizza();

    printf("\n\n      Codice congratulazioni: ");
    esadecimale(mappa);
    visualizza();
   
    risultato = mappa[0] - nome[8];
    __asm("mov _risultato,%al");
    __asm("mov %al,_AL");
    mappa[0] = AL;
   
    risultato = mappa[4] - nome[8];
    __asm("mov _risultato,%al");
    __asm("mov %al,_AL");
    mappa[4] = AL;
   
    risultato = mappa[8] - nome[8];
    __asm("mov _risultato,%al");
    __asm("mov %al,_AL");
    mappa[8] = AL;
       
    // Ultima elaborazione
    for(i=0; i<12; i++) {
            mappa[i] = nome[i] ^ mappa[i];
    }

    printf("\n\n                     Serial: ");
    esadecimale(mappa);
    visualizza();
   
        // attende un carattere qualsiasi in ingresso
        scanf("%s", nome);

        return 0;
}

// converte un'array di interi in esadecimale
void esadecimale(int nome[]) {
     
     int i,j=0,temp;
     for (i = 0;i<12; i++) {    
         temp = nome[i];
         // resto della divisione
         vet[j+1] = temp % 16;
         // quoziente della divisione
         temp = temp / 16;     
         vet[j] = temp;
         j += 2;
     } 
}

/* Funzione che visualizza il contenuto del vettore 'vet'
 */

void visualizza() {
     
int j; // contatore
       
     for(j=0;j<DIM;j++) {
         // visualizzazione dei valori esadecimali
         if (vet[j]>=10) {
            printf("%c",vet[j]+ 'A' - 10);
         }     
         else printf("%c",vet[j]+'0');
         
         if (j % 2 == 1) {printf(" ");}                
     }                        
  // visualizza anche gli zeri a sinistra del numero convertito
  printf("\n\n");
}

Per accertarmi del suo funzionamento ho inserito come codice del keyfile --quequero-- ed il risultato esadecimale del serial è stato 4F 3D 32 3D 47 35 31 2C 40 39 66 7B ovvero O=2=G51,@9f{ che ci permette di ottenere le congratulazioni!!!


Note Finali

Un saluto caloroso a va a tutta la UIC!!!
Ciaoooooooooooooooooo alla proximaaaaaaaaa

ValerioSoft


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.