Keygenner S*m*a*r*tC*a*p*t*u*r*e v3.17.4

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...




I: Démarrage:


Installons le programme et exécutons-le pour voir comment il réagit.

1


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


1


On fait défiler le listing, et on repère des strings potentiellement intéressants:


1


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!


1


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


1


On continue à tracer et on tombe sur FindFirstFile avec un flag *DeskSoftLicense
on repasse ensuite dans le même segment avec en flag *.dlc


1


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.


1


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.


1


Entrons dans le CALL, le contenu du fichier DLC est récupéré.


1


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).


1


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)


1


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

1


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

1


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

1


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

1


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

1


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é.


1


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

1


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

1


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.


1


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)


1


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.


1


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.


1


Ensuite il récupère le buffer contenant le keyfile tronqué, puis le hash.


1


Puis il récupère notre chaine pour la valeur [License] du keyfile, et tente de vérifier la signature.


1


Celle-ci n'est pas bonne évidement.
Ensuite le programme détruit les handles, et on sort de la routine.


1


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.


1


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.


1


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:

1



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:

1



On place l'exécutable dans le répertoire d'installation du programme et on s'occupe de son cas.

1


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)

XHTML valide 1.1 CSS Valide !