a85k CrackMe 001 | ||
Data |
by [ active85k ] |
|
14/09/2002 |
Published by Quequero | |
|
Mmmm il tute e' completo nonche' bello...Pero' l'hai fatto tu il crackme, mi sa che non vale :P sei come Vixie che prima scrive il crond e poi rilascia gli exploit per il suo crond hahahah :PPPP |
Un passerotto di 350 kg sul ramo di un albero fa: CIIIIIIIIIIIIIIIIIIIIIIP! |
:) |
|
:) |
Difficoltà |
( )NewBies (X)Intermedio ( )Avanzato ( )Master |
Pronti per reversare il mio piccolo e primo CrackMe! Non ne avevo mai scritti prima d'ora! :)
Introduzione |
Tools usati |
IDA Disassembler v4.17 (ma va bene qualsiasi versione)
SoftICE v4.0 (ma va bene qualsiasi versione)
masm32 v7.0 (aaah! ma va bene qualsiasi versione anche di questo! :)
un cervello funzionale v5.0 (ma allora è un vizio! :-)
URL o FTP del programma |
Notizie sul programma |
Essay |
Bene, al lavoro! Iniziamo con l'avvio del nostro CrackMe per vedere di cosa si tratta e che effetto ci fa! Direi che sembra 'na cosa ben fatta. Ci sono due campi, uno per inserire il nostro nome, l'altro per inserire il nostro seriale. Iniziamo così a riflettere: è facilmente intuibile, soprattutto dalle dimensioni dell'eseguibile, che il programma è scritto in assembly, quindi, da adesso in avanti dobbiamo pensare in assembly.
Inizio ad inserire nel primo campo, un nome a caso (io ci inserisco "mattia") per vedere che cosa succede. Premo "Check!" e giustamente il programma bestemmia. La stessa cosa succede se inserisco un seriale di mia invenzione. Dobbiamo quindi arrivare al punto in cui il programma ritira il nome da noi immesso. Ci sono vari modi per ritirare il nome da un campo in assembly:
1. con la GetWindowTextA
2. con la GetDlgItemTextA (se si tratta di un proggy che prende la dialogbox dalle risorse)
3. usando il messaggio WM_GETTEXT con la SendMessageA o la SendDlgItemMessageA
Dobbiamo quindi andare a tentativi, quindi, entriamo in SoftICE (Ctrl+D) e mettiamo un breakpoint sulla prima chiamata digitando, nella riga di comando, "bpx GetWindowTextA". Premiamo di nuovo Ctrl+D per tornare in Windows. Bene, non ci resta che provare. Mettiamo di nuovo un nome, (io ci metto di nuovo "mattia") e un serial a casaccio (io ci metto "12345678"). Premiamo su "Check!" ED ECCO... che non succede proprio nulla! Il programma, imperterrito, ci manda nuovamente a quel paese! Quindi ritorniamo nuovamente in SoftICE, eliminiamo il breakpoint che abbiamo messo ("bc *") e proviamo a breakare sulla seconda chiamata ("bpx GetDlgItemTextA"). Ritorniamo nuovamente sul proggy e ripetiamo la storia: nome="mattia", serial="12345678", premiamo su "Check!". A questo punto credo di dover specificare che, in questo caso, SoftICE popperà solo se il nome è almeno di 10 caratteri, ma ce ne accorgeremo anche dopo. Allora mettiamo un nome di almeno 10 caratteri e ripremiamo su "Check!" Ecco che compare SoftICE che ci riempie di gioia! :) Quindi premiamo F11 per visualizzare la porocedura che ha eseguito il programma. Ecco, ci troviamo esattamente dopo una chiamata a GetDlgItemTextA, quindi, tra i parametri pushati dobbiamo risalire a quello che contiene il nome da noi inserito per vedere che cosa ha combinato. La GetDlgItemText ha la seguente sintassi:
UINT GetDlgItemText(
HWND hDlg,
// Handle identificativo della finestra
int
nIDDlgItem, // Numero identificativo del campo contenente il
testo
LPTSTR
lpString, // Indirizzo della stringa in cui verrà messo il testo
int nMaxCount
// Numero massimo dei caratteri che verranno catturati
);
Una volta analizzata la sintassi di questa call, andiamo ad analizzare il codice assembly eseguito dal programma: ricapitolando, inseriamo come nome "mattia mattia" (13 caratteri > 10), come serial "12345678" e premiamo il tasto "Check". Comparso SoftICE, premiamo F11 per la procedura principale. Ci troviamo, quindi, in questo punto di codice, che analizzeremo seguendo, quindi, il modello LIFO:
...
0177:004011AE 6A1E PUSH 1E // nMaxCount
0177:004011B0 68E6314000 PUSH 004031E6 // lpString
0177:004011B5 68BA0B0000 PUSH 00000BBA // nIDDlgItem
0177:004011BA FF7508 PUSH DWORD PTR [EBP+08] // hDlg
0177:004011BD E8D2000000 CALL USER32!GetDlgItemTextA // Chiamata
...
Questa è la parte di codice che, almeno in teoria, dovrebbe ritirare un testo di, al max 1Eh (= 30) caratteri e mettere il testo ritirato in 004031E6. Quindi, portiamo avanti la nostra curiosità e vediamo che diavolo ha ritirato. Rientriamo in SoftICE e breakiamo sulla procedura. Premiamo F11 e digitiamo "d 004031E6". Una volta premuto invio, in basso a destra, vediamo cosa contiene la locazione 004031E6. Osserviamo e vediamo che prima c'è il nostro seriale, successivamente seguito da un altro numero... e che numero è? Così, su due piedi, sembrerebbe... un seriale! Incuriositi, prendiamo carta e penna, ricopiamo lo strano seriale e inseriamolo nel nostro programmino lasciando sempre il nome "mattia mattia". Premiamo "Check!" e... Dio santo! Il seriale è giusto! Ma vieni!!! Ma vai!!! EVVIVAAAA!! Aspettate un attimo! Noi non volevamo fare questo! Fate attenzione: la chiamata non ha ritirato il nome per generare un seriale valido, ma tutt'altra cosa! Ha ritirato il nostro seriale, e la locazione conteneva già il giusto seriale generato dal proggy! Quindi questo significa che con la GetDlgItemTextA siamo andati più avanti di quanto speravamo! Il nome non lo abbiamo mai trovato! Questo significa che non è la chiamata giusta su cui breakare! Azz, 'sto reversing è veramente 'na palla al piede! Cmq non disperate. Tra le chiamate di prima, ne abbiamo saltata una: la SendMessage. E' la nostra ultima speranza! Entriamo in SoftICE, mettiamo l'ennesimo breakpoint su SendMessageA "bpx SendMessageA", usciamo da SoftICE, mettiamo il nome "mattia mattia", il serial "12345678" e premiamo di nuovo "Check!" (azz, 'sto pulsante si sta consumando a forza di premerlo! :). Ecco qua! SoftICE poppa, trionfante più che mai! Chissà se stavolta abbiamo fatto bene! Premiamo F11 e scorriamo la schermata più sopra di qualche riga. Dobbiamo quindi analizzare la SendDlgItemMessage e il messaggio WM_GETTEXT, che serve per ritirare il testo di un campo. Ecco tutte le sintassi di queste API:
LONG SendDlgItemMessage(
HWND hDlg, // Handle
identificativo della finestra
int nIDDlgItem, // Campo a cui mandare il messaggio
UINT Msg, //
Messaggio da mandare
WPARAM wParam, // Primo parametro richiesto dal
messaggio
LPARAM lParam // Secondo parametro
richiesto dal messaggio
);
Se andiamo a guardare il codice, il messaggio che è stato mandato è il parametro centrare fra i cinque. In questo caso, come vediamo sotto, è stato pushato 0Dh. Ebbene, questo parametro corrisponde al WM_GETTEXT. Abbiamo fatto centro! Come potete notare, ogni messaggio richiede due parametri. Quindi, dobbiamo andare a vedere quali parametri richiede il WM_GETTEXT:
WM_GETTEXT
wParam = (WPARAM) cchTextMax; // Numero, al
max, di caratteri da catturare
lParam = (LPARAM) lpszText; //
Indirizzo nel quale verrà inserito il testo catturato
Bene, adesso abbiamo tutto quello che ci serve per capire il codice assembly di questa diamine di procedura.
...
0177:004010E0 68C8314000 PUSH 004031C8 // Parametro2
0177:004010E5 6A1E PUSH 1E // Parametro1
0177:004010E7 6A0D PUSH 0D // WM_GETTEXT ;)
0177:004010E9 68B90B0000 PUSH 00000BB9 // nIDDlgItem
0177:004010EE FF7508 PUSH DWORD PTR [EBP+08] // hDlg
0177:004010F1 E8B0010000 CALL USER32!SendDlgItemMessageA // Chiamata
...
Vediamo se abbiamo capito bene: questa chiamata manda il WM_GETTEXT ad un campo contenente un testo. Di questo testo verranno catturati i primi 1Eh (= 30) caratteri, e il testo catturato verrà messo in 004031C8. Ecco, adesso dobbiamo nuovamente andare a vedere che diavolo ha messo in questa locazione. Entriamo in SoftICE, breakiamo, premiamo F11 e digitiamo "d 004031C8". Perfetto! In basso a destra vediamo che la locazione contiene il nostro nome! (nel mio caso "mattia mattia"). In poche parole, tutta 'sta storia serviva solo per capire da che punto dobbiamo incominciare a mettere in funzione le nostre amate cervella! =) Carta e penna (oppure il notepad.exe come faccio io) e scriviamoci l'indirizzo da cui parte il tutto (cioè dal primo parametro pushato = 0177:004010E0). Dell'indirizzo, serve solo la seconda parte, quindi scriviamo solo "004010E0". Adesso è arrivato il turno del nostro vecchio e caro disassembler! Io ho deciso di usare IDA perché... è più difficile? Bah, diciamo di si: ho scelto IDA perché è più difficile! Ma nooooo! Perché con IDA abbiamo la possibilità di rinominare a piacimento le nostre variabili! ;)
Molto bene, per ora, ci stiamo dentro! Adesso impareremo ad utilizzare IDA o almeno le basi ;). Apriamo il disassembler e loadiamo il nostro eseguibile. All'inizio ci verrà chiesto di che tipo di eseguibile si tratta, e dovrete selezionare "Portable Executable for IBM PC" (che poi è sià selezionato ;) e premere OK per avviare la procedura di disassembly. Attendete 1 millesimo di secondo, fino a quando, nel pannello in basso, non comparirà la riga "The initial autoanalysis is finished.". A questo punto il proggy è stato disassemblato. Adesso dobbiamo arrivare al punto in cui inizia la procedura di calcolo del seriale. In IDA, quindi, premiamo il tasto "G" (Go to) e, nel pannello che comparirà, dovete inserire l'indirizzo che avete precedentemente scritto (004010E0). Premete OK e cavalcate! Ci troviamo proprio in groppa all'algoritmo! Adesso dovete chiudere Winamp perché la musica ci disturba in quanto siamo arrivati alla parte cruciale della cosa! Vi riporterò sotto il codice assembly di IDA e vi spiegherò, riga dopo riga, tutte le operazioni che vengono fatte dal proggy per calcolare il seriale. Le mie spiegazioni saranno le scritte colorate e, in base al colore, si tratterà di micro-funzioni differenti. Fate molta attenzione perché, dopo questa spiegazione, scriveremo il KeyGen secondo le informazioni ricavate da tutta la pappa! :)
push offset Nome ; lParam Ho rinominato la variabile
chiamandola Nome
push 1Eh ; wParam
per rendere più comprensibile la lettura del
push 0Dh ; Msg
listato.
push 0BB9h ; nIDDlgItem
push [ebp+hDlg] ; hDlg
call SendDlgItemMessageA Questa è la chiamata che
prende il nome
cmp eax, 0Ah
Se il nome è lungo almeno 10 caratteri bene,
+----
jnb short loc_0_40111E altrimenti il
proggy vi manda a farvi... 'na pizza :)
|
push 10h ; uType
|
push offset aA85kCrackme ; lpCaption
|
push offset aInvalidNameOrS ; lpText
|
push [ebp+hDlg] ; hWnd
|
call MessageBoxA Questa chiamata ci
manda a farci fottere
|
push dword_0_4031C4 ; hWnd
|
call SetFocus
|
leave
|
retn 10h
|
+--->
loc_0_40111E:
xor ecx, ecx
Azzera ECX per usarlo come contatore
+------>
loc_0_401120:
|
mov al, byte ptr Nome[ecx]
Copia in AL l'ECXesimo carattere del Nome
|
cmp al, 0
Se il nome è finito
|
+---- jz short loc_0_401139
Allora passa avanti
|
| cmp al, 5Ah
Se il carattere del nome è minuscolo
|
| +-- jbe short
loc_0_401130 (altrimenti passa avanti)
<-------------------+
|
| | sub
al, 20h
Allora lo fa diventare maiuscolo (char -20h) -+
|
| |
|
| +-> loc_0_401130: ;
CODE XREF: sub_0_401061+CB j
|
| mov byte ptr Nome[ecx],
al Sostituisce il char minuscolo con quello
maiuscolo
|
| inc ecx
Incrementa di 1 il contatore per il prossimo char
+--+---- jmp short
loc_0_401120 Torna
indietro per analizzare il prossimo char.
|
|
[ in poche parole la funzione di sopra non fa altro che
trasformare ]
| [ il nome da minuscolo in maiuscolo. Quando la riscriveremo, la fa- ]
| [ remo molto più comprensibile di questa qua ;) ]
|
+---> loc_0_401139: ; CODE XREF: sub_0_401061+C7 j
xor ecx, ecx Azzera ECX
xor ebx, ebx Azzera EBX
+--------> loc_0_40113D: ; CODE
XREF: sub_0_401061+10B j
|
mov al, byte ptr Nome[ecx] Mette in AL l'ECXesimo
carattere del Nome maiuscolo
|
cmp cl, 4
Se siamo arrivati al quinto carattere del nome
|
+---- jz short loc_0_40116E
allora passiamo avanti altrimenti continua :)
|
|
|
| loc_0_401148: ; CODE XREF: sub_0_401061+F0 j
|
| cmp al, byte ptr a1qaz2wsx3edc4r[ebx]
Questa funzione compara il nostro char
|
| +-- jz short loc_0_401153
con i chars presenti in una stringa che contiene tutti
|
| | inc
ebx i chars che
possiamo usare. Quando lo trova, salta alla funzione
|
| +-- jmp short loc_0_401148
successiva. Ad es: se il nostro char
corrisponde al
|
| |
sesto char di questa stringa, EBX diventa ugualea 6.
| | | Per visualizzare l'intero contenuto della str, dovete andarci sopra col
| | | cursore (io ho colorato la stringa di bianco) e premere INVIO. Poi, una
|
|
| volta copiato il
contenuto, premete ESC per ritornare alla procedura.
|
| |
|
| | loc_0_401153:
; CODE XREF: sub_0_401061+ED j
|
| +-> jmp short
loc_0_401158
|
| |
|
| |
|
| | loc_0_401155:
; CODE XREF: sub_0_401061+FA j
|
| | sub
ebx, 9 <---------------------------------------+ Sottrae 9
ad EBX
|
| |
|
|
| +->
loc_0_401158: ; CODE XREF: sub_0_401061+F2 j
|
|
| cmp ebx, 9
Se EBX è più grande di 9
|
|
| ja short loc_0_401155
allora salta a -------------+
|
| mov dl, byte ptr a0123456789[ebx]
Copia in DL l'EBXesimo
carattere di una str
|
| mov byte ptr unk_0_403204[ecx], dl
piena di numeri e lo mette nel serial corrett
|
| inc ecx
Incrementa di 1 ECX (contatore)
|
| xor ebx, ebx
Riazzera EBX
+----+----
jmp short loc_0_40113D
Salta indietro per ripetere l'operazione con
|
il carattere successivo
|
+--->
loc_0_40116E: ; CODE XREF: sub_0_401061+E5 j
[ A
questo punto abbiamo ECX = 4, cioè rappresenta il 5° carattere del serial corretto.
]
[ 2Dh
= "-") per formare un serial di
questo tipo: ####- (# = numero).
]
mov byte ptr unk_0_403204[ecx], 2Dh Mette un
trattino al 5° char del Serial
inc ecx
Incrementa di 1 ECX
mov esi, offset Nome ESI
diventa puntatore al nome
+---------->
loc_0_40117B: ; CODE XREF: sub_0_401061+13B j
|
cmp ecx, 0Eh
Se ECX non è uguale a 0Eh (= 14)
|
+--- jnz short loc_0_401182
allora salta in loc_0_401182
| +-----+---
jz short loc_0_40119E altrimenti
salta in loc_0_40119E
| | |
| |
+--> loc_0_401182: ; CODE XREF: sub_0_401061+11D j
| | mov al, [esi]
Muove in AL l'ESIesimo carattere del nome
| | xor al, cl
xora il carattere con la sua posizione all'interno del
nome
| | cmp al, 5Ah
Se il char
xorato è minore o uguale a 5Ah
| |
+--- jbe short loc_0_40118E
Allora salta, altrimenti...
| |
| sub al, 8
...sottrae 8 al carattere
| |
+---+--- jmp short loc_0_401194
| |
| |
| |
| |
| |
| +--> loc_0_40118E: ; CODE XREF: sub_0_401061+127 j
| |
| cmp al, 30h
Se AL è maggiore di 30h
| |
+------- jnb short loc_0_401194
allora salta,
| |
| add al, 0Ah
altrimenti, aggiunge 0Ah (= 10( al carattere
| |
|
| |
+------> loc_0_401194: ; CODE XREF: sub_0_401061+12B j
| | ; sub_0_401061+12F j
| | mov byte ptr unk_0_403204[ecx], al
Muove AL nell'ECXesima posizione del serial
| | inc esi
Incrementa ESI di 1 (passa al char success)
| | inc ecx
Incrementa ECX di 1 (char success del serial)
+-+--------- jmp short loc_0_40117B
Ritorna per analizzare il prossimo char.
|
|
+--------> loc_0_40119E: ; CODE XREF: sub_0_401061+11F j
add cl, 20h
Aggiunge 20h a CL
mov byte ptr unk_0_403204[ecx], cl
Mette CL nel Serial da lui generato
mov byte ptr unk_0_403205[ecx], 0
Pone fine al suo serial mettendo uno zero.
[ In pratica, nella nostra attuale situazione, potremmo anche breakare su 0040119E ]
[ e scendere tre righe più sotto per sniffare il seriale valido con il comando "D", ]
[ ma noi dobbiamo diventare dei reverser! Quindi dobbiamo scrivere il KeyGen. ]
[ Non commenterò il codice qua sotto perché è inutile. Vi farò capire meglio più ]
[ giù. Questo codice guardatelo solo per avere una vaga idea di quello che fa :) ]
push 1Eh ; nMaxCount
push offset unk_0_4031E6 ; lpString
push 0BBAh ; nIDDlgItem
push [ebp+hDlg] ; hDlg
call GetDlgItemTextA
Questa è la chiamata su cui avevamo breakato per sbaglio
la prima volta :)
cmp eax, 0Eh
jb short loc_0_4011CC
cmp eax, 0Eh
jbe short loc_0_4011E2
loc_0_4011CC: ; CODE XREF: sub_0_401061+164 j
push 10h ; uType
push offset aA85kCrackme ; lpCaption
push offset aInvalidNameOrS ; lpText
push [ebp+hDlg] ; hWnd
call MessageBoxA
jmp short locret_0_401230
loc_0_4011E2: ; CODE XREF: sub_0_401061+169 j
mov esi, offset unk_0_403204
mov edi, offset unk_0_4031E6
push offset unk_0_4031E6 ; lpString2
push offset unk_0_403204 ; lpString1
call lstrcmpA
or eax, eax
jnz short loc_0_40121C
push 40h ; uType
push offset aA85kCrackme ; lpCaption
push offset aGoodWorkYourSe ; lpText
push [ebp+hDlg] ; hWnd
call MessageBoxA
push 0 ; nExitCode
call PostQuitMessage
jmp short locret_0_401230
loc_0_40121C: ; CODE XREF: sub_0_401061+19C j
push 10h ; uType
push offset aA85kCrackme ; lpCaption
push offset aInvalidNameOrS ; lpText
push [ebp+hDlg] ; hWnd
call MessageBoxA
locret_0_401230: ; CODE XREF: sub_0_401061+17F j
; sub_0_401061+1B9 j
leave
retn 10h
Fffiù! Ragazzi che sudata! ma finalmente abbiamo finito! e naturalmente sto scherzando, perché c'è ancora da scrivere il generatore di chiavi! Dio santo, non volete proprio fare niente, eh? :). Dopo che il proggy ha messo uno zero alla fine del suo serial, possiamo facilmente capire che, finalmente lo ha generato tutto! Quindi, in teoria, il tutorial potrebbe finire qua... ma in questo modo dove sarebbe la bravura e la costanza del nostro bravo scrittore??? ;) Le righe di codice che non ho commentato servono solo per comparare il nostro seriale con quello generato dal programma. Subito dopo, il proggy deve vedere se mandarci a cagare oppure congratularsi con noi!. I due seriali vengono comparati con una lstrcmp: se sono uguali, allora il CrackMe si congratula con noi e poi si chiude per evitare di insultarci alla chiusura manuale del programma, atrimenti ci manda a cagare con una messagebox.
Adesso è arrivato il momento del Coding! Vi scrivo sotto il codice del generatore di chiavi per questo crackme. Logicamente questa volta non commento per due motivi: 1) perché ho già commentato sopra, 2) perché quello scritto da me è molto più comprensibile del listato di IDA ;). Vi riporto sotto il codice dell'intero KeyGen in masm32. Se lo prendete e lo compilate, funziona alla grande! ;)
.386
.model flat, stdcall
option casemap: none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD
.data
AppName db "CrackMe 001 - KeyGen", 0
ClassName db "MainWindowClass", 0
EditClassName db "EDIT", 0
ButtonClassName db "BUTTON", 0
Button1Caption db "Create Key", 0
Button2Caption db "Exit", 0
Corto db "Il nome deve essere almeno
di 10 caratteri!", 0
Numb db "0123456789", 0
Chars db
"1QAZ2WSX3EDC4RFV5TGB6YHN7UJM8IK9OL0P ", 0
.data?
hInstance HINSTANCE ?
Edit1 HWND ?
Edit2 HWND ?
Button1 HWND ?
Button2 HWND ?
UserName db 30 dup (?)
MySerial db 30 dup (?)
.code
Start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL,NULL,
SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain PROC hInst: HINSTANCE, hPrevInst: HINSTANCE, CmdLine:
LPSTR, CmdShow: DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or
CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR
ClassName,ADDR AppName,
DS_MODALFRAME
or WS_POPUP or WS_CAPTION or WS_SYSMENU,10, 15, 250, 130,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke
GetMessage, ADDR msg,NULL,0,0
.BREAK .IF
(!eax)
invoke
TranslateMessage, ADDR msg
invoke
DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain Endp
WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM,
lParam:LPARAM
.IF uMsg == WM_CLOSE
invoke
PostQuitMessage,NULL
.ELSEIF uMsg == WM_CREATE
invoke
CreateWindowEx, WS_EX_CLIENTEDGE, ADDR EditClassName, NULL,
WS_CHILD or
WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL,
10, 5, 220,
25, hWnd, NULL, hInstance, NULL
mov Edit1,
eax
invoke
CreateWindowEx, WS_EX_CLIENTEDGE, ADDR EditClassName, NULL,
WS_CHILD or
WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL,
10, 35, 220,
25, hWnd, NULL, hInstance, NULL
mov Edit2,
eax
invoke
CreateWindowEx, NULL, ADDR ButtonClassName, ADDR Button1Caption,
WS_CHILD or
WS_VISIBLE, 15, 65, 100, 30, hWnd, 3001, hInstance, NULL
mov Button1,
eax
invoke
CreateWindowEx, NULL, ADDR ButtonClassName, ADDR Button2Caption,
WS_CHILD or
WS_VISIBLE, 120, 65, 100, 30, hWnd, 3002, hInstance, NULL
mov Button2,
eax
invoke
SetFocus, Edit1
ret
.elseif uMsg == WM_COMMAND
.if wParam ==
3002
invoke SendMessage, hWnd, WM_CLOSE, NULL, NULL
ret
.elseif
wParam == 3001
mov eax, wParam
shr eax, 16
.if eax == BN_CLICKED
invoke SendMessage, Edit1, WM_GETTEXT, 30, ADDR UserName
.if eax < 10
invoke MessageBox, hWnd, ADDR Corto, ADDR AppName, MB_ICONERROR+MB_OK
ret
.endif
;*********************************************
;***** INIZIO CALCOLO DEL SERIALE VALIDO *****
;*********************************************
xor ecx, ecx
@@INIZIO:
mov al, byte ptr [UserName+ecx]
cmp al, 00h
jz @@STEP1
.if al > "Z"
sub al, 20h
.endif
mov byte ptr [UserName+ecx], al
inc ecx
jmp @@INIZIO
@@STEP1:
xor ecx, ecx
xor ebx, ebx
@@STEP2:
mov al, byte ptr [UserName+ecx]
cmp cl, 04h
jz @@FINE1
@@STEP3:
cmp al, byte ptr [Chars+ebx]
jz @@STEP4
inc ebx
jmp @@STEP3
@@STEP4:
.while ebx > 9
sub ebx, 9
.endw
mov dl, byte ptr [Numb+ebx]
mov byte ptr [MySerial+ecx], dl
inc ecx
xor ebx, ebx
jmp @@STEP2
@@FINE1:
mov byte ptr [MySerial+ecx], "-"
inc ecx
mov esi, OFFSET UserName
@@JUMP1:
.if ecx == 14
jz @@JUMP2
.endif
mov al, byte ptr [esi]
xor al, cl
.if al > "Z"
sub al, 08
.elseif al < "0"
add al, 10
.endif
mov byte ptr [MySerial+ecx], al
inc esi
inc ecx
jmp @@JUMP1
@@JUMP2:
add cl, 20h
mov byte ptr [MySerial+ecx], cl
mov byte ptr [MySerial+ecx+1], 00h
invoke SetWindowText, Edit2, ADDR MySerial
.endif
.endif
.else
invoke
DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end Start
Note finali |
Ecco fatto! Abbiamo finito tutto! Compilate il vostro proggy, avviatelo, inserite un nome di almeno 10 caratteri, cliccate su "Create Key" e festeggiate come tanti animali impazziti! Beh, mi rendo conto che come prima volta... ho creato un crackme abbastanza rompiballe, bah... cercherò di migliorare. Spero che il mio lavoro vi sia piaciuto (anche perché ci ho messo tre notti di fila per farlo :P). Ringrazio di nuovo AndreaGeddon, Quequero e tutta la U.I.C. con la promessa di scrivere altri tutes ;).
Un saluto
[ active85k ]
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.