Winamp 5.04 | ||
Data |
by bender0 |
|
gg/mese/aaaa |
Published by Quequero | |
"?" |
Bender stavolta complimenti, hai fatto un tutorial veramente completo e chiaro, bravo davvero!!! |
"!" |
.... |
|
.... |
Difficoltà |
( )NewBies ( )Intermedio (X)Avanzato ( )Master |
studiamoci un bello schema protettivo made in Nullsoft.
Introduzione |
Tools usati |
URL o FTP del programma |
Notizie sul programma |
Essay |
parte prima
simple cracking
"praesidium dirumpere"
~
parte seconda
advanced keygenning
"praesidii imago esse"
~
reversing
keygenning
--- winamp504keygen.cpp start --- #include <stdio.h> #include <stdlib.h> #include <string.h> // windows.h per copiare il serial negli appunti #include <windows.h> // l'include per le funzioni dello sha1 #include "sha1.h" // il buffer da passare a SHA1Input e alcune delle sue componenti unsigned char msg[64]; unsigned char nums[3]={0,0,0}; // nums[0]: 0 = non valido; 1 = 5.0; >1 = > 5.0 unsigned char padbyte[1] = {0x80}; // dobbiamo paddare noi il messaggio unsigned char chksum[2]; // qui metteremo 25h volte la lunghezza del messaggio unsigned char bytes[16] = { // i 16 bytes fissi 0xE7,0x4A,0x67,0x3C,0x44,0x05,0x0B,0x39, 0xB9,0xD2,0xEB,0x63,0xCC,0xFD,0x07,0x69 }; // la funzione decode accetta come argomenti l'hash una volta "elaborata" // e un buffer di testo (24 bytes) per l'output. legge 5 byte e li converte // in caratteri indicizzando la tabella qui sotto. è codata in modo // orribile, lo so... unsigned char base32table[] = "0123456789ABCDEFHJKMNPQRSTUVWXYZ"; void decode(unsigned char* hash,char* dest) { dest[0] = base32table[ hash[0]&0x1F ]; dest[1] = base32table[ hash[0]>>5 | (hash[1]&0x03)<<3 ]; dest[2] = base32table[ (hash[1]&0x7F)>>2 ]; dest[3] = base32table[ hash[1]>>7 | (hash[2]&0x0F)<<1 ]; dest[4] = base32table[ hash[2]>>4 | (hash[3]&0x01)<<4 ]; dest[5] = '-'; dest[6] = base32table[ (hash[3]&0x3F)>>1 ]; dest[7] = base32table[ hash[3]>>6 | (hash[4]&0x07)<<2 ]; dest[8] = base32table[ hash[4]>>3 ]; dest[9] = base32table[ hash[5]&0x1F ]; dest[10] = base32table[ hash[5]>>5 | (hash[6]&0x03)<<3 ]; dest[11] = '-'; dest[12] = base32table[ (hash[6]&0x7F)>>2 ]; dest[13] = base32table[ hash[6]>>7 | (hash[7]&0x0F)<<1 ]; dest[14] = base32table[ hash[7]>>4 | (hash[8]&0x01)<<4 ]; dest[15] = base32table[ (hash[8]&0x3F)>>1 ]; dest[16] = base32table[ hash[8]>>6 | (hash[9]&0x07)<<2 ]; dest[17] = '-'; dest[18] = base32table[ hash[9]>>3 ]; dest[19] = base32table[ hash[10]&0x1F ]; dest[20] = base32table[ hash[10]>>5 | (hash[11]&0x03)<<3 ]; dest[21] = base32table[ (hash[11]&0x7F)>>2 ]; dest[22] = base32table[ hash[11]>>7 | (hash[12]&0x0F)<<1 ]; dest[23] = 0; } // copytoclipboard copia il buffer di testo passato come parametro // negli appunti, così lo possiamo pastare direttamente con ctrl+V void copytoclipboard(char* text) { if (!OpenClipboard(NULL)) return; EmptyClipboard(); HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE,strlen(text)+1); if (hmem == NULL) {CloseClipboard(); return;} char* strbuf = (char*) GlobalLock(hmem); memcpy(strbuf, text, strlen(text)+1); GlobalUnlock(hmem); SetClipboardData(CF_TEXT,hmem); CloseClipboard(); GlobalFree(hmem); } void main() { // un contatore int i; // due buffer di testo, uno per il name e uno per il numero unsigned char name[31]; unsigned char num[5]; // il numero verrà salvato qui unsigned char val; // raccolta dati printf("winamp 5.04 keygen\ncoded by bender0\n"); printf("enter your name (no spaces, no dots): "); gets((char*)name); printf("enter a number between 1 and 63: "); gets((char*)num); val = atoi((char*)num); // se non è tra 0 e 0x3F cancelliamo il resto // se è 0 lo settiamo a 1, poi lo copiamo nel buffer val &= 0x3F; if (!val) val++; nums[0] = val; // calcoliamo i due byte finali con la lunghezza del nome int len = strlen((char*)name); int checksum = 0x25 * (20+len); // spostiamo i due byte nel buffer chksum[1] = checksum & 0xFF; chksum[0] = (checksum & 0xFF00) >> 8; // dichiariamo e inizializziamo la struttura SHA1Context ct; SHA1Reset(&ct); // riempiamo il buffer: for (i=0;i<64;i++) msg[i]=0; // lo azzeriamo memcpy(msg,name,len+1); // il nome memcpy(msg+len+1,nums,3); // poi i tre byte memcpy(msg+len+4,bytes,16); // i byte fissi memcpy(msg+len+20,padbyte,1); // il byte per il padding memcpy(msg+62,chksum,2); // i due byte calcolati prima // passiamo il buffer nella struttura e ci facciamo calcolare l'hash SHA1Input(&ct,msg,64); // un buffer per contenere l'hash e il byte aggiuntivo unsigned char hash[13]; // copiamo 12 byte dell'hash dalla struttura al nostro buffer // la hash è il primo membro della struttura, quindi lo uso // come pointer unsigned char* phash = (unsigned char*)&ct; // copiamo rovesciando l'ordine dei bytes nelle doublewords for(i=0;i<12;i++) { hash[i] = phash[(i-(i%4))+(3-(i%4))]; } // eliminiamo tutte le informazioni extra, cioè il bit più alto // dei primi 6 bytes e i due bit più alti dei secondi 6 for(i=0;i<6;i++) { hash[i] &= 0x7F; } for(i=6;i<12;i++) { hash[i] &= 0x3F; } // copiamo bit a bit il numero immesso dall'utente nei bit alti // dei primi 6 bytes if (nums[0] & 0x20) hash[0] |= 0x80; if (nums[0] & 0x10) hash[1] |= 0x80; if (nums[0] & 0x08) hash[2] |= 0x80; if (nums[0] & 0x04) hash[3] |= 0x80; if (nums[0] & 0x02) hash[4] |= 0x80; if (nums[0] & 0x01) hash[5] |= 0x80; // calcoliamo il byte extra xorando tutti i byte con 0Bh unsigned char tmp=0x0B; for(i=0;i<12;i++) { tmp ^= hash[i]; } // spostiamolo alla fine del buffer hash[i] = tmp; // creiamo un buffer per il serial e lo facciamo riempire a decode unsigned char serial[24]; decode(hash,(char*)serial); // et voilà! printf("serial: %s\n",serial); // copiamolo anche negli appunti informando l'utente... copytoclipboard((char*)serial); printf("the serial has been copied to the clipboard, paste it with ctrl+V.\n"); // bye bye system("pause"); } --- winamp504keygen.cpp end---
riporto qui l'analisi della routine che valida i serial, copiandola direttamente da ida.
la pasto solo per referenza, leggere le parti evidenziate è sufficiente; ma se volete
vedere più da vicino cosa fa ogni istruzione della procedura potete leggere anche il resto.
.text:00444413 ***************************************************************************** .text:00444413 check: .text:00444413 questa routine valida i serial di winamp 5.04. .text:00444413 ***************************************************************************** .text:00444413 check proc near ; CODE XREF: sub_4443B4+40p .text:00444413 .text:00444413 SHA1CONTEXT = byte ptr -17Ch .text:00444413 ADDR_HASH = byte ptr -20h .text:00444413 ENCODED_PTR = byte ptr -14h .text:00444413 COUNTER = dword ptr -4 .text:00444413 NAME = dword ptr 8 .text:00444413 SERIAL = dword ptr 0Ch .text:00444413 NUMGEN = dword ptr 10h .text:00444413 SHIFTCOUNTER = dword ptr 14h .text:00444413 .text:00444413 push ebp .text:00444414 mov ebp, esp .text:00444416 sub esp, 17Ch ; crea un frame piuttosto grande (per una struttura sha1context) .text:0044441C mov eax, [ebp+NUMGEN] ; smista i parametri .text:0044441F push ebx .text:00444420 mov ebx, [ebp+SHIFTCOUNTER] .text:00444423 push esi .text:00444424 push edi .text:00444425 xor edx, edx ; azzera edx .text:00444427 push 0Bh .text:00444429 mov [eax], edx .text:0044442B mov [ebx], edx .text:0044442D pop edi ; edi = 0Bh .text:0044442E mov [ebp+SHIFTCOUNTER], edx ; azzera una variabile .text:00444431 xor esi, esi ; azzera anche esi .text:00444433 mov [ebp+COUNTER], edx ; e il contatore .text:00444436 .text:00444436 ***************************************************************************** .text:00444436 PRIMO LOOP: .text:00444436 il seguente loop codifica il serial usando un algoritmo base32 modificato, .text:00444436 che risponde alla tabella riportata a fine loop. .text:00444436 ***************************************************************************** .text:00444436 .text:00444436 primo_loop: ; CODE XREF: check+74j .text:00444436 ; check+BBj .text:00444436 mov eax, [ebp+SERIAL] ; -= PRIMO LOOP =- .text:00444439 inc [ebp+SERIAL] .text:0044443C movsx eax, byte ptr [eax] .text:0044443F cmp eax, 'a' .text:00444442 jl short non_minuscola .text:00444444 cmp eax, 'z' .text:00444447 jg short non_minuscola .text:00444449 sub eax, 20h ; minuscola? falla maiuscola e continua .text:0044444C .text:0044444C non_minuscola: ; CODE XREF: check+2Fj .text:0044444C ; check+34j .text:0044444C cmp eax, 'G' .text:0044444F jnz short non_G .text:00444451 push 36h ; G? 6h .text:00444453 jmp short poppa_e_meno30h .text:00444455 ; --------------------------------------------------------------------------- .text:00444455 .text:00444455 non_G: ; CODE XREF: check+3Cj .text:00444455 cmp eax, 'I' .text:00444458 jz short I .text:0044445A cmp eax, 'L' .text:0044445D jnz short non_L .text:0044445F .text:0044445F I: ; CODE XREF: check+45j .text:0044445F push 31h ; I,L? 1h .text:00444461 .text:00444461 poppa_e_meno30h: ; CODE XREF: check+40j .text:00444461 pop eax .text:00444462 .text:00444462 meno30h: ; CODE XREF: check+64j .text:00444462 sub eax, 30h .text:00444465 jmp short fatto .text:00444467 ; --------------------------------------------------------------------------- .text:00444467 .text:00444467 non_L: ; CODE XREF: check+4Aj .text:00444467 cmp eax, 'O' .text:0044446A jnz short non_O .text:0044446C push 30h ; O? 0h .text:0044446E pop eax .text:0044446F .text:0044446F non_O: ; CODE XREF: check+57j .text:0044446F cmp eax, '0' .text:00444472 jl short meno_di_zero .text:00444474 cmp eax, '9' .text:00444477 jle short meno30h ; numero? togli 30h .text:00444479 .text:00444479 meno_di_zero: ; CODE XREF: check+5Fj .text:00444479 cmp eax, 'A' .text:0044447C jl short meno_di_A .text:0044447E cmp eax, 'Z' .text:00444481 jle short maiuscola .text:00444483 .text:00444483 meno_di_A: ; CODE XREF: check+69j .text:00444483 test eax, eax ; la stringa ha meno di 20 caratteri validi? .text:00444485 jz short esce_meno1 ; errore! .text:00444487 jmp short primo_loop ; eventuali altri caratteri sono ignorati .text:00444489 ; --------------------------------------------------------------------------- .text:00444489 .text:00444489 maiuscola: ; CODE XREF: check+6Ej .text:00444489 cmp eax, 'O' ; O era 0 .text:0044448C jle short minug_O .text:0044448E dec eax ; più di O? dec .text:0044448F .text:0044448F minug_O: ; CODE XREF: check+79j .text:0044448F cmp eax, 'L' ; L era 1h .text:00444492 jle short minug_L .text:00444494 dec eax ; M,N? dec .text:00444495 .text:00444495 minug_L: ; CODE XREF: check+7Fj .text:00444495 cmp eax, 'I' ; I era 1h .text:00444498 jle short minug_I .text:0044449A dec eax ; J,K? dec .text:0044449B .text:0044449B minug_I: ; CODE XREF: check+85j .text:0044449B cmp eax, 'G' ; G era 6h .text:0044449E jle short minug_G .text:004444A0 dec eax ; H? dec .text:004444A1 .text:004444A1 minug_G: ; CODE XREF: check+8Bj .text:004444A1 sub eax, 37h ; alla fine toglie 37h .text:004444A4 .text:004444A4 fatto: ; CODE XREF: check+52j .text:004444A4 mov ecx, [ebp+SHIFTCOUNTER] .text:004444A7 add [ebp+SHIFTCOUNTER], 5 ; inc di 5 lo shiftcounter .text:004444AB shl eax, cl ; sposta nella giusta posizione .text:004444AD or edx, eax ; e incastra in edx .text:004444AF cmp [ebp+SHIFTCOUNTER], 8 .text:004444B3 jle short shctr_minug8 ; ci sono 8 bit di dati codificati pronti? .text:004444B5 sub [ebp+SHIFTCOUNTER], 8 ; se sì, togli 8 al counter .text:004444B9 mov [ebp+esi+ENCODED_PTR], dl ; e salva il valore; esi conta il char encodati .text:004444BD movzx eax, dl ; prende l'ultimo byte fatto... .text:004444C0 xor edi, eax ; e lo xora con edi, che in origine è 0Bh .text:004444C2 inc esi ; incrementa il puntatore ai char encodati .text:004444C3 sar edx, 8 ; aggiusta edx .text:004444C6 .text:004444C6 shctr_minug8: ; CODE XREF: check+A0j .text:004444C6 add [ebp+COUNTER], 5 ; via così fino al 20o carattere valido .text:004444CA cmp [ebp+COUNTER], 64h .text:004444CE jl primo_loop .text:004444CE - .text:004444CE si ricava la seguente tabella di encoding\decoding: .text:004444CE (cfr. la tabella della base32 nella rfc) .text:004444CE - .text:004444CE Value Encoding Value Encoding Value Encoding Value Encoding .text:004444CE - .text:004444CE 0 0,O 9 9 18 K 27 V .text:004444CE 1 1,L,I 10 A 19 M 28 W .text:004444CE 2 2 11 B 20 N 29 X .text:004444CE 3 3 12 C 21 P 30 Y .text:004444CE 4 4 13 D 22 Q 31 Z .text:004444CE 5 5 14 E 23 R .text:004444CE 6 6,G 15 F 24 S .text:004444CE 7 7 16 H 25 T .text:004444CE 8 8 17 J 26 U .text:004444CE - .text:004444D4 cmp [ebp+SHIFTCOUNTER], 0 ; il contatore dello shift non deve essere zero. .text:004444D4 ; se il serial è del formato giusto qui sarà sempre 4, .text:004444D4 ; ad indicare il nibble che avanza dall'encoding. .text:004444D8 jle pusha_meno2_e_esce .text:004444DE cmp esi, 0Dh ; devono risultare esattamente 12 bytes codificati .text:004444E1 jge pusha_meno2_e_esce .text:004444E7 mov [ebp+esi+ENCODED_PTR], dl ; aggiunge alla fine il nibble "di troppo" .text:004444EB and edx, 0Fh ; poi lo riprende .text:004444EE and edi, 0Fh ; assieme ai primi 4 bit dell'ultimo char encodato .text:004444F1 xor edx, edi ; li confronta... .text:004444F3 jz short prosegui ; devono essere uguali .text:004444F5 push -3 ; altrimenti... errore .text:004444F7 jmp poppa_e_esce .text:004444F7 - .text:004444F7 dalla precedente porzione di codice si capisce che generando il serial codificato dovremmo .text:004444F7 calcolare parte dell'ultimo carattere (i primi 4 bit su 5) bit in base allo xor di prima. .text:004444F7 - .text:004444FC ; --------------------------------------------------------------------------- .text:004444FC .text:004444FC esce_meno1: ; CODE XREF: check+72j .text:004444FC or eax, -1 .text:004444FF jmp esce .text:00444504 ; --------------------------------------------------------------------------- .text:00444504 ***************************************************************************** .text:00444504 SECONDO LOOP: .text:00444504 qui vengono generati due numeri a partire dal serial encodato. .text:00444504 questi due numeri sono poi salvati ai due indirizzi passati come parametri. .text:00444504 ***************************************************************************** .text:00444504 .text:00444504 prosegui: ; CODE XREF: check+E0j .text:00444504 push -0Ch .text:00444506 lea eax, [ebp+ENCODED_PTR] ; eax punta al serial encodato .text:00444509 pop edi ; edi = -12, è il counter .text:0044450A xor esi, esi ; esi fa da counter dei byte .text:0044450C push 2 .text:0044450E pop edx ; edx = 2 .text:0044450F sub edx, eax ; edx = 2-pointer .text:00444511 .text:00444511 secondo_loop: ; CODE XREF: check+130j .text:00444511 test edi, edi ; -= SECONDO LOOP =- .text:00444513 jge short edi_positivo ; se edi è arrivato nei positivi .text:00444515 - .text:00444515 questa parte usa i primi 6 byte del serial encodato .text:00444515 - .text:00444515 lea eax, [ebp+esi+ENCODED_PTR] ; carica l'indirizzo di un char encodato in eax .text:00444519 mov cl, al .text:0044451B mov al, [eax] ; carica un char in al .text:0044451D add cl, dl .text:0044451F and eax, 80h ; and con 80h .text:00444524 shr eax, cl ; shift a destra (con i valori: 2,3,4,5,6,7) .text:00444526 mov ecx, eax .text:00444528 mov eax, [ebp+NUMGEN] .text:0044452B or [eax], ecx ; or con una dword puntata da un argomento .text:0044452D jmp short continua .text:0044452F ; --------------------------------------------------------------------------- .text:0044452F - .text:0044452F questa usa gli altri 6 byte. .text:0044452F - .text:0044452F .text:0044452F edi_positivo: ; CODE XREF: check+100j .text:0044452F movzx eax, [ebp+esi+ENCODED_PTR] ; byte encodato in eax .text:00444534 shr eax, 6 ; shift di 6 a destra .text:00444537 mov ecx, edi ; in ecx il contatore due a due (valori: 0,2,4,6,8,10) .text:00444539 shl eax, cl ; shift a sinistra con i valori del contatore .text:0044453B or [ebx], eax ; or con un'altra dword puntata da un argomento .text:0044453D .text:0044453D continua: ; CODE XREF: check+11Aj .text:0044453D inc esi ; esi incrementato .text:0044453E inc edi ; edi va di due in due .text:0044453F inc edi .text:00444540 cmp edi, 0Ch ; siamo alla fine? .text:00444543 jl short secondo_loop ; loop .text:00444545 ***************************************************************************** .text:00444545 HASH: .text:00444545 qui viene calcolato un hash a partire dal name e dai due numeri generati. .text:00444545 ***************************************************************************** .text:00444545 lea eax, [ebp+SHA1CONTEXT] .text:0044454B push eax ; pusha il context .text:0044454C call sha1_init .text:00444551 push [ebp+NAME] ; pusha il name .text:00444554 lea eax, [ebp+SHA1CONTEXT] .text:0044455A push eax ; pusha il context .text:0044455B call sha1_A .text:00444560 mov eax, [ebp+NUMGEN] .text:00444563 push 1 ; pusha n = 1 .text:00444565 mov al, [eax] ; carica il primo numero generato .text:00444567 mov [ebp+0Fh], al ; lo posiziona .text:0044456A mov al, [ebx] ; carica il secondo .text:0044456C mov [ebp+13h], al ; lo posiziona .text:0044456F mov eax, [ebx] .text:00444571 sar eax, 8 ; carica il byte alto del secondo numero generato .text:00444574 mov [ebp+17h], al ; lo posiziona .text:00444577 lea eax, [ebp+0Fh] .text:0044457A push eax ; pusha l'indirizzo del buffer (ebp+Fh) .text:0044457B lea eax, [ebp+SHA1CONTEXT] .text:00444581 push eax ; pusha il context .text:00444582 call sha1 .text:00444587 lea eax, [ebp+13h] .text:0044458A push 1 ; pusha n = 1 .text:0044458C push eax ; pusha l'indirizzo del buffer (ebp+13h) .text:0044458D lea eax, [ebp+SHA1CONTEXT] .text:00444593 push eax ; pusha il context .text:00444594 call sha1 .text:00444599 lea eax, [ebp+17h] .text:0044459C push 1 ; pusha n = 1 .text:0044459E push eax ; pusha l'indirizzo del buffer (ebp+17h) .text:0044459F lea eax, [ebp+SHA1CONTEXT] .text:004445A5 push eax ; pusha il context .text:004445A6 call sha1 .text:004445AB push 10h ; pusha n = 10h .text:004445AD lea eax, [ebp+SHA1CONTEXT] .text:004445B3 push offset unk_45A4E8 ; pusha un indirizzo fisso per il buffer .text:004445B8 push eax ; pusha il context .text:004445B9 call sha1 .text:004445BE lea eax, [ebp+ADDR_HASH] .text:004445C1 push eax ; pusha l'indirizzo finale per l'hash .text:004445C2 lea eax, [ebp+SHA1CONTEXT] .text:004445C8 push eax ; pusha il context .text:004445C9 call sha1_B .text:004445CE add esp, 44h .text:004445D1 ***************************************************************************** .text:004445D1 TERZO LOOP: .text:004445D1 questo loop xora l'hash appena calcolato con il serial codificato, .text:004445D1 byte per byte. lo xor dei primi 6 byte deve dare 80 o 0, quello dei secondi 6 .text:004445D1 deve dare C0,80,40 o 0. .text:004445D1 ***************************************************************************** .text:004445D1 xor eax, eax ; azzera il contatore .text:004445D3 .text:004445D3 terzo_loop: ; CODE XREF: check+1E3j .text:004445D3 movzx ecx, [ebp+eax+ADDR_HASH] ; pointer all'hash in ecx .text:004445D8 movzx edx, [ebp+eax+ENCODED_PTR] ; pointer al serial codificato in edx .text:004445DD xor ecx, edx ; xor in ecx .text:004445DF xor edx, edx ; azzera edx .text:004445E1 cmp eax, 6 ; se siamo almeno a metà... .text:004445E4 setnl dl ; setta dl .text:004445E7 dec edx ; edx-1 .text:004445E8 and edx, 40h ; and 40 .text:004445EB add edx, 3Fh ; add 3F .text:004445EE test edx, ecx ; test con ecx; .text:004445EE ; edx ora è 7F fino al sesto, poi 3F .text:004445F0 jnz short oooops_sbagliato .text:004445F2 inc eax ; prossimo byte .text:004445F3 cmp eax, 0Ch ; è l'ultimo? .text:004445F6 jl short terzo_loop ; loop .text:004445F8 xor eax, eax ; se supera il check, eax = 0 .text:004445FA jmp short esce .text:004445FC ; --------------------------------------------------------------------------- .text:004445FC .text:004445FC oooops_sbagliato: ; CODE XREF: check+1DDj .text:004445FC push -4 ; codice sbagliato: -4 .text:004445FE jmp short poppa_e_esce .text:00444600 ; --------------------------------------------------------------------------- .text:00444600 .text:00444600 pusha_meno2_e_esce: ; CODE XREF: check+C5j .text:00444600 ; check+CEj .text:00444600 push -2 .text:00444602 .text:00444602 poppa_e_esce: ; CODE XREF: check+E4j .text:00444602 ; check+1EBj .text:00444602 pop eax .text:00444603 .text:00444603 esce: ; CODE XREF: check+ECj .text:00444603 ; check+1E7j .text:00444603 pop edi .text:00444604 pop esi .text:00444605 pop ebx .text:00444606 leave .text:00444607 retn .text:00444607 check endp .text:00444607
Note finali |
perdonatemi i sottotitoli in latino ma non ho saputo resistere all'idea :)
un grazie a ZaiRoN, perchè leggendo il suo tutorial su File Carbon (leggetevelo anche voi!) mi è venuto in mente di aver già visto da qualche parte lo sha-1, poi mi è venuto in mente che era in winamp, e poi mi è venuta l'ispirazione per scrivere questo essay ;)
ovviamente per chiarimenti, migliorie o correzioni mandatemi una mail.
ci vediamo al prossimo essay... bye.
bender0
Disclaimer |
Vorrei ricordare che il software va comprato e non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento è stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.