Introduction:
Dans ce tutoriel nous allons keygenner E*x*e L*o*c*k v10.0.0
Les outils:
OllyDbg v2.01 (http://Ollydbg.de/)
Detect It Easy (https://github.com/horsicq/DIE-engine/releases)
G*i*l*i*S*o*f*t E*x*e L*o*c*k v10.0.0 (https://mega.nz/file/YQAEiT4C#....)
I: Démarrage
Installez l'application, le programme d'installation vous demandera de redémarrer votre ordinateur, cliquez sur non.
Une fois installé, scanner l'exécutable principal (ExeLock.exe) avec DiE pour voir s'il est compressé, on ne dirait pas, cool.
Ouvrons l'application et essayons de nous enregistrer avec un faux numéro de série pour voir le comportement.
Nous avons un message qui nous indique que la longueur du sérial n'est pas bonne.
Ok cela nous suffira.
II: Trouver la procédure de calcul
Chargez l'application dans le débogueur et lancez-la complètement avec F9.
Entrez à nouveau un faux numéro de série pour avoir à nouveau le message "Invalid regcode length." Et mettez le débogueur en pause.
Une fois en pause, faites ALT+F9, ou depuis le menu d'olly : debug>Execute till user code
Maintenant que l'exécution a repris, cliquez sur OK pour fermez le message "Invalid regcode length.".
Le débogueur break, nous sommes maintenant a l'offset 006A52E6, juste après l'appel à MessageBoxW
Après avoir regardé un peu la procédure actuelle, il semble que nous soyons sur le segment d'enregistrement !
Mettez donc un point d'arrêt au début de la procédure en cours : 006A50CC
Il est maintenant temps de tracer cette routine.
III: Comprendre la routine
On commence à tracer, on rencontre d'abord un "email check" appelé depuis une API de commondll.dll
Si c'est bon, nous prenons le saut conditionnel et atterrissons juste sous le JMP.
Si ce n'est pas bon alors le saut conditionnel n'est pas pris, un MessageBox est affiché et nous prenons le saut pour quitter le segment.
On continue à tracer et puis on a un "empty check" pour le champ du numéro de série. Le code est similaire à ce que l'on a vu précédemment, si c'est bon, nous prenons le saut conditionnel.
Après la vérification que le champ ne soit pas vide, nous avons un contrôle de longueur, notre numéro de série doit faire 35 caractères (23 en hexadécimal)
Notre longueur n'est pas bonne, alors corrigeons cela, mettons un point d'arrêt sur la ligne actuelle, puis reprenons l'exécution de l'application.
Fermez la MessageBox d'erreur, et corrigez votre sérial avec quelque chose du genre:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Et cliquez sur Register pour rebreak sur votre ligne.
Une fois les vérifications de longueurs passées, le sérial est tronqué dans une routine.
Où l'on peut voir :
MOV ECX,5 (saisis 5 caractères)
MOV EDX,0D (commencez à saisir à la position 13 sur la chaîne)
MOV EAX, DWORD PTR SS:[EBP-8] (la chaîne à tronquer, notre faux sérial)
Une fois cela fait, nous avons un deuxième CALL qui vérifie si c'est un chiffre ou non.
Et une fois cela fait, nous avons une comparaison en hard avec 5541 (21825 en décimale) contre les 5 caractères saisis dans notre sérial.
Notre numéro de série n'est pas bon, faisons donc le bon réglage pour passer cette étape.
Placez un point d'arrêt sur la comparaison, reprenez l'exécution et changez votre sérial en quelque chose du genre: AAAAAAAAAAAA21825AAAAAAAAAAAAAAAAAA
Puis revenez à votre CMP et nous pouvons maintenant continuer à tracer.
Une fois cette vérification en hard passée, nous passons sur une liste noire de sérial.
Puis nous traçons jusqu'à atteindre un API call "MS_CheckSN" contenu dans MagicSkin.dll, il semble que les choses intéressantes soient faites par cette dll.
Donc une fois que vous êtes dessus.. F7 pour entrer.
Nous pouvons voir la liste des imports avec quelques autres apis intéressants aux noms évocateurs.
Très bien, F7 à nouveau pour entrer dans MagicSkin.dll.
Une fois sur la dll, on continue à tracer, celle-ci est un peu plus compliquée à comprendre.
Mais on reconnaît facilement des choses en traçant ce que l'on a vu précédemment: le contrôle de longueur et le contrôle de la partie dure.
Et aussi une armée de numéros de série.
Après avoir passé les numéros de série, nous approchons de la fin du segment de MS_CheckSN, notre intérêt se porte à 00A01CB5.
Pour mieux comprendre ce qui se passe, mettons d'abord un point d'arrêt et reprenons/modifions notre numéro de série en quelque chose répondant aux attentes du développeur.
Par exemple: 11111-22222-21825-33333-44444-55555
Expliquons en traçant maintenant,
Nous rencontrons d'abord un appel à une procédure (CALL 00A040AC) celle-ci va mettre C3BC dans EAX (50108 en décimal)
MOV DWORD PTR SS:[EBP-28],EAX: C3BC est mis dans un buffer.
MOV EAX,DWORD PTR SS:[LOCAL.2]: Place '22222' de notre faux sérial dans EAX
ADD EAX,DWORD PTR SS:[LOCAL.10] fait une addition dans EAX, 22222+50108 (=11A8A, 72330 en décimal)
Ensuite, nous avons une division:
XOR EDX,EDX: Mets EDX à zéro
MOV ECX,1869F: Mets 1869F dans ECX (9999 en décimal)
DIV ECX: Divise ECX par 1869F, le résultat et EAX=0 et EDX=11A8A
Ensuite nous avons une comparaison:
CMP DWORD PTR SS:[LOCAL.8],EDX: compare '33333' de notre numéro de série contre 11A8A (72330 en décimal)
Après cela, nous avons un saut conditionnel qui est effectué si le résultat de la comparaison n'est pas égal.
Donc pour passer cette vérification en numéro de série il faudrait avoir: 11111-22222-21825-72330-44444-55555
Une fois cette première vérification passée, nous avons le même genre de calcul, mais cette fois avec la partie '11111' de notre numéro de série qui va être calculé et comparé à '44444' de notre numéro de série.
Le résultat de 11111+50108 est égal à 61219
Après la division, le résultat est encore comparé dans EDX.
Pour passer celui-ci, le numéro de série doit être: 11111-22222-21825-72330-61219-55555
Une fois cette deuxième vérification passée, la procédure de MS_CheckSN est terminée, on obtient EAX=1
Puis on revient au segment d'enregistrement, mais rien de spécial ne se passe ensuite hormis la décision du saut final sur le good boy/bad boy.
La partie '55555' de notre numéro de série n'est pas vérifiée et peut contenir n'importe quoi.
Nous avons terminé et nous sommes enregistrés si on reprend l'exécution.
Nous pouvons maintenant coder un keygen.
IV: Faire un keygen
Juste un peu d'aléatoire, d'addition et de division, rien d'extraordinaire.
Sur mon précédent tutoriel (Keygenner A*D S*t*r*e*a*m R*e*c*o*r*d*e*r v5.0), nous avons déjà vu un peu d'aléatoire avec GetLocalTime, cette fois nous allons utiliser GetTickCount pour changer.
Les numéros sont stockés dans une base szNumberz, et peut être utilisé simplement en faisant: invoke GenRandomNumbers,addr szBuffer,5
5 ici représente le nombre de caractères a généré dans szBuffer.
Les divisions longues sont à prendre en compte pour faire un keygen valide si vous souhaitez vous embêter avec ça.
par exemple: C537 (50487) + C3BC (50108) = 188F3 (100595)
Dans le cas présent notre dividende a 6 chiffres et notre diviseur en a 5 (99999).
En divisant 100595 par 99999, on obtient 1 comme quotient et 596 comme reste (dans edx)
Le programme va donc comparer 596 a votre sérial.
sérial valide: 50487-22222-21825-72330-596-5555555
La dernière partie du sérial n'étant pas vérifié on lui rajoute de la pagination pour atteindre les 35 caractères.
Ou sinon si vous ne souhaitez pas vous embêter avec ça (comme moi) et avoir un sérial harmonieux, vous faite un lenght check et si ça ne va pas on recalcule.
keygen.asm:
.486 .model flat, stdcall option casemap :none ; case sensitive include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include \masm32\include\shlwapi.inc include \masm32\macros\macros.asm includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\shlwapi.lib DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD GenRandomNumbers PROTO :DWORD,:DWORD NumbToStr PROTO :DWORD,:DWORD Randomize PROTO .const IDD_MAIN equ 1000 IDB_EXIT equ 1001 IDB_GEN equ 1002 IDC_DATE_STATIC equ 1003 IDC_SERIAL equ 1004 .data ; Keygen details szRndm dd 0 szNumberz db "0123456789",0 ; App detail szSerialDialog db "Software Registeration",0 szClassSerial db "TfrmReg",0 ; Dialog details szTitle db "GiliSoft Exe Lock v10.0.0 *keygen*",0 szIDBExit db "eXiT",0 szIDBGen db "gENERATE!",0 szDateStatic db "09/07/2021",0 .data? hInstance dd ? szSerial1 db 100h dup(?) szSerial2 db 100h dup(?) szFinalSerial db 100h dup(?) szSerialRand db 100h dup(?) buff db 11 dup(?) ; the maximum unsigned number ; stored by a DWORD = 4294967296 ( 10 chars ) ; size of the buffer = 10 + 1 ; the last character is the NULL terminator szSize DWORD ? windhand dd ? ; Window handle of the registration dlg .code start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,hInstance,IDD_MAIN,0,ADDR DlgProc,0 invoke ExitProcess,eax DlgProc proc hWnd :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD mov eax,uMsg .if eax == WM_INITDIALOG ; Set the dialog controls texts. Done here in the code instead of resource ; file to reduce the required bytes (strings in the rc file are UNICODE not ANSI) invoke SetWindowText,hWnd,addr szTitle ; Set the window title text invoke SetDlgItemText,hWnd,IDB_GEN,addr szIDBGen invoke SetDlgItemText,hWnd,IDB_EXIT,addr szIDBExit invoke SetDlgItemText,hWnd,IDC_DATE_STATIC,addr szDateStatic .elseif eax == WM_COMMAND mov eax,wParam .if eax == IDB_EXIT invoke SendMessage,hWnd,WM_CLOSE,0,0 .elseif eax == IDB_GEN @GenAgain: call clean invoke GenRandomNumbers,addr szSerial1,5 invoke lstrcpy,addr szFinalSerial,addr szSerial1 invoke lstrcat,addr szFinalSerial,chr$('-') invoke GenRandomNumbers,addr szSerial2,5 invoke lstrcat,addr szFinalSerial,addr szSerial2 invoke lstrcat,addr szFinalSerial,chr$('-21825-') invoke StrToInt,addr szSerial2 ; (shlwapi) add eax,50108 xor edx,edx mov ecx,01869Fh div ecx invoke NumbToStr,edx,addr buff invoke lstrcat,addr szFinalSerial,eax invoke lstrlen,addr szFinalSerial push eax mov szSize, eax .if szSize != 23 ;lenght check pop eax jmp @GenAgain .endif pop eax invoke RtlZeroMemory,addr szSize,sizeof szSize invoke lstrcat,addr szFinalSerial,chr$('-') invoke StrToInt,addr szSerial1 add eax,50108 xor edx,edx mov ecx,01869Fh div ecx invoke NumbToStr,edx,addr buff invoke lstrcat,addr szFinalSerial,eax invoke lstrlen,addr szFinalSerial push eax mov szSize, eax .if szSize != 29 ;lenght check pop eax jmp @GenAgain .endif invoke lstrcat,addr szFinalSerial,chr$('-') invoke GenRandomNumbers,addr szSerialRand,5 invoke lstrcat,addr szFinalSerial,addr szSerialRand invoke SetDlgItemText,hWnd,IDC_SERIAL,addr szFinalSerial ; Try to send serial infos to the app. invoke FindWindow,addr szClassSerial,addr szSerialDialog .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,263524,WM_SETTEXT,0,addr szFinalSerial .endif .endif .elseif eax == WM_CLOSE invoke EndDialog,hWnd,0 .endif xor eax,eax ret DlgProc endp NumbToStr proc uses ebx x:DWORD,buffer:DWORD mov ecx,buffer mov eax,x mov ebx,10 add ecx,ebx ; ecx = buffer + max size of string @@: xor edx,edx div ebx add edx,48 ; convert the digit to ASCII mov byte ptr[ecx],dl ; store the character in the buffer dec ecx ; decrement ecx pointing the buffer test eax,eax ; check if the quotient is 0 jnz @b inc ecx mov eax,ecx ; eax points the string in the buffer ret NumbToStr endp GenRandomNumbers proc uses ebx pIn:DWORD,pLen:DWORD mov edi,pIn mov ebx,pLen .repeat invoke Randomize mov ecx,10 ; Change this number to a new Alphabet size if your gonna modify it xor edx,edx idiv ecx movzx eax,byte ptr [edx+szNumberz] stosb dec ebx .until zero? ret GenRandomNumbers endp Randomize proc uses ecx invoke GetTickCount add szRndm,eax add szRndm,eax add szRndm,'abcd' rol szRndm,4 mov eax,szRndm ; imul eax,'seed' ret Randomize endp clean proc invoke RtlZeroMemory,addr szFinalSerial,sizeof szFinalSerial invoke RtlZeroMemory,addr szSerial1,sizeof szSerial1 invoke RtlZeroMemory,addr szSerial2,sizeof szSerial2 invoke RtlZeroMemory,addr szSerialRand,sizeof szSerialRand invoke RtlZeroMemory,addr szSize,sizeof szSize ret clean endp end start
keygen.rc:
;This Resource Script was generated by WinAsm Studio. #define IDD_MAIN 1000 #define IDB_EXIT 1001 #define IDB_GEN 1002 #define IDC_DATE_STATIC 1003 #define IDC_SERIAL 1004 IDD_MAIN DIALOGEX 10,10,184,43 FONT 8,"Tahoma" STYLE 0x90c80804 EXSTYLE 0x00000188 BEGIN CONTROL "",IDB_EXIT,"Button",0x10010000,127,28,51,13,0x00000000 CONTROL "",IDC_SERIAL,"Edit",0x50010801,3,9,177,12,0x00000200 CONTROL "",IDB_GEN,"Button",0x10010000,70,28,51,13,0x00000000 CONTROL "",IDC_DATE_STATIC,"Static",0x58000000,3,34,44,9,0x00000000 END
make.bat:
@echo off \masm32\bin\rc /v keygen.rc \masm32\bin\ml.exe /c /coff /Cp /nologo keygen.asm \masm32\bin\link.exe /SUBSYSTEM:WINDOWS /RELEASE /VERSION:4.0 /OUT:Keygen.exe keygen.obj keygen.res del keygen.res del keygen.obj pause
Une fois compilé, ça ressemble à ça:
C'est tout pour le moment!
Xylitol, 08/07/2021
Copyright (C)- xtx Team (2021)