Bonjour à tous!
Pour mon premier post sur Re-Xe, je vous propose un petit tuto qui vise surtout les débutants en RE.
Il s’agit ici d’exploiter un simple petit KeyGenMe, en l’analysant puis en codant rapidement un petit KeyGen.
Vous pouvez trouver le KeygenMe ici : https://www.re-xe.com//uploads/2011/04/progressive_keygenme_1.zip
Si on l’execute, on aperçoit une simple fenêtre, avec deux champs de texte: un pour le nom et un pour le serial, ainsi que deux boutons.
Essayons de rentrer des infos au hasard.
Pour ma part, j’ai testé avec ‘ryscrow’ comme nom, et ‘123456789’ en serial. Appuyez sur Check, et normalement (sauf si vous avez une chance d’enfer et que vous avez réussi à trouver le serial correspondant au hasard du premier coup) la réponse ne tarde pas à tomber, avec une fenêtre qui s’ouvre indiquant: « Et non… Retente ta chance ».
Le but va donc être de trouver un serial correspondant au nom entré, et de réussir à trouver la routine pour le générer à partir de n’importe quel nom.
La première chose à vérifier, c’est que l’executable n’est pas packé ni crypté. Pour celà, un simple outil comme PEiD suffit.
On lance PEiD, on ajoute l’executable à tester, et PEiD nous informe que rien n’a été trouvé. (ce qui est normal pour un KeyGenMe destiné aux débutants…)
On va donc ici utiliser OllyDBG pour reverser notre programme.
Une fois lancé, OllyDBG nous place directement sur le point d’entrée du programme, à l’adresse 0x0401000.
Dans ce cas précis, le code désassemblé est suffisament clair pour qu’on puisse se passer de debug.
Les choses intéressantes commencent lors de l’appel à la fonction GetDlgItemTextA.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 0040106B |. 83F8 05 CMP EAX,5 0040106E |. 72 7E JB SHORT 004010EE 00401070 |. 83F8 14 CMP EAX,14 00401073 |. 0F87 8C000000 JA 00401105 00401079 |. 89C1 MOV ECX,EAX 0040107B |. 8D35 00204000 LEA ESI,[402000] 00401081 |. 31DB XOR EBX,EBX 00401083 |> 0FB606 /MOVZX EAX,BYTE PTR [ESI] 00401086 |. 01C3 |ADD EBX,EAX 00401088 |. 46 |INC ESI 00401089 |.^ E2 F8 \LOOPD SHORT 00401083 0040108B |. 53 PUSH EBX ; /<%i> 0040108C |. 68 63204000 PUSH 00402063 ; |Format = "%i" 00401091 |. 68 42204000 PUSH 00402042 ; |s = progress.00402042 00401096 |. FF15 C2304000 CALL [<&USER32.wsprintfA>] ; \wsprintfA 0040109C |. 6A 20 PUSH 20 ; /Count = 20 (32.) 0040109E |. 68 21204000 PUSH 00402021 ; |Buffer = progress.00402021 004010A3 |. 6A 66 PUSH 66 ; |ControlID = 66 (102.) 004010A5 |. FF75 08 PUSH DWORD PTR [EBP+8] ; |hWnd 004010A8 |. FF15 BE304000 CALL [<&USER32.GetDlgItemTex>; \GetDlgItemTextA 004010AE |. 68 21204000 PUSH 00402021 ; /String2 = "" 004010B3 |. 68 42204000 PUSH 00402042 ; |String1 = "" 004010B8 |. FF15 6A304000 CALL [<&KERNEL32.lstrcmp>] ; \lstrcmpA 004010BE |. 75 17 JNZ SHORT 004010D7 004010C0 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 004010C2 |. 68 66204000 PUSH 00402066 ; |Title = "Progressive KeygenMe #1" 004010C7 |. 68 7E204000 PUSH 0040207E ; |Text = "Bravooo !!!",LF,CR,"Maintenant code un keygen et si t'es",LF,CR,"motiv",E9," un tutorial est le bienvenu." 004010CC |. FF75 08 PUSH DWORD PTR [EBP+8] ; |hOwner 004010CF |. FF15 C6304000 CALL [<&USER32.MessageBoxA>] ; \MessageBoxA 004010D5 |. EB 67 JMP SHORT 0040113E 004010D7 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 004010D9 |. 68 66204000 PUSH 00402066 ; |Title = "Progressive KeygenMe #1" 004010DE |. 68 D5204000 PUSH 004020D5 ; |Text = "Et non...",LF,CR,"Retente ta chance" 004010E3 |. FF75 08 PUSH DWORD PTR [EBP+8] ; |hOwner 004010E6 |. FF15 C6304000 CALL [<&USER32.MessageBoxA>] ; \MessageBoxA 004010EC |. EB 50 JMP SHORT 0040113E 004010EE |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 004010F0 |. 68 66204000 PUSH 00402066 ; |Title = "Progressive KeygenMe #1" 004010F5 |. 68 21214000 PUSH 00402121 ; |Text = "Le nom doit faire au moins 5 caract",E8,"res" 004010FA |. FF75 08 PUSH DWORD PTR [EBP+8] ; |hOwner 004010FD |. FF15 C6304000 CALL [<&USER32.MessageBoxA>] ; \MessageBoxA 00401103 |. EB 39 JMP SHORT 0040113E 00401105 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 00401107 |. 68 66204000 PUSH 00402066 ; |Title = "Progressive KeygenMe #1" 0040110C |. 68 F2204000 PUSH 004020F2 ; |Text = "Le nom ne doit pas faire plus de 20 caract",E8,"res" 00401111 |. FF75 08 PUSH DWORD PTR [EBP+8] ; |hOwner 00401114 |. FF15 C6304000 CALL [<&USER32.MessageBoxA>] ; \MessageBoxA 0040111A |. EB 22 JMP SHORT 0040113E 0040111C |> 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL 0040111E |. 68 49214000 PUSH 00402149 ; |Title = "About" 00401123 |. 68 4F214000 PUSH 0040214F ; |Text = "Progressive KeygenMe #1",LF,CR,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,"",AF,> 00401128 |. FF75 08 PUSH DWORD PTR [EBP+8] ; |hOwner 0040112B |. FF15 C6304000 CALL [<&USER32.MessageBoxA>] ; \MessageBoxA |
En analysant un peu, on se rend compte que le gros de l’algorithme de génération du serial tient en 11 lignes de code:
1 2 3 4 5 6 7 8 9 10 11 | 0040106B |. 83F8 05 CMP EAX,5 0040106E |. 72 7E JB SHORT 004010EE 00401070 |. 83F8 14 CMP EAX,14 00401073 |. 0F87 8C000000 JA 00401105 00401079 |. 89C1 MOV ECX,EAX 0040107B |. 8D35 00204000 LEA ESI,[402000] 00401081 |. 31DB XOR EBX,EBX 00401083 |> 0FB606 /MOVZX EAX,BYTE PTR [ESI] 00401086 |. 01C3 |ADD EBX,EAX 00401088 |. 46 |INC ESI 00401089 |.^ E2 F8 \LOOPD SHORT 00401083 |
Les 4 premières lignes contrôlent le nombre de caractères du « Name », nombre stocké dans le registre EAX.
Si EAX < 5 (donc 5 en décimal), on saute vers l’instruction qui affiche un message d’erreur. Si EAX > 14 (donc 20 en décimal), on saute vers l’instruction qui affiche un autre message d’erreur.
La 5ème instruction place le contenue du registre EAX dans ECX.
La 6ème place dans ESI un pointeur vers l’adresse où est stocké « Name » (402000)
La 7ème instruction remet à 0 le registre EBX.
Les 4 dernières instructions forment une boucle qui pourrait se traduire ligne par ligne par:
Placer l'octet vers lequel pointe ESI dans EAX (implicitement: Tant que celà est possible, la boucle se termine à la fin de la chaine de caractères.) EBX = EBX + EAX // Ajouter à EBX la valeur de EBX Incrémenter i Retourner au début
La suite du code se contente de comparer la valeur obtenue par traitement du Name avec le sérial donné, et de nous rediriger en fonction du résultat de cette comparaison.
Donc après réflexion, l’algo n’est pas si compliqué que ça: il se contente d’additioner les valeurs décimales de chaque caractères du « Name ».
Voici un petit KeyGen que j’ai codé en C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Et voici l’utilisation :
Et donc :
Et voilà, cet article est fini 😀 J’espère qu’il vous aura aidé.
Si vous avez la moindre question, n’hésitez pas à poster des commentaires !
Yo nigga
les valeurs décimales de chaque caractères du « Name ». // loop -> addition de chaque chars du nom en hex !
le décimal que tu parle de c’est %i
i: signed decimal integer. This value is equivalent to d.
(le output du serial et en décimal)
pour résumé: les calcules sont en hex mais le output et en dec
allez un keygen en assembleur car le c en console ça sucks:
tapz.asm:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
.model flat, stdcall
option casemap :none ; case sensitive
include windows.inc
uselib MACRO libname
include libname.inc
includelib libname.lib
ENDM
uselib user32
uselib kernel32
DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
IDC_OK equ 1003
IDC_IDCANCEL equ 1004
.data
szFormat db "%i",0
szSizeMin db "Le nom doit faire au moins 5 caractères",0
szSizeMax db "Le nom ne doit pas faire plus de 20 caractères",0
szCap db "Progressive KeygenMe #1 KEYGEN",0
.data?
hInstance dd ? ;dd can be written as dword
szName db 256 dup(?)
szCode db 256 dup(?)
.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam, hInstance, 101, 0, ADDR DlgProc, 0
invoke ExitProcess, eax
; -----------------------------------------------------------------------
DlgProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
.if uMsg == WM_COMMAND
.if wParam == IDC_OK
; -----------------------------------------------------------------------
; TODO
; -----------------------------------------------------------------------
invoke GetDlgItemText,hWin,1001,addr szName,sizeof szName
CMP EAX,5
JB @MinSize
CMP EAX,014h
JA @MaxSize
MOV ECX,EAX
LEA ESI,offset szName
XOR EBX,EBX
@progress_00401083:
MOVZX EAX,BYTE PTR DS:[ESI]
ADD EBX,EAX
INC ESI
LOOPD @progress_00401083
PUSH EBX
PUSH offset szFormat ; ASCII "%i"
PUSH offset szCode
CALL wsprintf
invoke SetDlgItemText,hWin,1002,addr szCode
ret
@MinSize:
invoke MessageBox,hWin,addr szSizeMin,addr szCap,MB_ICONEXCLAMATION
RET
@MaxSize:
invoke MessageBox,hWin,addr szSizeMax,addr szCap,MB_ICONEXCLAMATION
RET
.elseif wParam == IDC_IDCANCEL
invoke EndDialog,hWin,0
.endif
.elseif uMsg == WM_CLOSE
invoke EndDialog,hWin,0
.endif
xor eax,eax
ret
DlgProc endp
end start
tapz.rc:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define IDC_OK 1003
#define IDC_CANCEL 1004
101 DIALOGEX 0,0,169,44
CAPTION "Base"
FONT 8,"Tahoma"
STYLE 0x80c80880
EXSTYLE 0x00000000
BEGIN
CONTROL "OK",IDC_OK,"Button",0x00000001,110,5,50,14,0x00000000
CONTROL "Cancel",IDC_CANCEL,"Button",0x00000000,110,23,50,14,0x00000000
CONTROL "",1001,"Edit",0x00000080,7,7,90,12,0x00000200
CONTROL "",1002,"Edit",0x00000080,7,24,90,12,0x00000200
END
see ya!
J’ai oublié un truc: joyeux noël