Introduction:
Dans ce tutoriel nous allons être confronté à du RSA-1024 en signature et faire un keyfilemaker.
Les outils
Pour mettre en application ce tutoriel il nous faudra...
OllyDbg v2.01 (http://Ollydbg.de/)
Detect It Easy (https://github.com/horsicq/DIE-engine/releases)
SmartCapture v3.17.4 (https://www.desksoft.com/Download/SCSetup.exe)
I: Démarrage:
Installons le programme et exécutons-le pour voir comment il réagit.
Rien de spécial, on a juste un nag au démarrage qui nous dit qu'il nous reste 30 jours d'évaluation.
Le programme n'a pas de boîte de dialogue permettant à l'utilisateur d'activer un numéro de série.
Cela laisse présager que le sérial d'activation doit être stocké dans un fichier, ou bien dans la base de registre Windows.
On scanne l'exécutable principal (SmartCapture.exe) avec DiE (Detect It Easy) pour voir s'il est compressé, apparemment ce n'est pas le cas, super!
II: Trouver la routine d'enregistrement
Chargeons l'application dans le débogueur.
Nous allons regarder dans un premier temps les strings, afin de se faire une idée de ce fichier:
Clic droit>Search for>All referenced strings
On fait défiler le listing, et on repère des strings potentiellement intéressants:
Double-cliquons sur le premier string "DeskSoftLicense" qui nous amène sur sa position: 0043C4F2.
Ensuite nous remontons un peu cette procédure jusqu'a atteindre son début, posons un breakpoint à cet endroit.
Après pressons la touche F9 pour lancer le programme et à cet instant... le débogueur break!
Il n'y a plus qu'a tracer pour voir ce qu'il se passe, allez hop c'est parti!
III: Comprendre la routine d'enregistrement
On commence à tracer tranquillement à coup de F8 comme d'habitude.
On comprend très rapidement que le programme est à la recherche d'un fichier *.dlc
Dans son répertoire de données: %AppData%/DeskSoft/SmartCapture
Ainsi que son répertoire d'installation: %ProgramFiles(X86)%/SmartCapture
On continue à tracer et on tombe sur FindFirstFile avec un flag *DeskSoftLicense
on repasse ensuite dans le même segment avec en flag *.dlc
Dans la dernière procédure avant la petite boucle, le programme refait un FindFirstFile avec les mêmes flags.
Mais dans cette procédure on a en plus de la récursivité, au cas où le .dlc est dans un sous-répertoire de SmartCapture.
Tant que le fichier n'est pas trouvé, on ne rentre pas dans la boucle.
On continue à tracer, mais plus rien d'intéressant ne se passe, on arrive alors sur l'initialisation du mode 'DEMO' après être sorti de la routine principale que l'on avait trouvé.
On va donc naviguer dans le répertoire d'installation de SmartCapture et créer un fichier de licence.
III.a: Construction du keyfile
Créons un nouveau document texte, de votre coté appelez-le comme vous voulez, mais surtout en lui donnant l'extension: .dlc
Placez aussi quelques caractères dans le fichier histoire de lui donner une taille autre que zéro, car le programme va surement prendre son contenu.
Ensuite rechargeons notre cible dans le débogueur avec CTRL+F2, et on le relance l'exécution avec F9.
Puis on retrace pour arriver jusqu'où l'on était.
Attendez-vous à répéter cette opération assez souvent pour comprendre comment le fichier .dlc est formé.
Continuons de tracer, et avec le fichier de licence .dlc trouvé, on entre maintenant dans la boucle.
Entrons dans le CALL, le contenu du fichier DLC est récupéré.
Ensuite ça devient un peu plus intéressant.
Le string "[License]" est poussé sur la pile avec "bonjour" (le contenu de mon fichier .dlc) puis nous entrons dans une procédure.
Ça sent la comparaison et vous avez raison!
Si les deux strings ne sont pas identiques, ça saute vers la sortie (JE 0043C98C).
On réécrit notre fichier de licence, mais cette fois-ci avec le string "[License]".
Puis on recommence.. et la c'est bon on ne saute plus vers la sortie.
Par contre on arrive tout de suite sur une autre condition.
Le programme compare après la 9ème lettre afin de voir s'il y a le caractère égal '=' s’il n'y est pas, on saute vers la sortie. (JNE 0043C98C)
Aller, on continue à construire notre fichier de licence petit à petit en suivant ce que le programme demande.
On le réenregistre avec:
[License]=Bonjour
On réessaye, ça passe bien, mais juste après il tente de trouver la chaine "[Product]".
On remarque également un peu en dessous la ligne CMP AL,3D
Donc on peut directement réécrire notre fichier avec un '[Product]='
[License]=Bonjour [Product]=Bonjour
On réessaye et là... on est éjecté de la routine.
Ah il y a une petite subtilité, le texte est comparé de bas en haut, donc:
[Product]=Bonjour [License]=Bonjour
Voilà ça passe beaucoup mieux.
On continue de tracer, on passe la vérification de l'existence de la chaine '[Product]' sans soucis.
Un peu plus bas, mon string 'Bonjour' est récupéré dans une boucle puis comparé avec "SmartCapture"
On remarque aussi la présence de "[UsrName]" en dessous et aussi une vérification sur le signe égal.
On peut donc rééditer notre fichier en conséquence et recommencer.
[UsrName]=Xylitol [Product]=SmartCapture [License]=Bonjour
On continue et on rencontre maintenant "[LicType]"
Si le string n'est pas trouver on est éjecté.
On re-édite le fichier en conséquence/reload la cible:
[LicType]=Enterprise [UsrName]=Xylitol [Product]=SmartCapture [License]=Bonjour
On continue, ça passe, le contenu de [LicType] ne semble pas être vérifié pour le moment.
Et on arrive sur [NumUser].
Vous savez quoi faire.
[NumUser]=1337 [LicType]=Enterprise [UsrName]=Xylitol [Product]=SmartCapture [License]=Bonjour
On continue, après ça le programme fait un peu de formatage de chaîne avec notre type de licence et le nombre de postes.
Puis on arrive sur "[Version]"
Allez, on réédite/recharge le débogueur:
[Version]=3.7.14 [NumUser]=1337 [LicType]=Enterprise [UsrName]=Xylitol [Product]=SmartCapture [License]=Bonjour
Ensuite on continue de tracer, puis on rencontre une comparaison pour la version.
Notre première lettre est comparée avec "3" s'il y a autre chose, le programme ferme le handle du fichier .dlc et quitte la routine comme les fois précédentes.
Le reste des lettres qui précède la première n'est pas regardé.
Vient après encore une autre vérification d'existence de chaîne pour "[ExpDate]"
Re-belotte avec le fichier de licence et le débogueur:
[ExpDate]=31/12/9999 [Version]=3.x [NumUser]=1337 [LicType]=Enterprise [UsrName]=Xylitol [Product]=SmartCapture [License]=Bonjour
On passe ça, puis on arrive encore sur une vérification d'existence de chaîne: "[OrderID]"
Aller zou! On bricole à nouveau le fichier de licence et on recharge.
[OrderID]=0 [ExpDate]=31/12/9999 [Version]=3.x [NumUser]=1337 [LicType]=Enterprise [UsrName]=Xylitol [Product]=SmartCapture [License]=Bonjour
Une fois cela effectué on continue de tracer.
On arrive sur une boucle qui formate nos chaînes, puis on arrive à la fin de la procédure.
Il semblerait que les passes de validité sur le keyfile sont terminées.
Le contenu de notre valeur pour '[License]' est récupéré, ainsi que le contenu du keyfile, mais sans la partie finale "=Bonjour" de [License].
Puis on entre dans une dernière procédure avant d'arriver sur CloseHandle.
Allez zou! On fait F8 jusqu'au CALL, et une fois dessus, F7.
III.b: L'algorithme
On arrive dans une procédure crypto.
La première chose qu'il fait est d'acquérir un handle pour le CSP (cryptographic service provider)
On continue de tracer, il importe un keyblob.
Allons regarder à quoi il ressemble, on va sur la fenêtre de dump, puis: clic droit>Go to>Expression...
On rentre 00629FB8, et.. Ohhh une clé publique RSA.
L'instruction précédente nous indique ça taille: 94h (148) on a probablement ici du 1024 bits.
Tout de suite après, il acquiert un handle pour hasher.
On remarque au passage le PUSH 8003 qui correspond au ALG_ID CALG_MD5.
Ensuite il récupère le buffer contenant le keyfile tronqué, puis le hash.
Puis il récupère notre chaine pour la valeur [License] du keyfile, et tente de vérifier la signature.
Celle-ci n'est pas bonne évidement.
Ensuite le programme détruit les handles, et on sort de la routine.
On continue à tracer puis on rencontre le CloseHandle pour le fichier de license ouvert, puis on sort de la routine.
On comprend que le saut conditionnel dans la 'petite boucle' du début sert à valider l'enregistrement.
Si notre sérial était bon, on aurait pris ce jump.
Voilà, on sait maintenant comment ça fonctionne.
Le seul problème c'est de trouver la clé privée pour le keyblob et ça... pour le moment avec une taille pareille c'est impossible.
On va donc devoir remplacer la clé publique par une autre que l'on maitrise, c'est la solution la plus simple.
Rappel sur le RSA en signature:
Bob signe avec ça clé privée (d,e): S = M ^d mod n
Puis il transmet M (le message) ainsi que S (la signature)
Alice possède le message et la signature de Bob.
Pour vérifier que la signature correspond au message: M' = S ^ e mod n
Puis Alice regarde si M′ = M, si oui, la signature est valide.
A savoir qu'en pratique, c'est un hach du message qui est signé et non le message lui-même, car le message peut être bien trop long.
Dans notre cas, c'est en MD5.
IV: Faire un Keygen
Donc on va devoir faire un patch + keygen
Il nous faut une clé RSA de la même taille aussi, commençons par ça.
Pour générer un blob RSA, on peut le faire à la manière fainéant avec RSAkeyFileGen v0.3.
Ça fait même l'export bin to hex pour l'asm, bien pratique tout de même.
Ou bien de le faire par nous-même, c'est bien aussi!
Pour générer/exporter du RSA on peut le faire via CryptoAPI.
Voici un petit exemple en assembleur, qui génère une paire de clés et affiche la sortie sur console.
rsagen.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\advapi32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\advapi32.lib include \masm32\macros\macros.asm DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD WriteHexadecimal PROTO :DWORD,:DWORD .const IDC_QUIT equ 1004 IDC_GENKEY equ 1005 PRIVATE_KEY_SIZE equ 0254h PUBLIC_KEY_SIZE equ 094h LINE_BREAK equ (10) CARRIAGE_RETURN equ (13) .data ;Keypair gen: szFileNamePrivate db "Private.key",0 szFileNamePublic db "Public.key",0 dwBlobLen dd 0 hfile dd 0 hkey dd 0 hProv dd 0 hexadecimal_digits db "0123456789ABCDEF",0 message_rsa_gen_priv db "[iNFO] Private key: ",0 message_rsa_gen_pub db "[iNFO] Public key: ",0 message_done db "[iNFO] Private.key and Public.key saved!",13,10,0 .data? hInstance dd ? ;dd can be written as dword console_handle HANDLE ? text_length dd ? general_buffer db 4096 dup (?) bKeyBlobPriv db PRIVATE_KEY_SIZE dup (?) bKeyBlobPub db PUBLIC_KEY_SIZE dup (?) NumOfBytesWritten DWORD ? .code start: invoke GetStdHandle,STD_OUTPUT_HANDLE mov console_handle,eax 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_GENKEY ;reference: https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-creating-a-key-container-and-generating-keys invoke CryptAcquireContext,offset hProv,NULL,NULL,PROV_RSA_FULL,NULL ;Get the priv key invoke CryptGenKey,hProv,AT_SIGNATURE,CRYPT_EXPORTABLE,addr hkey mov dwBlobLen,PRIVATE_KEY_SIZE invoke CryptExportKey,hkey,0,PRIVATEKEYBLOB,0,addr bKeyBlobPriv,addr dwBlobLen invoke lstrlen,addr message_rsa_gen_priv mov [text_length],eax invoke WriteConsoleA,console_handle,addr message_rsa_gen_priv,text_length,NULL,NULL invoke WriteHexadecimal,addr bKeyBlobPriv,PRIVATE_KEY_SIZE invoke CreateFile,addr szFileNamePrivate,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL mov hfile,eax invoke WriteFile,hfile,offset bKeyBlobPriv,PRIVATE_KEY_SIZE,offset NumOfBytesWritten,NULL ; invoke GetLastError invoke CloseHandle,hfile ;Get the pub key invoke CryptGenKey,hProv,AT_SIGNATURE,CRYPT_EXPORTABLE,addr hkey mov dwBlobLen,PUBLIC_KEY_SIZE invoke CryptExportKey,hkey,0,PUBLICKEYBLOB,0,addr bKeyBlobPub,addr dwBlobLen invoke lstrlen,addr message_rsa_gen_pub mov [text_length],eax invoke WriteConsoleA,console_handle,addr message_rsa_gen_pub,text_length,NULL,NULL invoke WriteHexadecimal,addr bKeyBlobPub,PUBLIC_KEY_SIZE invoke CreateFile,addr szFileNamePublic,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL mov hfile,eax invoke WriteFile,hfile,offset bKeyBlobPub,PUBLIC_KEY_SIZE,offset NumOfBytesWritten,NULL ; invoke GetLastError invoke CloseHandle,hfile invoke lstrlen,addr message_done mov [text_length],eax invoke WriteConsoleA,console_handle,addr message_done,text_length,NULL,NULL ;releasing invoke CryptReleaseContext,hProv,0 invoke RtlZeroMemory,addr bKeyBlobPub,sizeof bKeyBlobPub invoke RtlZeroMemory,addr bKeyBlobPriv,sizeof bKeyBlobPriv .elseif wParam == IDC_QUIT invoke EndDialog,hWin,0 .endif .elseif uMsg == WM_CLOSE invoke EndDialog,hWin,0 .endif xor eax,eax ret DlgProc endp WriteHexadecimal proc source_buffer:DWORD, source_length:DWORD local output_buffer:DWORD mov eax,offset general_buffer mov output_buffer,eax WriteHexadecimal_Loop: mov eax,source_length cmp eax,0 jz WriteHexadecimal_End sub eax,1 mov [source_length],eax mov eax,source_buffer mov dl,[eax] mov dh,dl add eax,1 mov source_buffer,eax shr dh,4 and dl,0Fh xor eax,eax mov al,dh mov ecx,offset hexadecimal_digits add ecx,eax mov dh,[ecx] mov eax, output_buffer mov [eax],dh add eax, 1 mov output_buffer,eax xor eax,eax mov al,dl mov ecx,offset hexadecimal_digits add ecx,eax mov dl,[ecx] mov eax, output_buffer mov [eax],dl add eax,1 mov output_buffer,eax jmp WriteHexadecimal_Loop WriteHexadecimal_End: mov eax,output_buffer mov dl,CARRIAGE_RETURN mov [eax],dl add eax,1 mov dl,LINE_BREAK mov [eax],dl add eax,1 xor dl,dl mov [eax],dl invoke lstrlen,addr general_buffer mov [text_length],eax invoke WriteConsoleA,console_handle,addr general_buffer,text_length,NULL,NULL xor eax,eax ret WriteHexadecimal endp end start
rsagendlg.rc:
;This Resource Script was generated by WinAsm Studio. #define IDC_QUIT 1004 #define IDC_GENKEY 1005 101 DIALOGEX 0,0,169,44 CAPTION "CryptGenKey RSA-1024" FONT 8,"Tahoma" STYLE 0x80c80880 EXSTYLE 0x00000000 BEGIN CONTROL "Gen",IDC_GENKEY,"Button",0x10000001,50,23,50,14,0x00000000 CONTROL "Quit",IDC_QUIT,"Button",0x10000000,110,23,50,14,0x00000000 END
make.bat:
@echo off \masm32\bin\rc /v rsagendlg.rc \masm32\bin\ml.exe /c /coff /Cp /nologo rsagen.asm \masm32\bin\link.exe /SUBSYSTEM:CONSOLE /RELEASE /VERSION:4.0 /OUT:rsa-1024-genkey.exe rsagen.obj rsagendlg.res del rsagendlg.res del rsagen.obj pause
Une fois compilé, ça ressemble à ça:
C'est rudimentaire, mais ça fait le job! Ensuite vous pouvez utiliser bin2dbex.exe fourni avec masm32 pour convertir ça.
Maintenant que ce problème est résolu, on va pouvoir faire notre patch, on se souvient de notre position à patcher: l'offset 00629FB8 au moment de CryptInportKey.
Pour le keygen on connaît la structure du message et qu'il y a un formatage MD5 pour la signature.
Pour signer avec RSA on utilisera CryptSignHash de advapi, voilà, il n'y a plus qu’à!
base.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\advapi32.inc include \masm32\include\masm32.inc includelib \masm32\lib\masm32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\advapi32.lib include \masm32\macros\macros.asm include crc32.inc DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD Patch PROTO :DWORD patch MACRO offsetAdr,_bytes,_byteSize invoke SetFilePointer,hTarget,offsetAdr,NULL,FILE_BEGIN .if eax==0FFFFFFFFh invoke CloseHandle,hTarget invoke MessageBox,hWin,addr szFileBusy,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION ret .endif invoke WriteFile,hTarget,addr _bytes,_byteSize,addr BytesWritten,FALSE ENDM .const IDB_GEN equ 1001 IDB_PATCH equ 1002 IDB_QUIT equ 1003 IDC_NAME equ 1004 IDC_DATE_STATIC equ 1005 IDC_LBLNAME equ 1006 IDC_CHECKBOX equ 1007 MAXSiZE equ 256h CALG_MD5 equ 8003h PRIVATE_KEY_SIZE equ 0254h PUBLIC_KEY_SIZE equ 094h SIGNATURE_SIZE equ 080h HCRYPTHASH equ dd HCRYPTPROV equ dd .data ;Public key for the patch WBuffer1 db 006h,002h,000h,000h,000h,024h,000h,000h,052h,053h,041h,031h,000h,004h,000h,000h WBuffer2 db 001h,000h,001h,000h,06Fh,0AAh,013h,0A8h,04Bh,0BCh,09Ch,055h,003h,0ECh,0FDh,0B1h WBuffer3 db 01Eh,096h,0AFh,0C4h,0D0h,045h,013h,0B6h,0E6h,0FCh,0B7h,04Ch,040h,0F9h,037h,0A4h WBuffer4 db 029h,0CEh,0F5h,02Bh,093h,065h,091h,02Ah,074h,0CEh,0B8h,025h,079h,0D1h,013h,0B4h WBuffer5 db 01Eh,034h,038h,0FAh,09Ch,0B8h,0CDh,0F2h,04Ch,0EBh,07Ah,080h,0DDh,09Ah,004h,009h WBuffer6 db 07Eh,0BCh,0F3h,09Ah,0F3h,0ECh,066h,03Ah,0B0h,0A5h,0ABh,070h,0A4h,0F2h,035h,0C6h WBuffer7 db 01Ah,0DDh,0B8h,044h,073h,0FEh,08Ah,07Eh,07Fh,044h,059h,033h,09Eh,0E4h,0E2h,0DEh WBuffer8 db 059h,0F0h,02Ah,024h,097h,0D4h,06Ch,09Ch,0ACh,079h,0A3h,0F7h,098h,06Bh,04Bh,008h WBuffer9 db 0F5h,0A1h,00Ah,09Fh,032h,0B7h,0B8h,0BBh,0CBh,090h,05Fh,0CDh,006h,0F9h,017h,045h WBuffer10 db 0B4h,0D4h,0EFh,0AAh PatchOffset1 dd 00228DB8h ;00629FB8 PatchOffset2 dd 00228DC8h ;00629FC8 PatchOffset3 dd 00228DD8h ;00629FD8 PatchOffset4 dd 00228DE8h ;00629FE8 PatchOffset5 dd 00228DF8h ;00629FF8 PatchOffset6 dd 00228E08h ;0062A008 PatchOffset7 dd 00228E18h ;0062A018 PatchOffset8 dd 00228E28h ;0062A028 PatchOffset9 dd 00228E38h ;0062A038 PatchOffset10 dd 00228E48h ;0062A048 ;Private key for the keygen private_key \ db 007h,002h,000h,000h,000h,024h,000h,000h,052h,053h,041h,032h,000h,004h,000h,000h db 001h,000h,001h,000h,06Fh,0AAh,013h,0A8h,04Bh,0BCh,09Ch,055h,003h,0ECh,0FDh,0B1h db 01Eh,096h,0AFh,0C4h,0D0h,045h,013h,0B6h,0E6h,0FCh,0B7h,04Ch,040h,0F9h,037h,0A4h db 029h,0CEh,0F5h,02Bh,093h,065h,091h,02Ah,074h,0CEh,0B8h,025h,079h,0D1h,013h,0B4h db 01Eh,034h,038h,0FAh,09Ch,0B8h,0CDh,0F2h,04Ch,0EBh,07Ah,080h,0DDh,09Ah,004h,009h db 07Eh,0BCh,0F3h,09Ah,0F3h,0ECh,066h,03Ah,0B0h,0A5h,0ABh,070h,0A4h,0F2h,035h,0C6h db 01Ah,0DDh,0B8h,044h,073h,0FEh,08Ah,07Eh,07Fh,044h,059h,033h,09Eh,0E4h,0E2h,0DEh db 059h,0F0h,02Ah,024h,097h,0D4h,06Ch,09Ch,0ACh,079h,0A3h,0F7h,098h,06Bh,04Bh,008h db 0F5h,0A1h,00Ah,09Fh,032h,0B7h,0B8h,0BBh,0CBh,090h,05Fh,0CDh,006h,0F9h,017h,045h db 0B4h,0D4h,0EFh,0AAh,02Bh,0E5h,00Ah,053h,0A7h,07Ah,025h,0EDh,0C4h,0F0h,05Fh,005h db 049h,0BEh,07Dh,06Fh,041h,057h,03Dh,0D0h,063h,029h,015h,075h,04Ch,0A6h,08Dh,0EEh db 042h,0C6h,070h,0C7h,049h,022h,0D2h,0E2h,05Ah,018h,0DDh,09Bh,004h,0CFh,0B5h,048h db 050h,09Dh,0C7h,08Fh,06Ah,037h,004h,045h,00Ah,0FCh,014h,075h,002h,0CFh,06Ah,07Fh db 01Ch,094h,02Dh,0F1h,0CDh,0F5h,018h,03Dh,09Ch,00Eh,0B6h,036h,018h,0D5h,02Ah,039h db 02Ah,051h,0E4h,09Fh,0E7h,04Eh,012h,006h,0ECh,07Ah,059h,0E6h,01Ah,058h,0B5h,05Dh db 048h,023h,028h,0B0h,0ABh,07Bh,0ABh,0BDh,006h,010h,0EAh,0B7h,03Eh,088h,0E1h,01Ch db 02Dh,05Ch,012h,010h,0F2h,0C6h,0D5h,061h,092h,0ECh,020h,085h,02Ch,0F8h,0C8h,07Ch db 031h,028h,071h,0B5h,0B9h,0C0h,001h,0EEh,037h,01Ah,0C5h,0F4h,08Ch,04Fh,0B7h,0C4h db 0A9h,081h,07Ch,0BFh,024h,075h,06Dh,03Bh,007h,018h,0F7h,016h,0E4h,01Ch,0A4h,076h db 0DBh,017h,06Eh,016h,0ECh,062h,032h,02Dh,03Fh,057h,0DCh,0EFh,036h,0F6h,0D0h,032h db 00Ch,0C4h,0D0h,01Eh,01Bh,037h,06Eh,075h,0D8h,002h,074h,02Bh,02Fh,0B2h,0B4h,004h db 00Fh,0DBh,0B1h,003h,0B5h,069h,081h,0D0h,02Ch,034h,0C5h,0B2h,0B8h,053h,005h,0FBh db 0A6h,0BCh,019h,014h,0ACh,01Fh,0CFh,085h,0B7h,097h,0BBh,02Dh,022h,066h,015h,025h db 000h,091h,098h,074h,02Ah,0DAh,0D2h,047h,078h,026h,0EDh,040h,075h,053h,051h,0DBh db 02Ah,00Ch,021h,0DAh,045h,063h,025h,012h,043h,0CCh,066h,0A3h,06Ah,0ACh,00Bh,01Eh db 014h,00Eh,0DCh,093h,08Ah,063h,028h,01Dh,075h,0EEh,099h,0C3h,0A1h,0A1h,028h,07Fh db 0B0h,062h,0EBh,05Bh,02Dh,019h,0FFh,004h,063h,036h,069h,043h,029h,0BBh,04Fh,099h db 0ADh,0EBh,0CCh,0F7h,090h,0ABh,097h,0E8h,0E7h,04Ch,0F5h,074h,03Bh,081h,018h,01Fh db 0E7h,05Ah,01Ch,078h,0A8h,011h,01Fh,0FAh,0ACh,0EEh,0C3h,05Fh,038h,031h,0E4h,069h db 018h,0FDh,085h,0D7h,089h,0C3h,068h,0C2h,058h,09Bh,0B5h,088h,005h,0A4h,0F0h,0F8h db 0B3h,0FBh,071h,085h,026h,0DEh,0F0h,058h,032h,007h,060h,049h,03Dh,052h,0ABh,039h db 02Ch,047h,0F4h,04Eh,0A7h,0A7h,028h,068h,029h,005h,0CEh,08Bh,0A9h,0B7h,060h,0A0h db 07Fh,0BDh,059h,00Dh,01Ah,0ABh,0C9h,063h,04Fh,096h,0C4h,0AFh,04Bh,0A2h,0E0h,071h db 087h,046h,06Bh,089h,03Dh,00Dh,0FBh,00Dh,09Ch,01Ah,090h,059h,06Fh,0E3h,00Fh,0AFh db 0EFh,0B5h,01Eh,057h,01Dh,0B4h,0EFh,073h,08Ch,02Ch,05Ah,04Bh,03Ah,017h,020h,05Ah db 066h,000h,05Fh,0DAh,04Fh,0C2h,080h,018h,0A2h,0BEh,02Fh,0CDh,0EDh,01Ah,099h,035h db 06Dh,057h,0AAh,033h,0DCh,04Dh,0DCh,088h,066h,051h,04Ch,001h,033h,045h,0F1h,066h db 0F8h,049h,04Dh,08Dh comment / P = F12D941C7F6ACF027514FC0A4504376A8FC79D5048B5CF049BDD185AE2D22249C770C642EE8DA64C75152963D03D57416F7DBE49055FF0C4ED257AA7530AE52B Q = B57128317CC8F82C8520EC9261D5C6F210125C2D1CE1883EB7EA1006BDAB7BABB02823485DB5581AE6597AEC06124EE79FE4512A392AD51836B60E9C3D18F5CD E = 10001 N = AAEFD4B44517F906CD5F90CBBBB8B7329F0AA1F5084B6B98F7A379AC9C6CD497242AF059DEE2E49E3359447F7E8AFE7344B8DD1AC635F2A470ABA5B03A66ECF39AF3BC7E09049ADD807AEB4CF2CDB89CFA38341EB413D17925B8CE742A9165932BF5CE29A437F9404CB7FCE6B61345D0C4AF961EB1FDEC03559CBC4BA813AA6F D = 8D4D49F866F14533014C516688DC4DDC33AA576D35991AEDCD2FBEA21880C24FDA5F00665A20173A4B5A2C8C73EFB41D571EB5EFAF0FE36F59901A9C0DFB0D3D896B468771E0A24BAFC4964F63C9AB1A0D59BD7FA060B7A98BCE05296828A7A74EF4472C39AB523D4960073258F0DE268571FBB3F8F0A40588B59B58C268C389 */ ;dialog details szTitle db "DeskSoft SmartCapture v3.17.4 *patch+keygen*",0 szIDBGen db "gENERATE",0 szIDBExit db "eXiT",0 szIDBPatch db "pATCH",0 szlblName db "Name:",0 szIDBBackup db "bCK",0 MsgBoxCaption db "Keygen",0 szEnterName db "Your name is too short !",0 szTooLong db "Your name is too long !",0 szGenSucces db "License file created!",0 szNotFound db "SmartCapture.exe not found",0 szWrongSize db "Bad size",0 szBadCRC32 db "Incorrect CRC32",0 szFileBusy db "File busy",0 szSucess db "Patched!",13,10 db "now use keygen!",0 szDateStatic db "25/09/2021",0 ; Patch details TargetName db "SmartCapture.exe",0 BackupName db "SmartCapture.exe.backup",0 TargetCRC32 dd 27BB21CFh ; CRC32 of SmartCapture.exe TargetSize dd 2531168 ; File size of SmartCapture.exe ;keygen details szSignatureChars dd MAXSiZE dup (0) szDesc db "DeskSoft License",0 szFileName db "DeskSoftLicense.dlc",0 hkey dd 0 dwBlobLen dd 0 hfile dd 0 format db '[Product]=SmartCapture',13,10 db '[UsrName]=%s',13,10 db '[LicType]=Enterprise',13,10 db '[NumUser]=Unlimited',13,10 db '[Version]=3',13,10 db '[OrderID]=0',13,10 db '[ExpDate]=31/12/9999',13,10 db '[License]',0 .data? hInstance dd ? ;dd can be written as dword ;keygen details szSignature db SIGNATURE_SIZE dup (?) szBufName db 600h dup (?) buffer db 600h dup (?) buffkey db 600h dup (?) hHash HCRYPTHASH ? hProv HCRYPTPROV ? NumOfBytesWritten DWORD ? ;patch details hTarget HINSTANCE ? BytesWritten db ? .code start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,hInstance,101,0,ADDR DlgProc,0 invoke ExitProcess,eax HexToChar Proc HexValue :DWORD, CharValue :DWORD, HexLength :DWORD mov esi,[ebp+8] mov edi,[ebp+0Ch] mov ecx,[ebp+10h] @HexToChar: lodsb mov ah, al and ah, 0fh shr al, 4 add al, '0' add ah, '0' .if al > '9' add al, 'A'-'9'-1 .endif .if ah > '9' add ah, 'A'-'9'-1 .endif stosw loopd @HexToChar Ret HexToChar endp DlgProc proc hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD LOCAL ff32:WIN32_FIND_DATA LOCAL pFileMem:DWORD .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,IDB_PATCH,ADDR szIDBPatch invoke SetDlgItemText,hWin,IDB_GEN,ADDR szIDBGen invoke SetDlgItemText,hWin,IDB_QUIT,ADDR szIDBExit invoke SetDlgItemText,hWin,IDC_DATE_STATIC,ADDR szDateStatic invoke SetDlgItemText,hWin,IDC_LBLNAME,ADDR szlblName invoke SetDlgItemText,hWin,IDC_CHECKBOX,ADDR szIDBBackup ; Init CRC32 table call InitCRC32Table ; Check IDC_CHECKBOX for file backup invoke SendDlgItemMessage,hWin,IDC_CHECKBOX,BM_SETCHECK,1,0 .elseif uMsg == WM_COMMAND .if wParam == IDB_PATCH ;Patch procedure start here invoke FindFirstFile,ADDR TargetName,ADDR ff32 ; File to patch is not in same dir .if eax == INVALID_HANDLE_VALUE invoke MessageBox,hWin,addr szNotFound,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION .else mov eax,TargetSize ; File size is incorrect .if ff32.nFileSizeLow != eax invoke MessageBox,hWin,addr szWrongSize,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION ; Filesize is correct .else mov pFileMem,InputFile(ADDR TargetName) invoke CRC32,pFileMem,ff32.nFileSizeLow mov edx,TargetCRC32 ; Calculated CRC32 does not match .if eax != edx invoke MessageBox,hWin,addr szBadCRC32,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION .else invoke GetFileAttributes,addr TargetName ; The file is read-only, so let's try to set it to read/write .if eax!=FILE_ATTRIBUTE_NORMAL invoke SetFileAttributes,addr TargetName,FILE_ATTRIBUTE_NORMAL .endif ; Everything's okay, so let's patch the file invoke CreateFile,addr TargetName,GENERIC_READ+GENERIC_WRITE,FILE_SHARE_READ+FILE_SHARE_WRITE,\ NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL .if eax!=INVALID_HANDLE_VALUE mov hTarget,eax ;Before patching check if backup invoke SendDlgItemMessage,hWin,IDC_CHECKBOX,BM_GETCHECK,0,0 .if eax==BST_CHECKED invoke CopyFile, addr TargetName, addr BackupName, TRUE .else .endif ; Start patches to the file patch PatchOffset1,WBuffer1,16 patch PatchOffset2,WBuffer2,16 patch PatchOffset3,WBuffer3,16 patch PatchOffset4,WBuffer4,16 patch PatchOffset5,WBuffer5,16 patch PatchOffset6,WBuffer6,16 patch PatchOffset7,WBuffer7,16 patch PatchOffset8,WBuffer8,16 patch PatchOffset9,WBuffer9,16 patch PatchOffset10,WBuffer10,4 invoke CloseHandle,hTarget invoke MessageBox,hWin,addr szSucess,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION invoke GetDlgItem,hWin,IDB_PATCH invoke EnableWindow, eax, FALSE .endif .endif .endif .endif .elseif wParam == IDB_GEN invoke GetDlgItemText,hWin,IDC_NAME,Addr szBufName,MAXSiZE .if eax < 3 invoke MessageBox,hWin,addr szEnterName,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION .elseif eax > 60 invoke MessageBox,hWin,addr szTooLong,addr MsgBoxCaption,MB_OK+MB_ICONEXCLAMATION .elseif ;Format the serial invoke wsprintfA, offset buffer, offset format, Addr szBufName invoke lstrcat,offset buffkey,offset buffer invoke lstrcat,offset buffkey,chr$("=") ;get the csp invoke CryptAcquireContext,offset hProv,addr szDesc,NULL,PROV_RSA_FULL,NULL .if eax == 0 invoke GetLastError .if eax == NTE_BAD_KEYSET invoke CryptAcquireContext,offset hProv,addr szDesc,NULL,PROV_RSA_FULL,CRYPT_NEWKEYSET .endif .endif ;import the private key invoke CryptImportKey,hProv,addr private_key,PRIVATE_KEY_SIZE,0,0,addr hkey ;hash using md5 invoke CryptCreateHash,hProv,CALG_MD5,0,0,offset hHash invoke lstrlen,offset buffer invoke CryptHashData,hHash,offset buffer,eax,0 ;sign the message mov dwBlobLen,SIGNATURE_SIZE invoke CryptSignHash,hHash,AT_SIGNATURE,offset szDesc,0,offset szSignature,addr dwBlobLen ;Hex to chars the signature invoke HexToChar,addr szSignature,addr szSignatureChars,SIGNATURE_SIZE ;format the final serial invoke lstrcat,addr buffkey,addr szSignatureChars ;create the keyfile invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL mov hfile,eax invoke GetLastError .if eax == ERROR_ALREADY_EXISTS invoke CloseHandle,hfile invoke DeleteFile,addr szFileName invoke CreateFile,addr szFileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL mov hfile,eax .endif invoke lstrlen,addr buffkey invoke WriteFile,hfile,offset buffkey,eax,offset NumOfBytesWritten,NULL ; invoke CloseHandle,hfile invoke MessageBox,hWin,addr szGenSucces,addr MsgBoxCaption,MB_OK+MB_ICONINFORMATION call clean .endif .elseif wParam == IDB_QUIT invoke EndDialog,hWin,0 .endif .elseif uMsg == WM_CLOSE invoke EndDialog,hWin,0 .endif xor eax,eax ret DlgProc endp Patch proc hWnd:HWND local status:DWORD Patch EndP clean proc invoke CryptReleaseContext,hProv,0 invoke CryptDestroyHash,hHash invoke RtlZeroMemory,addr szSignatureChars,sizeof szSignatureChars invoke RtlZeroMemory,addr buffer,sizeof buffer invoke RtlZeroMemory,addr buffkey,sizeof buffkey invoke RtlZeroMemory,addr szSignature,sizeof szSignature ret clean endp end start
crc32.inc:
CRC32 PROTO :DWORD,:DWORD .data? CRCtable dd 256 DUP (?) .code align 4 ; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл ; These are MASM versions of Donkey's GoAsm CRC-32 procedures, ; adapted from routines by Thomas Bleeker (MadWizard),table- ; driven and fast ; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл InitCRC32Table proc uses ebx esi edi mov edi, offset CRCtable - 4 xor ecx, ecx M1: mov eax, ecx mov ebx, 0EDB88320h add edi, 4 mov esi, 8 @@: shr eax, 1 sbb edx, edx and edx, ebx xor eax, edx dec esi jnz @B inc ecx mov [edi], eax cmp ecx, 256 jb M1 mov eax,offset CRCtable ret InitCRC32Table endp align 4 CRC32 proc uses ebx esi edi lpBuffer, cbBuffer mov esi, lpBuffer mov edi, offset CRCtable mov edx, cbBuffer shr edx, 1 or ecx, -1 xor eax, eax @@: mov al, [esi] xor al, cl shr ecx, 8 mov ebx, [edi+4*eax] xor ecx, ebx mov al, [esi+1] xor al, cl shr ecx, 8 mov ebx, [edi+4*eax] add esi,2 xor ecx, ebx dec edx jnz @B test dword ptr[cbBuffer], 1 jz @F mov al, [esi] xor al, cl inc esi shr ecx, 8 mov ebx, [edi+4*eax] xor ecx, ebx @@: mov eax, ecx not eax ret CRC32 endp
base.rc:
;This Resource Script was generated by WinAsm Studio. #define IDB_GEN 1001 #define IDB_PATCH 1002 #define IDB_QUIT 1003 #define IDC_NAME 1004 #define IDC_DATE_STATIC 1005 #define IDC_LBLNAME 1006 #define IDC_CHECKBOX 1007 101 DIALOGEX 0,0,207,59 FONT 8,"Tahoma" STYLE 0x80c80880 EXSTYLE 0x00000000 BEGIN CONTROL "",IDB_GEN,"Button",0x10000000,113,31,50,14,0x00000000 CONTROL "",IDB_QUIT,"Button",0x10000000,170,31,29,14,0x00000000 CONTROL "",IDB_PATCH,"Button",0x10000001,57,31,51,14,0x00000000 CONTROL "",IDC_NAME,"Edit",0x10000080,31,12,171,12,0x00000200 CONTROL "",IDC_DATE_STATIC,"Static",0x58000000,3,49,44,9,0x00000000 CONTROL "",IDC_LBLNAME,"Static",0x50000000,3,15,24,10,0x00000000 CONTROL "",IDC_CHECKBOX,"Button",0x50010003,3,34,27,10,0x00000000 END
make.bat:
@echo off \masm32\bin\rc /v base.rc \masm32\bin\ml.exe /c /coff /Cp /nologo base.asm \masm32\bin\link.exe /SUBSYSTEM:WINDOWS /RELEASE /VERSION:4.0 /OUT:KeyfileMaker.exe base.obj base.res del base.res del base.obj pause
Une fois compilé, ça ressemble à ça:
On place l'exécutable dans le répertoire d'installation du programme et on s'occupe de son cas.
Et voilà c'est déjà la fin.
En complèment voici un autre tuto que j'ai réalisé sur le chiffrement RSA.
À une prochaine fois!
Xylitol, 25/09/2021
Copyright (C)- xtx Team (2021)