Zoom Icon

Corso UIC Avanzato 04 Pnluck

From UIC Archive

Corso UIC Avanzato 04 Pn

Contents


Corso UIC Avanzato 04 Pnluck
Author: Pn
Email: Email
Website: No Site
Date: 06-7/11/2004 (dd/mm/yyyy)
Level: Working brain required
Language: Italian Flag Italian.gif
Comments:



Introduzione

Qui rispetto agli altri tute, ci è voluto un po' + di tempo, grazie alle cose malefiche inserite dal compilatore borland, per fortuna che c'è IDA. Cmq dividerò il tutez in due parti, la prima che spiego il cracking e l'altra che spiego il reversing.


Tools

  • OllyDbg v1.10
  • IDA 5.0 Demo
  • Un cervello funzionante, un po' di relax e il traduttore pn->italiano e viceversa (domandatelo a bender0).


Notizie sul Programma

Un crackme fatto per trovare una key giusta


Essay

Iniziamo il crackme dicendo che si compone di due parti, la prima in cui dobbiamo ciccare su "Register", e poi una su cui ciccare su "About".

Ora troviamo i punti strategici, per trovare la procedura del pulsante About, basta che troviamo la string del msg di errore.

Cracking

Abbiamo trovato il punto d'attacco che è a 40171A, ok analizziamo:

.text:0040171A push ebp // Inizio procedura .text:0040171B mov ebp, esp .text:0040171D push ebx .text:0040171E mov ebx, [ebp+arg_0] .text:00401721 cmp dword_420140, 0 //cmq una dword con zero .text:00401728 jz short loc_401749 //se non è zero salta al // msg di errore, altrimenti continua .text:0040172A mov eax, [ebx] .text:0040172C push 0 .text:0040172E push offset aTskTskTsk ; "Tsk! tsk! tsk!" .text:00401733 push offset aNonRegistrato ; " Non Registrato " .text:00401738 push dword ptr [eax+0Ch] .text:0040173B push dword ptr [eax+68h] .text:0040173E call sub_40B20A .text:00401743 add esp, 14h .text:00401746 pop ebx .text:00401747 pop ebp .text:00401748 retn .text:00401749 ; --------------------------------------------------------------------------- .text:00401749 .text:00401749 loc_401749:  ; CODE XREF: sub_40171A+Ej .text:00401749 mov eax, [ebx] .text:0040174B push 0 .text:0040174D push offset aPremiOk ; "Premi OK! :-)" .text:00401752 push offset aRegistrato ; " Registrato! " .text:00401757 push dword ptr [eax+0Ch] .text:0040175A push dword ptr [eax+68h] .text:0040175D call sub_40B20A //msg box di complimenti .text:00401762 add esp, 14h .text:00401765 push ebx .text:00401766 call sub_40176F //call strana .text:0040176B pop ecx .text:0040176C pop ebx .text:0040176D pop ebp .text:0040176E retn .text:0040176E sub_40171A endp Ok, cambiamo quel jz in jne, e ci appare prima il msgbox di complimenti e poi uno ke ci avverte della chiave pirata.

Ora intuiamo subito, che quella msg appare da quella chiamata, ok analizziamola, no aspe aspe, sicuramente controlla di nuovo la key(ops non l'abbiamo fatta ancora), quindi vi vado a descrivere direttamente la procedura di "Registred".

Reversing

Per trovare questa procedura è un pochino più semplice, vi ricordate quel je (o jz è la stessa cosa), vi ricordate ke valore controlla, allora per trovare la procedura principale, basta vedere dove viene modificata quella dword, cercandola in olly o ida,risaliamo e ci troviamo a: 40127b.

Ok la procedura è un po' lunga, quindi la descriverà in spezzoni

Prima parte. (Molte volte lascio le info che ci lascia Ida, xkè chi sa cm fungono le api sono più che sufficienti, x gli altri c'è msdn :D )

text:0040127B push ebp //inizio procedura .text:0040127C mov ebp, esp .text:0040127E add esp, 0FFFFFF40h .text:00401284 push ebx .text:00401285 push esi .text:00401286 push edi .text:00401287 lea edi, [ebp+var_7F] .text:0040128A lea esi, [ebp+var_8] .text:0040128D mov eax, offset stru_420230 .text:00401292 call @__InitExceptBlockLDTC //carica la seh .text:00401297 mov [ebp+var_2D], 0 .text:0040129B mov [ebp+var_2E], 0 .text:0040129F mov [ebp+var_1C], 8 .text:004012A5 mov dword ptr [esi], 0FFFFFFFFh .text:004012AB mov dword ptr [esi+4], 1 .text:004012B2 push 180h  ; __int16 .text:004012B7 push 0  ; int .text:004012B9 push offset aTin_key ; path tin.key .text:004012BE push esi  ; int .text:004012BF call sub_4130D4 // c'è un CreateFile(serve x //aprire il file) .text:004012C4 add esp, 10h .text:004012C7 inc [ebp+var_10] .text:004012CA mov [ebp+var_1C], 14h .text:004012D0 push 1  ; len .text:004012D2 push edi  ; buf .text:004012D3 push dword ptr [esi] ; handle .text:004012D5 call __rtl_read //tipo ReadFile .text:004012DA add esp, 0Ch .text:004012DD cmp byte ptr [edi], 0 //se prende il primo char .text:004012E0 / ← jnz short loc_40130B //significa che il file //esiste, e salta, .text:004012E2 | xor eax, eax //altrimenti esce .text:004012E4 | push eax .text:004012E5 | dec [ebp+var_10] .text:004012E8 | cmp dword ptr [esi], 0FFFFFFFFh .text:004012EB | jle short loc_4012FB .text:004012ED | cmp dword ptr [esi+4], 0 .text:004012F1 | jz short loc_4012FB .text:004012F3 | push dword ptr [esi] .text:004012F5 | call j____close //chiude l'handle del file .text:004012FA | pop ecx .text:004012FB | .text:004012FB loc_4012FB:  ; CODE XREF: sub_40127B+70j .text:004012FB |  ; sub_40127B+76j .text:004012FB | pop eax .text:004012FC | mov edx, [ebp+var_2C] .text:004012FF | mov large fs:0, edx .text:00401306 | jmp loc_401422 //jmp alla fine di questa //procedura .text:0040130B ; --------------------------------------------------------------------------- .text:0040130B ↓ (CHE BELLO L'ASCII :) .text:0040130B loc_40130B:  ; CODE XREF: sub_40127B+65j .text:0040130B xor ebx, ebx //xora ebx .text:0040130D jmp short loc_401340 //e inizia una nuova funzione

Qui viene controllata l'esistenza del file "tin.key", leggendo il primo char della key, che quindi, in seguito non verrà letto.

Seconda parte

.text:0040130F loc_40130F:  ; CODE XREF: sub_40127B+CBj .text:0040130F push 1  ; len .text:00401311 push edi  ; buf .text:00401312 push dword ptr [esi] ; handle .text:00401314 call __rtl_read //legge un byte .text:00401319 add esp, 0Ch .text:0040131C movsx eax, bl //ebx fa da contatore .text:0040131F mov dl, [edi] //valore letto in dl .text:00401321 mov [ebp+eax+s], dl //valore salvato in memoria .text:00401328 cmp byte ptr [edi], 0 //compara il valore preso con zero .text:0040132B / ← jnz short loc_401332 //se non è zero salta .text:0040132D | inc [ebp+var_2E] //altrimenti incrementa questo valore .text:00401330 | /←jmp short loc_401336 //e salta .text:00401332 ; ---------|--|------------------------------------------------------------ .text:00401332 | | .text:00401332 loc_401332:| |  ; CODE XREF: sub_40127B+B0j .text:00401332 \→ | mov [ebp+var_2E], 0 //mette in ebp+2e zero .text:00401336 | .text:00401336 loc_401336: |  ; CODE XREF: sub_40127B+B5j .text:00401336 \→ movsx ecx, [ebp+var_2E] //carica in ecx ebp+2e .text:0040133A cmp ecx, 2 //se ecx è maggiore di .text:0040133D jg short loc_401348 //salta .text:0040133F inc ebx //altrimenti incrementa ebx .text:00401340 .text:00401340 loc_401340: (Questa funzione inizia qui)

              ; CODE XREF: sub_40127B+92j

.text:00401340 movsx eax, bl //muove bl in eax .text:00401343 cmp eax, 1Eh //e lo cmp con 0x1E(30d) .text:00401346 jl short loc_40130F //se minore reinizia Vengono letti dal key i char relativi all'user(grande massimo 30 char), ma se trova tre byte "00" esce.

Terza parte

.text:00401348 loc_401348:  ; CODE XREF: sub_40127B+C2j .text:00401348 mov [ebp+var_2E], 0 //muove 0 in ebp+2e .text:0040134C xor ebx, ebx //azzera il contatore .text:0040134E jmp short loc_401381 //inizia l'altra procedura (Altra procedura) .text:00401350 ; --------------------------------------------------------------------------- .text:00401350 .text:00401350 loc_401350:  ; CODE XREF: sub_40127B+10Cj .text:00401350 push 1  ; len .text:00401352 push edi  ; buf .text:00401353 push dword ptr [esi] ; handle .text:00401355 call __rtl_read .text:0040135A add esp, 0Ch .text:0040135D movsx eax, bl .text:00401360 mov dl, [edi] .text:00401362 mov [ebp+eax+var_C0], dl //salva il char appena letto .text:00401369 cmp byte ptr [edi], 0 .text:0040136C / ← ← jnz short loc_401373 .text:0040136E | inc [ebp+var_2E] .text:00401371 | /← jmp short loc_401377 .text:00401373 ; -------|---|--------------------------------------------------------------- .text:00401373 ↓ | .text:00401373 loc_401373: |  ; CODE XREF: sub_40127B+F1j .text:00401373 | mov [ebp+var_2E], 0 .text:00401377 | .text:00401377 loc_401377: |  ; CODE XREF: sub_40127B+F6j .text:00401377 \→ movsx ecx, [ebp+var_2E] .text:0040137B cmp ecx, 2 .text:0040137E jg short loc_401389 .text:00401380 inc ebx .text:00401381 .text:00401381 loc_401381: (inizio procedura)  ; CODE XREF: sub_40127B+D3j .text:00401381 movsx eax, bl .text:00401384 cmp eax, 1Eh .text:00401387 jl short loc_401350 Questa funzione è simile a quella precedente, solo che cambia la zona di salvataggio dei char letti.

Terza parte e mezza

.text:00401389 loc_401389:  ; CODE XREF: sub_40127B+103j .text:00401389 lea edx, [ebp+s] //carica in edx l'user .text:0040138F push edx .text:00401390 call _strlen //conta il num di char .text:00401395 pop ecx .text:00401396 mov edx, eax //edx = num di cifre .text:00401398 xor ebx, ebx //xora ebx .text:0040139A cmp dl, bl //cmp il num di char con 0 .text:0040139C jle short loc_4013C9 //se non è stato letto niente salta

Questa parte di codice conta il numero di cifre dell'user.

Quarta parte

.text:0040139E loc_40139E:  ; CODE XREF: sub_40127B+14Cj .text:0040139E mov eax, ebx //eax = ebx .text:004013A0 inc eax eax++ .text:004013A1 movsx ecx, al ecx = eax .text:004013A4 mov al, [ebp+ecx+s] //al = char dell'user .text:004013AB movsx ecx, bl //ecx = bl .text:004013AE xor al, [ebp+ecx+s] al ^= char dell'user .text:004013B5 movsx ecx, bl ecx = bl .text:004013B8 cmp al, [ebp+ecx+var_C0] //cmp il risultato con un char della psw .text:004013BF /← jnz short loc_4013C4 //se non è uguale salta .text:004013C1 | inc [ebp+var_2D] //incremeta questo // valore(importante!) .text:004013C4 | .text:004013C4 loc_4013C4: |  ; CODE XREF: sub_40127B+144j .text:004013C4 \→ inc ebx //increment ail contatore .text:004013C5 cmp dl, bl //abbiamo finito i char .text:004013C7 jg short loc_40139E //se no reinizia, //altrimenti continua

Qui finalmente possiamo divertirci, infatti qui viene confrontata la psw inserita con quella generata, quel valore var_2d, è molto impostante, il xkè vedete sotto :D. Cmq la psw viene generata in questo modo, vi faccio un esempio con il primo char: es usr[1]^usr[0] = psw[0], cioè viene preso il primo e il secondo char dell'user, xorati e poi confrontato il risultato con il char inserito, poi il secondo e il terzo, e così via. Dovrebbe essere facile :D

Quinta parte(ultima)

.text:004013C9 loc_4013C9:  ; CODE XREF: sub_40127B+121j .text:004013C9 cmp dl, [ebp+var_2D] //verifica se tutti i //char, sia della psw inserita, che quella generata siano uguali .text:004013CC jnz short loc_4013FE //se no salta .text:004013CE xor eax, eax //se la psw è uguale alla psw //generata .text:004013D0 mov dword_420140, eax //viene messo 0 in //questa Dword, ke è quella che verifica se il prg è stato registrato :D .text:004013D5 mov eax, 1 //continuo fino alla chiusura :D .text:004013DA push eax .text:004013DB dec [ebp+var_10] .text:004013DE cmp dword ptr [esi], 0FFFFFFFFh .text:004013E1 jle short loc_4013F1 .text:004013E3 cmp dword ptr [esi+4], 0 .text:004013E7 jz short loc_4013F1 .text:004013E9 push dword ptr [esi] .text:004013EB call j____close .text:004013F0 pop ecx .text:004013F1 .text:004013F1 loc_4013F1:  ; CODE XREF: sub_40127B+166j .text:004013F1  ; sub_40127B+16Cj .text:004013F1 pop eax .text:004013F2 mov edx, [ebp+var_2C] .text:004013F5 mov large fs:0, edx .text:004013FC jmp short loc_401422

Ok abbiamo finito :D, ora vi faccio un keygen semplice semplice in c++. Vamoseeeeeeeeeeeeeeeeee

#include<iostream>
#include<cstdio>
using namespace std;
int main() {
   char user[15];
   char psw[15];
   char zer[] = {0x00,0x00};
   FILE * pFile; //prendo l'user
   printf("Inserisci il tuo nick: ");
   scanf("%s",&user);   //creo il file
   pFile = fopen("tin.key","w+t");
   if(!pFile) 
   {printf("Impossibile creare file"); return 0;}
   //metto il primo char, quello spazzatura 
   fseek(pFile,0,SEEK_SET);
   fwrite("0x01",1,1,pFile);   //inizio a scrivere il nick
   fseek(pFile,1,SEEK_CUR);
   fwrite(user,1,strlen(user),pFile);   //aggiungo gli zeri finali
   fseek(pFile,1,SEEK_CUR);
   fwrite(zer,1,2,pFile);   //calcola la posizione dove inserire la psw
   for(int a=0;a<=strlen(user)-1;a++){
      psw[a] = user[a] ^ user[a+1];
      }  //aggiungo la psw 
   //ho messo strlen(user) xkè la psw deve avere la lunghezza dell'user
  //quindi xkè usare altre cose :D
  fwrite(psw,1,strlen(user),pFile);
  fseek(pFile,1,SEEK_CUR);
  fwrite(zer,1,2,pFile);
  fclose(pFile);
   printf("File tin.key creato");
   return 0;
   }

Ora vediamo se funge,e nooooooooooooooooooooo, ca**o, dice chiave pirata, allora dobbiamo vedere la procedura che viene lanciata "About",ora vi ricordate quella call strana, rivediamola, e sembra tutto uguale tranne qui

.text:00401879 push 1  ; len .text:0040187B lea edx, [ebp-7Fh] .text:0040187E push edx  ; buf .text:0040187F push dword ptr [edi] ; handle .text:00401881 call __rtl_read .text:00401886 add esp, 0Ch .text:00401889 mov al, [ebp+var_7F] //prende il char appena letto .text:0040188C mov dl, [ebp+var_A0] //prende il primo char dell'user .text:00401892 xor dl, [ebp+var_C0] //e lo xora con il primo della psw .text:00401898 cmp dl, al //e cmp il risultato con, il char preso .text:0040189A jz short loc_4018AE //se è uguale salta,altrimenti msgbox di errore

Quindi per far sì che tutto funga, dobbiamo aggiungere alla fine del file, il risultato dello xor tra 1char psw e 1char user. Aggiungete questo codice prima di file close:

char ult[2]; //variabile ult[0] = user[0]^psw[0]; //genero l'ultimo char fwrite(ult,1,1,pFile); //e lo scrivo

Ora dovrebbe fungere tutto, a me funge =D, raga alla prossima :D

Pn =)


Note Finali

Cm non ringraziare que, ged, iron,dr batch, brno, il dj di crack-it, b0,geuzzo, e tutti gli altri.

Poi i miei boss NT e Quake


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 malevole 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.