|
WinRar peut être considéré comme un programme paradoxal!
D'un coté il est assez simple à cracker, de l'autre il me semble qu'à ce jour personne n'a
encore trouvé comment générer un serial valide.
Il ne s'agit pas ici de proposer un nouveau tut sur cette protection. TeeJi avait déjà étudié
la version 2.50 en mettant en évidence le flag "is_registered" et la manière de
le mettre à 01, et Alien, pour la version 2.60 s'était attaqué à
la key File (rarreg.*).
Pour ces trois versions, le principe de cette protection est restée identique.
Je ne développerai donc pas le "How To crack", mais plutôt la partie qui m'intéressait,
à savoir apprendre comment gérer en ASM des fichiers Key, et pouvoir créer un patch.
La solution que j'ai donc retenue est la création d'un fichier rarreg.key et sa validation par le programme.
Sans le KeyFile le patch du programme ne donnera rien de mieux que la version d'évaluation, l'adresse patchée
n'étant lue par Winrar que si un fichier rarreg.* a été détecté.
L'approche de TeeJi:
Recherche de la string "evaluation copy" du bandeau d'écran:
:00434E95 803D083B470000 cmp byte ptr [00473B08], 00
:00434E9C 752A jne 00434EC8
* Possible Reference to String Resource ID=00873: "evaluation copy
Une seule occurrence, où l'on retrouve le flag "Is_registered"
comme dans la version 2.50: [00473B08]
Une recherche rapide va permettre de cibler 4 manipulations sur cette adresse
:0042415C E88FD1FFFF call 004212F0
:00424161 803D083B470000 cmp byte ptr [00473B08], 00 is_registered?
:00424168 7410 je 0042417A
:0042416A 803D0435470000 cmp byte ptr [00473504], 00 is_name_present (dans la keyFile)
:00424171 7507 jne 0042417A
:00424173 C605083B470000 mov byte ptr [00473B08], 00 user not registered
Cette première manipulation (avec un call 004212F0 qui est sollicité
par 35 appels) va principalement définir si un fichier rarreg.* est présent et non vide (ce fichier
peut avoir n'importe quelle extension, .txt marche tout aussi bien que .key).
* Reference To: KERNEL32.GetLocalTime, Ord:0000h
|
:0042B1BB E8F0CF0300 Call 004681B0
:0042B1C0 33C0 xor eax, eax
:0042B1C2 E8D1A3FEFF call 00415598
:0042B1C7 A2083B4700 mov byte ptr [00473B08], al
Cette seconde manipulation fait suite au contrôle de la fin de la période
d'essai:
- saisie de la date
- vérification du statut utilisateur
Les deux dernières manipulations sont liées à la validation
du KeyFile.
Vous aurez remarqué que ces trois derniers extraits du Dead Listing font tous référence au
call 00415598.
Dans la mesure ou la première manipulation est liée à l'absence d'un fichier rarreg.*, seul
le call repéré va nous intéresser.
Affichage, ou non, de "evaluation copy" dans le bandeau d'écran
:00433C8A B001 mov al, 01 > mise à 01 du flag
:00433C8C E80719FEFF call 00415598 > contrôle du contenu du KeyFile
:00433C91 A2083B4700 mov byte ptr [00473B08], al > AL=01 -> User registered
Affichage, ou non, de "40 Day trial" dans l'écran About
:0043460A B001 mov al, 01
:0043460C E8870FFEFF call 00415598
:00434611 A2083B4700 mov byte ptr [00473B08], al
C'est donc le Call 00415598 qui est LE call où le KeyFile est vérifié:
- Présence d'un name et serial
- Génération de la clé
- Vérification de la clé
- AL = 0 ou 1 en fonction du résultat
A la sortie de ce call, en présence d'un faux serial, vous arrivez ici:
:00415890 E8033B0000 call 00419398
:00415895 8BD8 mov ebx, eax
:00415897 3B9E00060000 cmp ebx, dword ptr [esi+00000600]
:0041589D 7424 je 004158C3
:0041589F 33C0 xor eax, eax > Bad_KeyFile
Pour que le serial soit reconnu comme valide, il faudrait que le programme passe
ici:
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00415965(C), :00415A07(C)
|
:00415A2A B001 mov al, 01 > Flag KeyFile_OK
via deux Strings Data ref de ce type:
* Possible StringData Ref from Data Obj ->"70c2441db366d92ea7be1342b3bf629026ba92bb675f06"
->"e684bdd34511097434"
Qui laissent préfigurer de la forme que pourrait avoir le serial.
Tout se joue entre le "je 004158C3" en 0041589D et l'adresse 00415A2A mov al, 01.
Une petite portion de code...
En définitive, c'est le Xor EAX,EAX en 0041589F que j'ai décidé de modifier.
Dans la mesure ou le Flag Is_registered ne porte que sur l'état du registre AL, un simple Mov AL,01 (quelque
soit la valeur contenue dans EAX) va suffire à valider le KeyFile et votre statut.
Mon petit programme devra donc:
- vérifier la présence du 33C0 et le remplacer par un B001
- créer un keyFile dont la forme sera reconnue pour pouvoir au moins arriver en 004158F.
Reste à trouver l'allure que devra avoir ce KeyFile.
Dans son tut Alien avait proposé de remplir ce fichier avec un Name et un serial (dans cette ordre), mais
au premier essai, seul le serial apparaissait. Dans une seconde tentative, il avait inversé cet ordre (Serial
+ Name), et seul son Nom était apparu.
j'en ai déduis qu'en fait ce fichier devait être composé de trois lignes (j'ai essayé
avec quatre lignes...), et que la première d'entre elles ne serait pas affichée.
Bien joli toutes ces suppositions, mais un peu trop empiriques quand même....
En regardant dans la liste des APIs utilisées, deux d'entre elles pourraient nous donner de plus amples
informations:
- ReadFile (utilisé pour la lecture de datas dans un fichier)
- GetPrivateProfileStringA (Utilisé pour récupéré une string d'une section spécifiée
dans un fichier d'initialisation).
Commençons par la première API:
:004066DB push 00000000 > adresse de la structure pour les datas
:004066DD lea eax, dword ptr [esp+04] > adresse du nombre d'octets lus,
:004066E1 push eax > poussée sur la pile
:004066E2 push esi > nombre d'octets à lire (53h dans notre cas)
:004066E3 push edi > adresse du buffer qui recevra les datas
:004066E4 push [ebx+04] > handle du fichier à lire
:004066E7 Call KERNEL32.ReadFile
Le programme devant récupérer le handle du fichier à lire,
ce handle est retourné par CreateFileA:
:0040629B push [ebp-04] > pointe vers le nom du fichier
:0040629E Call CreateFileA
Ce nom du fichier va être C:\Program Files\WinRar\rareg.key
Et ce fichier doit contenir un maximum de 83 caractères (53h).
La taille du Name étant aléatoire, d'un utilisateur à l'autre (disons 10 caractères),
la première ligne du fichier pouvant en consommer autant, il resterait environ 63 caractères pour
composer le serial. Or les strings ressemblant à des serials rencontrées dans Wdasm sont de 64 caractères,
ce qui semblerait confirmer que le serial pourrait être composé d'autant de digits.
ReadFile pouvant être utilisé pour lire n'importe quel type de données dans un fichier, son
utilisation ne nous apprend pas grand chose.
GetPrivateProfileStringA pourrait se révéler intéressant dans la mesure ou ce type de foncion
est principalement utilisée pour des fichiers d'initialisation dans lequel on trouve un nom de section (ici
[registration]) et un nom de clé (informated=) suivi des données à saisir par l'API.
[registration]
regname=Christal
regcode=12345678
informed=0
En fait, cette API est utilisée pour lire un fichier RAR.INI (inexistant)
et dans lequel le programme cherche à trouver des données pour:
:0042AC70 push "regname" > nom de la clé
:0042AC75 push "registration" > nom de la section
:0042AC7A Call GetPrivateProfileStringA
puis
:0042AC8F push "regcode"
:0042AC94 push "registration"
:0042AC99 Call GetPrivateProfileStringA
et enfin
:0042ACA1 push "informed"
:0042ACA6 push "registration"
:0042ACAB Call GetPrivateProfileIntA > attend un nombre entier
Mais en jouant avec ces adresses, on aboutit à un écran qui nous apprends que depuis la version 2.60,
le principe d'enregistrement a été renforcé, puis WritePrivateProfileStringA met la clé
"informed" à 01 pour se souvenir qu'il est inutile d'afficher cet écran par la suite (comme
vous pourrez vous en rendre compte, à condition que vous n'ayez pas un fichier rareg.* déjà
créé):
[registration]
regname=Christal
regcode=12345678
informed=1
Nous voilà guère plus avancé pour la création de notre
KeyFile.
A défaut, j'ai donc choisi un KeyFile qui afficherait le Nom qui vous aurez entré dans le champ de
mon générateur de Key suivi d'un petit message, et qui serait créé sur ce modèle:
[registration]
Your name
WinRar 2.80 KeyFile
N'étant ni codeur, ni cracker ou quoi que ce soit d'autre, je me suis inspiré
de sources déjà existant, dont ceux de papow, SyntaxError et Iczelion, pour réaliser mon générateur/patcheur.
Un merci tout particulier à SyntaxError et à TaxerZ qui m'ont bien briefé lors d'un passage
sur le channel #crack.fr (undernet)
;=========================================================================
; Ce source ASM est dérivé de celui de:
; Papaow pour la partie graphique et la trame de ce source
; (développé lors d'un précedent texte sur les KeyGenerator)
; SyntaxError pour la partie Patch de Winrar.exe
; Iczelion (traduit par Morgatte) pour la partie KeyFile
; Un grand merci à tous!
;=========================================================================
.386
.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\gdi32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\masm32.lib
;=========================================================================
.const
;=========================================================================
Prog equ "WinRar 2.80"
Auteur equ "Christal"
;=========================================================================
IDC_Gen equ 3001
IDC_Exit equ 3002
IDC_About equ 3003
.data
;=========================================================================
; Données dont vous aurez besoin
;=========================================================================
Erreur db "Mettez au moins une lettre...",0
Already db "Un fichier Key existe déjà !",0
no_here db "Le Fichier WinRar.exe est absent !",0
badversion db "Ce n'est pas la bonne version de WinRar !",0
PasGlop db "Le patch a échoué !",0
ClassName db "WinClass",0
NameApp db Prog," KeyFile by [Your name]",0
EditClass db "edit",0
StaticClass db "static",0
ButtonClass db "button",0
DlgName db "Dialog",0
IconName db "Icon2",0
TextAbout db "KeyFile Maker pour Win Rar 2.80",0Dh,0Ah,0Ah,0Ah
db "Coded by Christal",0
Caption db Prog,0
TextNom db "Enter your name here:",0
TextCoded db "cODED bY [Your name]",0
ButtonAbout db "&About",0
ButtonExit db "&Exit",0
ButtonGen db "&Generate",0
FontString db "Arial", 0
cle_serial db "RegName",0
Well_done db "Key File créée",0
prg_name db "\WinRar.exe",0
Path_Key_File db "\rarreg.key",0
dont_touch db "[registration]",0Dh,0Ah
fmap dd ? ; handle du fichier mappé
faddr dd ? ; adresse du début du fichier mappé
Lg_path DWORD 0
.data?
;=========================================================================
; Variables dont vous aurez besoin
;=========================================================================
hInstance HINSTANCE ?
CommandLine LPSTR ?
CommandLine2 LPSTR ?
hwnd HWND ?
hwndButton HWND ?
hwndEdit1 HWND ?
hwndEdit2 HWND ?
hwndStatic1 HWND ?
hwndStatic3 HWND ?
hwndButton1 HWND ?
hwndButton2 HWND ?
hwndButton3 HWND ?
buffer db 512h dup (?)
lg_name DWORD ?
Font1 DWORD ?
Directory DWORD ?
SizeReadWrite DWORD ? ; Nombre d'octets à écrire
hFile HANDLE ? ; Handle du fichier.
.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
mov CommandLine, eax
;=========================================================================
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
;=========================================================================
; Traçage de la boite de dialogue
;=========================================================================
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_DBLCLKS
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszClassName,OFFSET ClassName
invoke LoadImage,hInstance,ADDR IconName,IMAGE_ICON,32,32,LR_LOADMAP3DCOLORS
mov wc.hIcon,eax
mov wc.hIconSm,NULL
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowExA,WS_EX_WINDOWEDGE,\
ADDR ClassName,ADDR NameApp,\
WS_SYSMENU or WS_MINIMIZEBOX or WS_DLGFRAME or WS_BORDER\
or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or WS_VISIBLE,\
280,200,385,162,NULL,NULL,hInst,NULL
mov hwnd,eax
INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
INVOKE UpdateWindow, hwnd
.WHILE TRUE
INVOKE GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
;=========================================================================
; Tracage de la DialogBox et Gestion des événements (voir précedent texte)
;=========================================================================
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
mov eax,uMsg
.IF eax==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF eax==WM_CREATE
invoke CreateWindowExA,WS_EX_CLIENTEDGE, ADDR EditClass,NULL,\
WS_CHILDWINDOW or WS_MAXIMIZEBOX or WS_VISIBLE or\
ES_AUTOHSCROLL,12,30,261,23,hWnd,NULL,hInstance,NULL
mov hwndEdit1,eax
invoke CreateWindowExA,WS_EX_CLIENTEDGE, ADDR EditClass,NULL,\
WS_CHILDWINDOW or ES_READONLY or WS_VISIBLE or\
ES_AUTOHSCROLL,12,80,261,23,hWnd,NULL,hInstance,NULL
mov hwndEdit2,eax
invoke CreateWindowExA,WS_EX_NOPARENTNOTIFY, ADDR StaticClass,ADDR TextNom,\
WS_CHILD or WS_VISIBLE or ES_LEFT ,\
12,15,180,15,hWnd,NULL,hInstance,NULL
mov hwndStatic1,eax
invoke CreateWindowExA,WS_EX_NOPARENTNOTIFY, ADDR StaticClass,ADDR TextCoded,\
WS_CHILD or WS_VISIBLE or ES_LEFT ,\
12,110,180,15,hWnd,NULL,hInstance,NULL
mov hwndStatic3,eax
invoke CreateWindowExA,NULL, ADDR ButtonClass,ADDR ButtonAbout,\
WS_CHILDWINDOW or WS_MAXIMIZEBOX or WS_VISIBLE or WS_GROUP or WS_TABSTOP,\
295,100,75,23,hWnd,IDC_About,hInstance,NULL
mov hwndButton1,eax
invoke CreateWindowExA,NULL, ADDR ButtonClass,ADDR ButtonExit,\
WS_CHILDWINDOW or WS_VISIBLE or WS_CLIPSIBLINGS,\
295,40,75,23,hWnd,IDC_Exit,hInstance,NULL
mov hwndButton2,eax
invoke CreateWindowExA,NULL, ADDR ButtonClass,ADDR ButtonGen,\
WS_CHILDWINDOW or WS_VISIBLE or WS_CLIPSIBLINGS\
or BS_DEFPUSHBUTTON,\
295,10,75,23,hWnd,IDC_Gen,hInstance,NULL
mov hwndButton3,eax
invoke SetFocus, hwndEdit1
invoke CreateFontA, -11, -5, 0, 0, 150, FALSE, FALSE, FALSE,\
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY, DEFAULT_PITCH,ADDR FontString
mov Font1, eax
invoke PostMessageA, hwndStatic1, WM_SETFONT, Font1, TRUE
invoke PostMessageA, hwndButton1, WM_SETFONT, Font1, TRUE
invoke PostMessageA, hwndButton2, WM_SETFONT, Font1, TRUE
invoke PostMessageA, hwndButton3, WM_SETFONT, Font1, TRUE
invoke PostMessageA, hwndStatic3, WM_SETFONT, Font1, TRUE
.ELSEIF eax==WM_COMMAND
mov eax,wParam
.IF ax==IDC_About
shr eax,16
.IF ax==BN_CLICKED
invoke MessageBoxA, NULL,addr TextAbout, addr Caption,040h
.ENDIF
.ENDIF
.IF ax==IDC_Gen
shr eax,16
.IF ax==BN_CLICKED
invoke GetWindowTextA,hwndEdit1,ADDR buffer,512
;=========================================================================
; Key File generator et Patch
;=========================================================================
cmp eax,00 ; champ Name rempli?
je Trop_court ; Goto msg error
mov word ptr [eax+buffer],0A0Dh ; rajoute un RTN chariot
add eax,2 ; et modifie la lg du buffer Name
mov lg_name, eax ; enregistre la lg du name
invoke GetCurrentDirectory,128,ADDR Directory ; récupère le Path
mov Lg_path,eax ; enregistre sa longueur
mov edi, offset Directory ; et y ajoute le nom
Add edi,eax
mov esi, offset Path_Key_File ; de la KeyFile
mov ecx, 11
rep movsb
; création du fichier rarreg.key
invoke CreateFile,ADDR Directory,GENERIC_READ or GENERIC_WRITE ,\
FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,NULL
cmp eax,-1 ; eax renvoi le Handle du fichier créé
jne @@1 ; si un fichier identique existe
jmp reg_exist ; la valeur de retour sera égal à -1
@@1:
mov hFile,eax ; hFile = handle du fichier créé
; le fichier rareg.key contient trois lignes:
; [Registration] , le nom saisie dans la DlgBox , et ce qui correspondrait au serial
mov eax, 14 ; = longueur de [Registration]
invoke WriteFile,hFile,ADDR dont_touch,EAX,ADDR SizeReadWrite,NULL
mov eax, lg_name ; taille du Name entré
invoke WriteFile,hFile,ADDR buffer,eax,ADDR SizeReadWrite,NULL
mov eax,33 ; = taille du "serial" à écrire
invoke WriteFile,hFile,ADDR NameApp,EAX,ADDR SizeReadWrite,NULL
;BOOL WriteFile
; HANDLE hFile, // handle du fichier à remplir
; LPCVOID lpBuffer, // pointeur vers les data à écrire
; DWORD nNumberOfBytesToWrite, // nombre d'octets à écrire
; LPDWORD lpNumberOfBytesWritten, // pointe vers "l'adresse" où doit être écrit les Data
; LPOVERLAPPED lpOverlapped // pointe vers la structure nécessaire pour overlapped I/O
; lpNumberOfBytesWritten est géré par la fonction WriteFile et pointe vers le nombre d'octets
; écrits par la fonction. WriteFile met cette valeur à zero avant de faire quoi que ce soit.
; lpNumberOfBytesWritten est incrémenté par WriteFile à chaque octet écrit.
; Si vous devez écrire dans un endroit particulier du fichier, il vous faudra connaître le nombre
; d'octets ("l'adresse" du pointeur) à partir duquel vous voudrez écrire
; Patch de WinRar.exe: recherche de la présence de l'exécutable
invoke GetCurrentDirectory,128,ADDR Directory ; récupère le Path
mov Lg_path,eax ; enregistre sa longueur
mov edi, offset Directory ; et y ajoute le nom
Add edi,eax
mov esi, offset prg_name ; de l'exe à trouver
mov ecx, 11 ; (11 caractères de long)
rep movsb
; vérifie si le fichier Winrar.exe est bien dans le même répertoire que notre prog
; et récupère le handle de la cible à modifier (patcher).
; et appel du fichier à Mapper.
invoke CreateFileA,addr Directory,GENERIC_READ+GENERIC_WRITE,\
FILE_SHARE_READ+FILE_SHARE_WRITE,0, OPEN_EXISTING,\
FILE_ATTRIBUTE_NORMAL,0
cmp eax,-1 ; si EAX=-1
jz absent ; WinRar.exe est absent
mov hFile,eax ; hFile = handle du fichier trouvé
; Les (Files Mapping) configurations de fichiers vont permettre de lire et écrire dans un fichier.
; Pour utiliser la configuration de fichier, vous pouvez vous imaginer que c'est un fichier entier,
; déjà chargé en mémoire, et dans lequel vous pouvez employer un pointeur de mémoire
; pour lire ou écrire des données .
invoke CreateFileMapping,hFile,0,PAGE_READWRITE,0,0,addr prg_name
test eax,eax
jz umap ; la fonction a échouée, sinon
mov fmap,eax ; la valeur de retour est le handle du fichier mappé
; HANDLE CreateFileMapping
; HANDLE hFile, // handle du fichier à mapper
; LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes
; DWORD flProtect, // protection for mapping object
; DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
; DWORD dwMaximumSizeLow, // low-order 32 bits of object size
; LPCTSTR lpName // Nom du fichier à mapper
; MapViewOfFile va permettre de Mapper une région du fichier choisie ou bien le fichier entier en mémoire.
; Cette fonction renvoie le pointeur du premier octet de la zone où commence le fichier configuré (Mappé).
invoke MapViewOfFile,fmap,FILE_MAP_WRITE,0,0,0
test eax,eax ; la valeur de retour est l'adresse de début du mapped view
jz umap ; cad l'adresse à laquelle le fichier commence en mémoire
;LPVOID MapViewOfFile
; HANDLE hFileMappingObject, // file-mapping object to map into address space
; DWORD dwDesiredAccess, // access mode
; DWORD dwFileOffsetHigh, // high-order 32 bits of file offset
; DWORD dwFileOffsetLow, // low-order 32 bits of file offset
; DWORD dwNumberOfBytesToMap // number of bytes to map
mov faddr,eax ; On a notre pointeur !!!
mov edx,eax
cmp word ptr ds:[edx],'ZM' ; c'est un .exe ?
jnz Pas_Glop
mov eax,dword ptr ds:[edx+3Ch]
add eax,faddr
cmp word ptr ds:[eax],'EP' ; au bon format ?
jnz Pas_Glop
mov eax,edx ; on rajoute la valeur de l'offset à patcher
add eax, 00014E9Fh ; au pointeur de début du fichier mappé
cmp word ptr [EAX],49203 ; vérifie que l'on va modifier la bonne version
jne bad_version
mov word ptr [EAX],01B0h ; et on patch
; Dans l'exemple d'Iczelion (traduit par Morgatte), la modification d'un fichier peut être
; fait avec la fonction WriteFile, à condition de correctement paramètrer l'adresse à patcher
jmp GlopGlop
;=========================================================================
; Affichage des messages
;=========================================================================
Trop_court:
invoke SetWindowTextA,hwndEdit2,ADDR Erreur
jmp Fin
reg_exist:
invoke SetWindowTextA,hwndEdit2,ADDR Already
jmp Fin
absent:
invoke SetWindowTextA,hwndEdit2,ADDR no_here
jmp Fin
bad_version:
invoke SetWindowTextA,hwndEdit2,ADDR badversion
jmp Umapping
Pas_Glop:
invoke SetWindowTextA,hwndEdit2,ADDR PasGlop
jmp Umapping
umap:
invoke SetWindowTextA,hwndEdit2,ADDR Already
jmp Umapping
GlopGlop:
invoke SetWindowTextA,hwndEdit2,ADDR Well_done
Umapping:
; UnmapViewOfFile va Unmapper le fichier
invoke UnmapViewOfFile,faddr
; CloseHandle avec l'Handle renvoyé par CreateFile va fermer le fichier réel.
invoke CloseHandle,hFile
Fin:
;=========================================================================
; Fin
;=========================================================================
.endif
.endif
.IF ax==IDC_Exit
invoke ExitProcess,eax
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
ret
WndProc endp
end start
;=========================================================================
;* Fin de KeyGen.asm *
;* KeyGen.rc *
Icon2 ICON "icon2.ico"
;* Fin de KeyGen.rc *
;=========================================================================
|
|