Introduction:
Dans ce tutoriel nous allons voir comment faire un multi-keygen pour plusieurs produits différents du même éditeur.
Les outils:
OllyDbg v2.01 (http://Ollydbg.de/)
Detect It Easy (https://github.com/horsicq/DIE-engine/releases)
P*l*a*n*e*P*l*o*t*t*e*r v6.5.3.1 (http://www.coaa.co.uk/planeplotter6_5_3_1.exe)
I: Démarrage
La musique habituelle: installez l'application, scannez la avec DiE, ça ne semble pas compressé, super.
On ouvre l'application et une MessageBox apparais:
You are now on day 1 of your 21-day free trial period. Do you wish to register PlanePlotter to keep using it?
Si on clique sur 'Oui' on se retrouve avec un dialogue qui nous donne un Hardware ID (PP535249 pour moi) et nous demande d'entrer notre serial..
On rentre n'importe quoi, exemple: 1337
Sorry that registration number is incorrect. Email info@coaa.co.uk for help.
Bon on en a assez vu.
II: Trouver la procédure de calcul
Charger le fichier dans ollydbg.
Nous allons rechercher cette chaîne de mauvais serial, pour ça: clic droit>Search for>All referenced strings
On cherche "Sorry that registration" et on trouve 2 résultats, donc nous allons mettre un point d'arrêt sur les deux chaines.
Maintenant, nous exécutons le programme avec F9 et nous essayons de valider un numéro de série bidon.
Une fois validé nous atterrissons maintenant sur notre point d'arrêt en 0054AC57.
Si on se positionne sur l'instruction juste en dessous du saut, la fenêtre d'état du deboggueur nous dit qu'on vient de 0054AA0.
Voyons ce qui se passe à cette adresse avec un clic droit et ensuite: Go to JNE from 0054AA05
Si nous regardons où nous sommes maintenant, nous comprenons que c'est le segment où la décision est faite si le serial est valide ou non.
Nous avons une instruction CMP qui compare notre faux serial (1337) avec un pointeur à l'adresse ESP+44 (0012D9C0)
Si le résultat n'est pas égal, nous sautons et allons dans notre segment avec la messagebox "Sorry that registration number is incorrect"
Si le résultat est égal, le saut n'est pas effectué, puis il charge les chaînes de texte pour la version enregistrée.
Mais le problème c'est que ça ne nous avance pas à grand-chose.
Ok, c'est cool on a choppé le serial pour notre HID mais comment celui-ci a été calculé ?
Surtout que pendant le traçage aucune opération n'a été effectuée pour obtenir ce serial.
On va donc remonté avec une technique un peut crade, les breakpoints hardware en write sur la plage ou et stocké le bon serial. (0x12D9C0)
Donc, on en pose un puis on recharge l'appli et on F9 comme un porc jusqu'a voir apparaitre notre serial (AD01=429 pour moi)
Finalement on trouve ça:
Vous voyer le CALL juste avant ? Cliquons dessus et suivons-le.
C'est une petite procédure, mais c'est là que toute la magie est faite pour les calculs.
Voilà, on a trouvé ce que l'on cherchait.
Pour faire un keygen je vais utiliser le plugin Asm2Clipboard et ripper directement cette routine.
III: Faire un Multi-keygen
Après avoir examiné les autres sharewares créés par C*O*A*A, leur algorithme reste toujours «le même» avec deux/trois variantes.
Je vous propose donc un exemple de 'multi-keygen' en assembleur.
Cela fait réviser quelques trucs comme comment utiliser une ComboBox en assembleur.
Bien que cela puisse être fait de manière plus efficace, cet exemple convient parfaitement aux petits algos.
kg.asm:
.386 .model flat, stdcall option casemap :none include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include \masm32\include\comctl32.inc include \masm32\include\masm32.inc includelib \masm32\lib\comctl32.lib includelib \masm32\lib\masm32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\comctl32.lib DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD .const IDD_MAIN equ 1000 IDB_EXIT equ 1001 IDC_COMBOBOX equ 1002 IDC_NAME equ 1003 IDC_SERIAL equ 1004 IDC_NameText equ 1005 IDC_SerialText equ 1006 IDC_ProductText equ 1007 .data ; keygen details szApp00 db "PlanePlotter v6.x.x.x",0 szSerialDialog00 db "PlanePlotter Registration",0 szApp01 db "TrainPlotter v1.x",0 szSerialDialog01 db "Registration",0 szApp02 db "DSCdecoder v4.x.x.x",0 szSerialDialog02 db "DSCdecoder registration",0 szApp03 db "NDBfinder v2.x.x",0 szSerialDialog03 db "Registration",0 szApp04 db "SondeMonitor v6.x.x.x",0 szSerialDialog04 db "SondeMonitor Registration",0 szApp05 db "EpirbPlotter v2.x",0 szSerialDialog05 db "Registering EpirbPlotter",0 szApp06 db "OrbcommPlotter v1.x",0 szSerialDialog06 db "Registration",0 szApp07 db "Argos3Plotter v2.x",0 szSerialDialog07 db "Registration of Argos3Plotter",0 szApp08 db "CombiPlotter v1.x.x",0 szSerialDialog08 db "Registration",0 szApp09 db "Syntonia v1.x",0 szSerialDialog09 db "Registration",0 ;keygen texts szTitle db "COAA products +10 *multikeygen*",0 szHIDLabel db "yOUR.HiD:",0 szProductLabel db "pRODUCT:",0 szSerialLabel db "sERiAL:",0 szGenButton db "gEN",0 szExitButton db "cLOSE",0 szEnterHID db "Enter your HID buddy!",0 szTooLong db "HID too long",0 szMinCharsPlz db "Enter your HID buddy!",0 template TCHAR "%d",0 .data? szName TCHAR 100 dup(?) szSerial TCHAR 100 dup(?) hInstance dd ? hCombo dd ? windhand dd ? ; Window handle of registration dialog szSize DWORD ? .code start: invoke GetModuleHandle, NULL mov hInstance, eax invoke InitCommonControls invoke DialogBoxParam,hInstance,IDD_MAIN,0,ADDR DlgProc,0 invoke ExitProcess, eax Combo proc LOCAL buffer[256]:BYTE invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp00 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp01 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp02 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp03 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp04 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp05 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp06 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp07 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp08 invoke SendMessage,hCombo,CB_ADDSTRING,0,offset szApp09 invoke SendMessage,hCombo,CB_SETCURSEL,0,0 ret Combo endp DlgProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD mov eax,uMsg .if uMsg == 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,hWin,ADDR szTitle ; Set the window title text invoke SetDlgItemText,hWin,IDC_NameText,ADDR szHIDLabel invoke SetDlgItemText,hWin,IDC_SerialText,ADDR szSerialLabel invoke SetDlgItemText,hWin,IDC_ProductText,ADDR szProductLabel invoke SetDlgItemText,hWin,IDC_SERIAL,ADDR szEnterHID invoke SetDlgItemText,hWin,IDB_EXIT,ADDR szExitButton invoke GetDlgItem,hWin,IDC_COMBOBOX mov hCombo,eax invoke Combo .elseif uMsg == WM_COMMAND mov eax,wParam mov edx,eax shr edx,16 and eax,0FFFFh .if eax == IDB_EXIT invoke SendMessage,hWin,WM_CLOSE,0,0 .endif .if edx == EN_CHANGE .if eax == IDC_NAME CHECKLENGHT: invoke GetDlgItemText,hWin,IDC_NAME,addr szName,sizeof szName invoke lstrlen, ADDR szName mov szSize, eax .if szSize == 0 invoke SetDlgItemText,hWin,IDC_SERIAL,addr szEnterHID .elseif eax > 10 invoke SetDlgItemText,hWin,IDC_SERIAL,addr szTooLong .elseif eax < 6 invoke SetDlgItemText,hWin,IDC_SERIAL,addr szMinCharsPlz .elseif ; Everything good, let's calc the serial! push eax push edi push esi push ebx invoke GetDlgItemText,hWin,IDC_NAME,addr szName,sizeof szName mov edi,offset szName mov esi,offset szName add esi,2 jmp @lbox ;magic stuff start here .endif .endif .endif .if edx == LBN_SELCHANGE ;==CBN_SELCHANGE .if eax == IDC_COMBOBOX jmp CHECKLENGHT @lbox: invoke SendDlgItemMessage,hWin,IDC_COMBOBOX,CB_GETCURSEL,0,0 .if eax == CB_ERR .elseif eax == 0 ; PlanePlotter v6.5.x.x A0: lodsb stosb cmp al, 0 jnz A0 invoke atol,addr szName ADD EAX,04E1h MOV ECX,10h MOV EDI,EDI L001: ADD EAX,EAX TEST EAX,10000h JE L002 XOR EAX,0C75h L002: SUB ECX,1 JNZ L001 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial ; Puts szSerial in DialogBox invoke FindWindow,NULL,addr szSerialDialog00 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1005,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 1 ; TrainPlotter v1.3 A1: lodsb stosb cmp al, 0 jnz A1 invoke atol,addr szName MOV ECX,10h ADD EAX,38Fh L003: SHL EAX,1 MOV EDX,EAX AND EDX,10000h CMP EDX,10000h JNZ L004 XOR EAX,0C75h L004: DEC ECX JNZ L003 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog01 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1002,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 2 ; DSCdecoder v4.5.x.x A2: lodsb stosb cmp al, 0 jnz A2 invoke atol,addr szName ADD EAX,511h MOV ECX,10h MOV EDI,EDI L005: ADD EAX,EAX TEST EAX,10000h JE L006 XOR EAX,0C75h L006: SUB ECX,1 JNZ L005 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog02 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1004,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 3 ; NDBfinder v2.9.6 A3: lodsb stosb cmp al, 0 jnz A3 invoke atol,addr szName ADD EAX,6DFh MOV ECX,10h MOV EDI,EDI L008: ADD EAX,EAX TEST EAX,10000h JE L007 XOR EAX,0C75h L007: SUB ECX,1 JNZ L008 AND EAX,0FFFFh invoke wsprintf,OFFSET szSerial,OFFSET template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog03 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1006,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 4 ; SondeMonitor v6.1.6.9 A4: lodsb stosb cmp al, 0 jnz A4 invoke atol,addr szName ADD EAX,41Bh MOV ECX,10h MOV EDI,EDI L009: ADD EAX,EAX TEST EAX,10000h JE L0010 XOR EAX,0C75h L0010: SUB ECX,1 JNZ L009 AND EAX,0FFFFh invoke wsprintf,OFFSET szSerial,OFFSET template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog04 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1001,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 5 ; EpirbPlotter v2.1 A5: lodsb stosb cmp al, 0 jnz A5 invoke atol,addr szName MOV ECX,10h ADD EAX,3D1h L0012: SHL EAX,1 MOV EDX,EAX AND EDX,10000h CMP EDX,10000h JNZ L0011 XOR EAX,0C75h L0011: DEC ECX JNZ L0012 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog05 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1003,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 6 ; OrbcommPlotter v1.3 A6: lodsb stosb cmp al, 0 jnz A6 invoke atol,addr szName MOV ECX,10h ADD EAX,3CBh L0013: SHL EAX,1 MOV EDX,EAX AND EDX,10000h CMP EDX,10000h JNZ L0014 XOR EAX,0C75h L0014: DEC ECX JNZ L0013 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog06 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1002,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 7 ; Argos3Plotter v2.1 A7: lodsb stosb cmp al, 0 jnz A7 invoke atol,addr szName MOV ECX,10h ADD EAX,49Dh L0016: SHL EAX,1 MOV EDX,EAX AND EDX,10000h CMP EDX,10000h JNZ L0015 XOR EAX,0C75h L0015: DEC ECX JNZ L0016 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog07 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1003,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 8 ; CombiPlotter v1.5.1 A8: lodsb stosb cmp al, 0 jnz A8 invoke atol,addr szName MOV ECX,10h ADD EAX,17Bh L0017: SHL EAX,1 MOV EDX,EAX AND EDX,10000h CMP EDX,10000h JNZ L0018 XOR EAX,0C75h L0018: DEC ECX JNZ L0017 AND EAX,0FFFFh invoke wsprintf, OFFSET szSerial, OFFSET template, eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow, NULL, addr szSerialDialog08 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1001,WM_SETTEXT,0,addr szSerial .endif .elseif eax == 9 ; Syntonia v1.3 A9: lodsb stosb cmp al, 0 jnz A9 invoke atol,addr szName MOV ECX,10h ADD EAX,5ADh L0020: SHL EAX,1 MOV EDX,EAX AND EDX,10000h CMP EDX,10000h JNZ L0019 XOR EAX,0C75h L0019: DEC ECX JNZ L0020 AND EAX,0FFFFh invoke wsprintf,addr szSerial,addr template,eax invoke SetDlgItemText,hWin,IDC_SERIAL,addr szSerial invoke FindWindow,NULL,addr szSerialDialog09 .if eax mov windhand, eax invoke SendDlgItemMessageA,windhand,1002,WM_SETTEXT,0,addr szSerial .endif .endif pop ebx pop esi pop edi pop eax .endif .endif .elseif eax == WM_CLOSE invoke AnimateWindow,hWin,1000,AW_HIDE or AW_CENTER invoke EndDialog, hWin, 0 .endif xor eax,eax ret DlgProc endp end start
kg.rc:
;This Resource Script was generated by WinAsm Studio. #define IDD_MAIN 1000 #define IDB_EXIT 1001 #define IDC_COMBOBOX 1002 #define IDC_NAME 1003 #define IDC_SERIAL 1004 #define IDC_NameText 1005 #define IDC_SerialText 1006 #define IDC_ProductText 1007 IDD_MAIN DIALOGEX 10,10,180,101 FONT 8,"Tahoma" STYLE 0x90c80804 EXSTYLE 0x00000008 BEGIN CONTROL "",IDB_EXIT,"Button",0x10010000,131,86,47,13,0x00000000 CONTROL "",IDC_COMBOBOX,"ComboBox",0x50300000,43,34,134,50,0x00000000 CONTROL "",IDC_SERIAL,"Edit",0x10000880,43,18,134,13,0x00000200 CONTROL "",IDC_NAME,"Edit",0x10000080,43,3,134,13,0x00000200 CONTROL "",IDC_NameText,"Static",0x50010002,3,6,37,10,0x00001000 CONTROL "",IDC_SerialText,"Static",0x50010002,3,22,37,10,0x00000000 CONTROL "",IDC_ProductText,"Static",0x50010002,3,37,37,10,0x00000000 END
make.bat:
@echo off \masm32\bin\rc /v kg.rc \masm32\bin\cvtres.exe /machine:ix86 kg.res \masm32\bin\ml.exe /c /coff kg.asm \masm32\bin\link.exe /SUBSYSTEM:WINDOWS /OUT:keygen.exe kg.obj kg.res del kg.RES del kg.OBJ pause
Une fois compilé, ça ressemble à ça:
C'est tout pour le moment!
Xylitol, 27/06/2021
Copyright (C)- xtx Team (2021)