integrato ;)
EffeTech HTTP sniffer reverse engineering 3°parte
Analisi di algoritmi, keygenning e cracking

Terminata finalmente l'analisi rifacciamo il punto della situazione.
Il nome che si introduce nella form di registrazione non viene minimamente preso in considerazione nel controllo della validità della licenza del programma, così come non vengono presi in considerazione i caratteri serial[16] e serial[17] (lo si vede nel calcolo degli 8 resti). Si deduce quindi che qualsiasi valore introdurremo in queste posizioni la nostra licenze sarà comunque validata.
Un'altra cosa poco sensata di questo programma studiato è che, come si vede al momento della richiesta del codice di registrazione, esistono due tipi di licenze, commerciale e non commerciale. Il punto è che qualsiasi seriale valido introduceremo, sia che EBP alla fine sia == 0x2BA5 o a 0x3A30 andremo sempre a registrare una licenza di tipo "Non-Commercial"!
Sarebbe interessante studiare anche questa parte per vedere come viene differenziata una licenza commerciale da una no, sempre ammesso che questa distinzione esista realmente (in quanto il programma non ha nessuna differenza di funzionamento se registrato tramite licenza commerciale o meno).
In ogni caso abbiamo di fronte problemi più grandi ora, realizzare un keygen che generi seriali validabili da questo algoritmo, e la cosa è tutt'altro che semplice.

 
Software reversing 6 passo: Keygenning
 
Dopo ormai parecchie ore di lavoro spese a reversare centinaia di righe di codice uno si aspetta, o almeno spera, che la parte peggiore del lavoro sia finita, purtroppo in questo caso invece ci aggorgeremo presto che sta per iniziare!
Non siamo difronte al solito sistemino da quattro soldi che scambia qualche lettera, somma/sottrae/divide/moltiplica per qualche costante e valida quindi il codice, qui qui il procedimento per la validazione varia di volta in volta in base ai caratteri introdotti! (abbiamo infatti ben 7 rotuine diverse che collaborano alla validazione del seriale e a decidere quale di queste routine verrà eseguita ad ogni ciclo sono dei resti calcolati appunto sulla base dei nostri caratteri).
Il keygenning quindi in questo caso è tutt'altro che banale e come vedremo adesso il fatto che a scegliere quale delle 7 funzioni verrà eseguita siano delle operazioni di resto complica ulteriormente le cose.
Come appurato quindi in questo caso non è possibile semplicemente invertire l'ordine delle operazioni eseguite sui caratteri per creare un seriale valido e non è neanche possibile eseguire un trace del procedimento di validazione perchè come sappiamo questo algoritmo varia di volta in volta. Cosa fare allora?
Fortunatamente osservando la seconda parte dell'algoritmo si nota che nel ciclo di elaborazione degli 8 resti non viene più preso in considerazione nessun carattere, e questo gioca a nostro favore!
Possiamo fissare a priori 8 resti a nostra discrezione (ovviamente che verifichino la seconda parte dell'algoritmo) ed in base a questi calcolarci solo di volta in volta i dei caratteri che li generino (e quindi che verifichino tutto l'algoritmo) mettendo a sistema le 8 equazioni, ma purtroppo non sarà cosi semplice come sembra.
Per questo procedimento fissiamo quindi 8 valori i quali, terminate le operazioni con le 7 funzioni, generino un EBP uguale a 0x2BA5 o a 0x3A30, Utilizziamo:
  1. resto[0] = 124;
  2. resto[1] = 187;
  3. resto[2] = 125;
  4. resto[3] = 89;
  5. resto[4] = 132;
  6. resto[5] = 200;
  7. resto[6] = 125;
  8. resto[7] = 86;
(Si verifica facilmente eseguendo il ciclo di check con questi resti che EBP risulterà uguale a 0x3A30)
A questo punto sapendo la relazione che lega i caratteri che cerchiamo con i resti scelti procediamo a ritroso per calcolare questi caratteri. Abbiamo il sistema composta da:

124 = (((serial[2] * 3) + (100 - serial[3]) * 2 + serial[4] + serial[1]) * 2 + serial[0])
          % 232;
187 = ((serial[6] * 3) + (serial[14] * 2) + serial[4] + serial[3]) % 233;
125 = (serial[5] + serial[14] + serial[3] + serial[6] + serial[2] + serial[4]) % 212;
89 = (serial[12] * serial[4] + serial[13]) % 123;
132 = (((serial[11] * 2 + serial[14]) * 2) + (serial[6] * 7) + (serial[2] * 9) + serial[10]
          + serial[8] + serial[13] + serial[3] + serial[12]) % 218;
200 = ((serial[4] * 3) + (serial[6] + serial[7] * 4) * 2 + serial[2] + serial[8] + serial[3]
          + serial[2]) % 211;
125 = (((serial[3] * 3) + serial[9] * 4) + (serial[2] * 11) + (serial[5] * 7) + serial[8]) % 244;
86 = (((serial[2] + (serial[3] + serial[11] * 2) * 2) * 3) + (serial[9] * 7) + (serial[12] * 11)
          + serial[3]) % 123;

In cui compaiono i caratteri 0-14. La cosa più facile è fissare alcuni di questi caratteri, 7 per la precisione, mi modo tale da essere in grado di calcolare gli altri 8 in base alle 8 relazioni che conosciamo. Ricordandoci anche che viene effettuato il controllo:

(serial[15] - serial[10] - serial[8]) + (serial[0] - 80) = 0

Impostiamo per semplcitià quindi questi caratteri:
  1. serial[0] = 80;
  2. serial[8] = 49;
  3. serial[10] = 48;
  4. serial[15] = 97;
(fissiamo anche serial[15] in modo che il controllo che conosciamo sia sempre verificato, volendo si potrebbe calcolare in modo casuale questi valori sempre facendo in modo che venga rispettata l'equazione ma a noi non cambia molto)
Insieme ad altri 4, questa volta a nostra completa discrezione in modo casuale:
  1. #define INF 32
  2. #define SUP 126
  3.  
  4. serial[1] = (rand() % (SUP-INF)) + INF + 1;
  5. serial[4] = (rand() % (SUP-INF)) + INF + 1;
  6. serial[5] = (rand() % (SUP-INF)) + INF + 1;
  7. serial[6] = (rand() % (SUP-INF)) + INF + 1;
  8.  
  9. /* Fisso anche i caratteri 17-18 che non influiscono nei calcoli */
  10. serial[16] = (rand() % (SUP-INF)) + INF + 1;
  11. serial[17] = (rand() % (SUP-INF)) + INF + 1;
I limiti INF e SUP servono per generare caratteri ascii validi e digitabili da tastiera, cioè circa i caratteri dal 32 al 126.
Fatto questo rimane solo da risolvere il sistema in base alle 8 variabili rimaste in gioco, serial[2], serial[3], serial[7], serial[9], serial[11], serial[12], serial[13] e serial[14]. Questo sistema però ha un inconveniente: si tratta di un sistema modulare in classi di resto differenti (232,233,212,123...) e questo ovviamente non contribuisce a semplificare le cose.
Con un piccolo espediente matematico riscriviamo le varie equazioni trasformando le operazioni di modulo in normali moltiplicazioni introducendo 8 variabili fittizie, ad esempio:

124 = (((serial[2] * 3) + (100 - serial[3]) * 2 + serial[4] + serial[1]) * 2 + serial[0])
          % 232;

La trasformiamo (sostituendo anche le costanti) in:

124 = 2*(serial[1] + 3*serial[4] - 2*serial[5] + serial[6] + 240) - 232*x;

Facciamo la stessa cosa con le altre 7 equazioni e con un software matematico alla mano (Derive) andiamo a sostituire queste 8 varibili fittizzie che abbiamo introddotto con dei numeri "casuali" (nella realtà si tratta di numeri studiati apposta per riuscire a generare nella maggior parte delle volte caratteri nel range [INF;SUP]) e risolviamo in base ai caratteri che cerchiamo per ottenere:
  1. serial[2] = - (serial[1] + 3*serial[4] + 2*(2*serial[5] - serial[6] - 588))/7;
  2. serial[3] = (2*serial[1] - serial[4] - 6*serial[5] + 3*serial[6] + 763)/7;
  3. serial[7] = - (2*serial[4] - 2*serial[5] + 3*(serial[6] - 324))/8;
  4. serial[9] = (5*serial[1] + 36*serial[4] + 13*serial[5] - 31*serial[6] + 679)/28;
  5. serial[11] = - (serial[1]*(79*serial[4] - 475) + 188*serial[4]*serial[4] - serial[4]*
  6. (125*serial[5] + 109*serial[6] + 70627) - 1459*serial[5] + 2133*
  7. serial[6] + 3082415)/(112*(3*serial[4] + 8));
  8. serial[12] = - (187*serial[1] + 596*serial[4] + 307*serial[5] - 661*serial[6] - 890799)/
  9. (28*(3*serial[4] + 8));
  10. serial[13] = (187*serial[1]*serial[4] + 596*serial[4]*serial[4] + serial[4]*
  11. (307*serial[5] - 661*serial[6] - 46431) + 2251648)/(28*(3*serial[4] + 8));
  12. serial[14] = - (serial[1] + 3*serial[4] - 3*serial[5] + 12*serial[6] - 1904)/7;
Che sono proprio le equazioni che ci serviranno per calcolare gli ultimi caratteri del nostro seriale valido.
Abbiamo trovato dunque un modo per calcolare dei caratteri lavorando con i quali l'algoritmo di controllo del seriale ricava sempre gli stessi 8 resti, scelti appositamente per varificare i controlli successivi!
Sembrerebbe tutto perfetto, ma purtroppo non lo è per niente!
Purtroppo scegliendo di risolvere il problema in questo modo abbiamo ancora due grossi problemi:
1) I caratteri 2,3,7,9,11,12,13,14 che generiamo non è detto che siano entro un rage valido
E questo fatto può essere anche risolto facilmente con un ciclo che generi nuovi "caratteri fissi" 1,4,5,6 fin quando non calcoleremo tutti caratteri entro il range desiderato.
2) La propagazione dell'errore
E qui invece non abbiamo praticamente mezzi. Mi spiego meglio:
Lavorando con interi (ma anche con float la situazione non migliorerebbe affatto anzi, vi assicuro che peggiorerebbe) abbiamo un grosso errore di calcolo che ci portiamo dietro (dovuto dalle continue approssimazioni) che viene via via ampliato di operazione in operazione e che ci porta inesorabilmente a non verificare sempre il sistema di partenza (tantomeno a riottenere sempre gli 8 resti fissati all'inizio) una volta reinseriti i valori calcolati!
Questo fatto è facilmente verificabile controllando i resti calcolati dall'algoritmo di check visto in precedenza inserendo come input delle batterie di caratteri generati con questo nostro metodo. Siamo quindi di nuovo da capo: il nostro metodo, empiricamente perfetto, è vittima di approssimazioni non eliminabili che lo portano il 99% dei casi a generare caratteri che falliscono il controllo.
Con la voglia e la curiosità iniziale per il reversing ormai esaurita e con giorni di lavoro sulle spalle ci troviamo a dover risolvere anche quest'ultimo problema.
Parlandone un pò con amici ho deciso di sviluppare anche io i conti, come fanno i software matematici, in modo perfetto evitando approsimazioni e passando quindi all'utilizzo di una classe di numeri razionali che mi permettesse di ridurre le approssimazioni solo all'ultima frazione. Ma ovviamente anche questo era un vicolo cieco:
E' vero, adesso teoricamente saremmo in grado di calcolare dei caratteri che indubbiamente verificano il 100% delle volte il sistema di partenza, ma l'algoritmo che genera i resti partendo dai caratteri (il nostro ma soprattutto quello dell'Effetech HTTP sniffer) è ancora vittima della propagazione dell'errore il che ci porta di nuovo a non riuscire a validare i nostri caratteri generati la maggior parte delle volte.
In realtà cosi facendo le cose sono peggiorate: mentre prima, vittime anche noi di approsimazioni, potevamo generare a volte combinazioni corrette pur contaminati da errore di calcolo, adesso generado solamente caratteri "perfetti" l'errore prodotto unicamente dall'algoritmo di verifica ci porta a ridurre ancora di più la percentuale di combinazioni corrette prodotte! (senza parlare del tempo speso in interazioni a calcolare le varie operazioni sulle frazioni).
Bisogna ammettere che l'algoritmo pensato per validare la licenza di questo programma si difende bene, ma arrivati a questo punto l'ultima cosa da fare è buttare tutto il lavoro fatto. Arrendendoci al fatto che gli errori di calcolo non sono evitabili tanto vale sperare che si compensino a vicenda e sfruttare quella piccola percentuale di volte in cui il nostro metodo funziona. Lasciando perdere le idee sull'utilizzo di una classe razionale aggiungiamo sul ciclo di controllo del range dei caratteri generati anche il controllo sull'esattezza dei resti per stampare a schermo solo seriali effettivamenti perfetti sotto tutti i punti di vista. Il codice quindi risulta:
  1. do
  2. {
  3. serial[1] = (rand() % (SUP-INF)) + INF + 1;
  4. serial[4] = (rand() % (SUP-INF)) + INF + 1;
  5. serial[5] = (rand() % (SUP-INF)) + INF + 1;
  6. serial[6] = (rand() % (SUP-INF)) + INF + 1;
  7.  
  8. serial[2] = - (serial[1] + 3*serial[4] + 2*(2*serial[5] - serial[6] - 588))/7;
  9. serial[3] = (2*serial[1] - serial[4] - 6*serial[5] + 3*serial[6] + 763)/7;
  10. serial[7] = - (2*serial[4] - 2*serial[5] + 3*(serial[6] - 324))/8;
  11. serial[9] = (5*serial[1] + 36*serial[4] + 13*serial[5] - 31*serial[6] + 679)/28;
  12. serial[11] = - (serial[1]*(79*serial[4] - 475) + 188*serial[4]*serial[4] - serial[4]*
  13. (125*serial[5] + 109*serial[6] + 70627) - 1459*serial[5] + 2133*
  14. serial[6] + 3082415)/(112*(3*serial[4] + 8));
  15. serial[12] = - (187*serial[1] + 596*serial[4] + 307*serial[5] - 661*serial[6] - 890799)/
  16. (28*(3*serial[4] + 8));
  17. serial[13] = (187*serial[1]*serial[4] + 596*serial[4]*serial[4] + serial[4]*
  18. (307*serial[5] - 661*serial[6] - 46431) + 2251648)/(28*(3*serial[4] + 8));
  19. serial[14] = - (serial[1] + 3*serial[4] - 3*serial[5] + 12*serial[6] - 1904)/7;
  20.  
  21. } while( /* Range caratteri */
  22. (serial[2] < INF || serial[2] > SUP) || (serial[3] < INF || serial[3] > SUP) ||
  23. (serial[7] < INF || serial[7] > SUP) || (serial[9] < INF || serial[9] > SUP) ||
  24. (serial[11] < INF || serial[11] > SUP) || (serial[12] < INF || serial[12] > SUP) ||
  25. (serial[13] < INF || serial[13] > SUP) || (serial[14] < INF || serial[14] > SUP) ||
  26. /* Correttezza resto */
  27. 124 != ((((serial[2] * 3) + ((0x64 - serial[3]) * 2 )) + serial[4] + serial[1])
  28. * 2 + serial[0]) % 0xE8 ||
  29. 187 != ((serial[6] * 3) + (serial[14] * 2) + serial[4] + serial[3]) % 0xE9 ||
  30. 125 != (serial[5] + serial[14] + serial[3] + serial[6] + serial[2] + serial[4])
  31. % 0xD4 ||
  32. 89 != (serial[12] * serial[4] + serial[13]) % 0x7B ||
  33. 132 != (((serial[11] * 2 + serial[14]) * 2) + (serial[6] * 7) + (serial[2] * 9)
  34. + serial[10] + serial[8] + serial[13] + serial[3] + serial[12]) % 0xDA ||
  35. 200 != ((serial[4] * 3) + (serial[6] + serial[7] * 4) * 2 + serial[2] + serial[8]
  36. + serial[3] + serial[2]) % 0xD3 ||
  37. 125 != (((serial[3] * 3) + serial[9] * 4) + (serial[2] * 0xB) + (serial[5] * 7)
  38. + serial[8]) % 0xF4 ||
  39. 86 != (((serial[2] + (serial[3] + serial[11] * 2) * 2) * 3) + (serial[9] * 7) +
  40. (serial[12] * 0xB) + serial[3]) % 0x7B);
Usciti dal quale avremo sicuramente la certezza di avere tra le mani un seriale valido.
Come si nota eseguendo questo algoritmo la generazione di un seriale valido può richiedere anche qualche secondo, capita infatti che il ciclo venga ripetuto addirittura 6000000 volte prima di riuscire ad ottenere un codice che rispecchi tutte le caratteristiche richieste, e a questo non porremo rimedio.
La soluzione proposta è senz'altro migliorabile, magari introducendo coefficenti di correzzione che aumentino la percentuale di codici validi, o scegliendo resti e/o caratteri iniziali diversi che portino a meno conti e quindi meno errori, in ogni caso lo scopo di questo articolo era quello di reversare un algoritmo e trovare un modo per realizzare un keygen, e questo è stato fatto.
La realizzazione di un keygen quindi termina qui, come detto il medoto proposto non è senz'altro il migliore per generare seriali, ma funziona alla grande.
Se qualcuno leggendo questo articolo ha un'idea migliore o trova un altro modo valido per generare seriali lo invito a postarlo direttamente.
Per sfizio ho realizzato anche un programmino con un'interfaccia grafica nel tipico stile dei keygen che utilizza questo algoritmo scaricabile dalla sezione.

 
Software reversing 7 passo: Cracking
 
Conoscendo l'algoritmo di controllo del seriale, sapendo come valida gli input introdotti e dove chiama le funzioni di errore siamo anche in grado di patchare direttamente l'eseguibile nei suoi punti deboli, in modo da forzare la validazione di qualsiasi codice vogliamo.
Di solito è più semplice crakkare una applicazione che realizzarne un keygen funzionante, il cracking si effettua generalmente su programmi più complicati con algoritmi di controllo veramente lunghi o non invertibili o quando non si vuole stare a perdere troppo tempo.
Io personalmente se posso preferisco non mettere mai mano direttamente sull'eseguibile.
In questo caso il cracking dell'Effetech HTTP sniffer dopo il lavoro svolto non è più necessario ma è comunque interessante e verrà svolto per vedere come bastano pochi bit di differenza nel codice nell'eseguibile per cambiarne totalmente il funzionamento.
Dunque iniziamo.
Provando a evitare la chiamata alla routine di errore sul 2 check (0x00415540) e forzare il salto sul check di EBP (0x0040F07B) è possibile riuscire a rendere valido qualsiasi seriale (di 18 caratteri) introdotto.
Chiudendo a riaprendo l'applicazione però si vede subito che il form di registrazione riappare; significa quindi che ad ogni avvio il programma ricontrolla il seriale introdotto nella registrazione precedente che aveva salvato sul registro di sistema.
Dobbiamo quindi cambiare punto di attacco, debuggare il programma dall'inizio e intercettare il punto in cui avviene il controllo del seriale presente sul registro (io ho utilizzato un breakpoint su RegQueryValueExA). Senza stare a esaminare l'intero disassemblato e portiamoci all'indirizzo 0x0040F9FA:
  1. 0040F9FA JNZ SHORT EHSniffe.0040FA13 ; Salto in caso di errore
  2. 0040F9FC PUSH EHSniffe.00473744
  3. 0040FA01 MOV ECX,EHSniffe.004736C8
  4. 0040FA06 CALL <EHSniffe.CheckSerial> ; Controllo il seriale
  5. 0040FA0B TEST EAX,EAX
  6. 0040FA0D JNZ EHSniffe.0040FA96 ; Salto in caso di errore
Visto che la prima parte delle istruzioni per la registrazione del protdotto avvengono alla fine della funzione CheckSerial (ed avviene solo per certi valori di EBP) non possiamo patchare il controllo all'indirizzo 0x0040FA0D ma dobbiamo far in modo che la procedura all'interno di Checkserial avvenga.
Quindi come prima patchamo l'istruzione all'indirizzo 0x0040F07B cambiando il salto da JE (salto condizionato) a JMP (salto incondizionato) e per fare in modo che la procedura CheckSerial venga sempre chiamata all'avvio dobbiamo anche impedire l'esecuzione dell'istruzione di salto presente all'indirizzo 0x0040F9FA (noppandolo).
Fatte queste operazioni otterremo il risultato sperato: il programma si avvia, non mostra più la schermata di registrazione e non scade dopo 15 giorni!.

  1. 0040F075 81FD A52B0000 CMP EBP,2BA5 ; if (EBP == 0x2BA5)
  2. 0040F07B 74 45 JE SHORT EHSniffe._JUMP_OK ; Salta
  1. 0040F075 81FD A52B0000 CMP EBP,2BA5 ; if (EBP == 0x2BA5)
  2. 0040F07B EB 45 JMP SHORT EHSniffe._JUMP_OK ; Salta

  1. 0040F9FA 75 17 JNZ SHORT EHSniffe.0040FA13 ; Salto in caso di errore
  2. 0040F9FC 68 44374700 PUSH EHSniffe.00473744
  3. 0040FA01 B9 C8364700 MOV ECX,EHSniffe.004736C8
  4. 0040FA06 E8 E5F0FFFF CALL <EHSniffe.CheckSerial> ; Controllo il seriale
  1. 0040F9FA 90 NOP
  2. 0040F9FB 90 NOP
  3. 0040F9FC 68 44374700 PUSH EHSniffe.00473744
  4. 0040FA01 B9 C8364700 MOV ECX,EHSniffe.004736C8
  5. 0040FA06 E8 E5F0FFFF CALL <EHSniffe.CheckSerial> ; Controllo il seriale
Per realizzare un programma che esegua questa patch al posto nostro l'unica accortezza che occorre avere è calcolarsi l'offset delle istruzioni che intendiamo cambiare all'interno dell'esegubile partendo dall'indirizzo virtuale che abbiamo nel debugger (0x0040FA0D e 0x0040F07B). Per far questo basta sottrarre a questi indirizzi l'image base dell'eseguibile (l'indirizzo dal quale parte il carticamento in memoria delle istruzioni) che ci mostra il debugger (dipende dal debugger dove trovare questa informazione, generalmente è tra le proprietà dell' immagine) in questo caso 0x00400000. Abbiamo quindi:

Offset1 = 0x0040F07B - 0x00400000 = F07B
Offset2 = 0x0040F9FA - 0x00400000 = F9FA

Apriamo il file EHSniffer.exe, posizioniamoci a questi indirizzi e sovrascriviamo le istruzioni che abbiamo appena visto con le nuove nostre:
  1. FILE *Effetech;
  2.  
  3. WORD Offset1 = 0xF07B;
  4. WORD Offset2 = 0xF9FA;
  5.  
  6. BYTE patch1 = 0xEB; /* JMP */
  7. BYTE patch2[2] = { 0x90, 0x90 }; /* NOP */
  8.  
  9. Effetech = fopen ("EHSniffer.exe","r+");
  10.  
  11. if (!Effetech)
  12. {
  13. printf("Errore apertura file\n");
  14. return 1;
  15. }
  16.  
  17. /* 1 patch */
  18. fseek (Effetech, Offset1 , SEEK_SET );
  19. fwrite(&patch1,sizeof(BYTE),1,Effetech);
  20.  
  21. /* 2 patch */
  22. fseek (Effetech, Offset2 , SEEK_SET );
  23. fwrite(patch2,sizeof(BYTE),2,Effetech);
  24.  
  25. printf("Crack applicata con successo\n");
  26.  
  27. fclose (Effetech);

 
Conclusioni
 
Con una buona conoscenza dell'assembly, un pò di pratica con un debugger, una minima conoscenza di un linguaggio di programmazione ad alto livello e soprattutto molta voglia e tempo non è troppo difficile studiare programmi di questo tipo come è stato fatto in questo articolo.
Ricordo ancora una volta che al termine del periodo di prova del programma per poter continuare ad usufruirne occorre acquistare legalmente una licenza, quest'articolo è solo uno studio a scopo informativo per dimostrare come è possibile capire il funzionamento di parti di programma già scritto da altri senza essere in possesso del codice sorgente.
Non mi ritengo responsabile di vostri eventuali atti in malafede, avere una pistola carica non vuol dire dover sparare.
Per cancellare la licenza realizzata dal keygen al termine dei 15 giorni di prova occorre cancellare la chiave del registro

[HKEY_USERS\S-1-5-21-117609710-1123561945-682003330-1003\Software\EffeTech\ EffeTech HTTP Sniffer\Reg]

o utilizzare il file .reg che ho realizzato nella sezione appendici.
Ne approfitto infine per ringraziare per l'idea che mi ha dato per il keygenning e MF per la soluzione del sistema.
Invito chiunque voglia esprimere la propria opinione, dare un'idea o chiedere qualcosa a lasciare un commento all' piuttosto che scrivermi una e-mail.
Update:
Dal 30 gennaio è stata rilasciata la versione 4.1 del programma in questione basandolo sull'ultima versione di winpcap. Da test ho verificato che l'algoritmo di check del seriale è rimasto lo stesso della versione precedente, cioè quello analizzato e reversato in questo articolo.
Gli indirizzi di memoria invece (ovviamente) sono cambiati e questo rende inefficace il crack proposto (a differenza del keygen che funziona tutt'ora perfettamente).
Ciò a dimostraree che vale la pena spendere un pò più di tempo nell'analisi dell'eseguibile per reversare l'algoritmo piuttosto che limitarsi a una pacth.

 
Appendici
 
Downloads: 199
Il setup del programma in questione
Downloads: 313
L'algoritmo di controllo del seriale.
Downloads: 310
L'algoritmo di keygen.
Downloads: 213
Il keygen con finestra grafica.
Downloads: 284
La crack per l'eseguibile.
Downloads: 329
Il file per rimuovere la licenza registrata.


Script Execution Time: 0.124818 seconds - Visite: 641917
Copyright © 2007-2017 Suondmao v0.1.5-1