Je crois que cela répondra à plusieurs posts ici et sur le forum EN.
Code : Tout sélectionner
;
; Workaround for a program usage counter
; I guess it is interesting and well documented.
; This shows how to manage a usage counter encrypted in the executable itself.
; So you should save the source at a given place with a choosen name and compile it.
; For testing it properly, run the executable.
; As it is, this workaround will inform you of the license expiration after 3 runs.
;
; Read carefully comments and also I hope variable names are clear enough for understanding this.
;
; By extension, it is easy now to hard code ie the executable name in the same way and binary area, so that if
; the first executable name is not the same that the running, you can freeze the app, or do anything you want.
; ----------------------------------------------------
; Essai de cryptage d'un compteur d'utilisation d'un prog
; Je pense que c'est intéressant et bien documenté.
; Ce programme montre comment gérer un compteur d'utilisation encodé dans l'exécutable lui-même.
; Il faut donc sauver le source en lui donnant un nom et le compiler.
; Pour tester correctement le fonctionnement, lancer l'exécutable.
; Tel quel, vous devriez être informé que la licence est expirée après 3 lancements.
;
; Lisez bien les commentaires, en vous aidant des noms de variables pour une bonne compréhension.
;
; Par extensio, il est maintenant facile de coder en dur le nom de l'exécutable et de le comparer
; à lexécutable en cours pour geler l'application ou interagir comme vousl le souhaitez.
;
; FWeil 20040707 : do not use this code without to inform me at fweil@internext.fr or on Purebasic forums.
;
; And you know what ? I am quite happy of this listing
;
;
; Set the size of the program messages array
; ----------------------------------------------------
; Fixe la taille du tableau des messages programme
;
#Max_Messages = 10
;
; Program messages array
; Tableau des messages du programme
;
Dim Messages.s(#Max_Messages)
;
; Procedure GetUserLanguage() : user language detection
; ----------------------------------------------------
; Procedure GetUserLanguage() : détection de la langue utilisateur
;
Procedure.s GetUserLanguage()
Language.s
GetSystemDefaultLangID = GetSystemDefaultLangID_()
Select GetSystemDefaultLangID
Case 1036 ; = French (Standard)
Language = "FR"
Default
Language = "EN"
EndSelect
ProcedureReturn Language
EndProcedure
;
; Procedure Encrypt() : string encryption. The string can be decrypted using Decrypt()
; Both Encrypt() / Decrypt() procedures are symetrical, usable, but simple. You can change it by any encrypt / decrypt process you know or design.
; Just if you adapt this code, do not forget that the reserved space for the key is assigned by the second data of the KeyManagement: label in data section
; ----------------------------------------------------
; Procedure Encrypt() : encodage d'une chaine de caractères. La chaine peut être décodée avec Decrypt()
; Les procédures Encrypt() / Decrypt() sont symétriques, utilisables, mais simples. On peut les changer par tout procédé de codage / décodage connu ou personnalisé.
; Si ce code est changé, il faut simplement ne pas oublier que l'espace réservé pour la clé est défini par la deuxième donnée de la section data identifiée par KeyManagemen:
;
Procedure.s Encrypt(String.s)
Result.s = ""
For i = 1 To Len(String)
Cod = Asc(Mid(String, i, 1))
Result + Chr(((Cod & $F0) >> 4) + ($80 + Random($7F) & $F0)) + Chr((Cod & $0F) + ($80 + Random($7F) & $F0))
Next
ProcedureReturn Result
EndProcedure
;
; Procedure Decrypt() : string decryption using symmetrical algorythm in connection with Encrypt()
; ----------------------------------------------------
; Procedure Decrypt() : décodage d'une chaine de caractères en utilisant l'algorithme symétrique de Encrypt()
;
Procedure.s Decrypt(String.s)
Result.s = ""
For i = 1 To Len(string) Step 2
Result + Chr(((Asc(Mid(String, i, 1)) & $0F) << 4) + (Asc(Mid(String, i + 1, 1)) & $0F))
Next
ProcedureReturn Result
EndProcedure
ProgramName.s = Space(#MAX_PATH)
GetModuleFileName_(0, @ProgramName, #MAX_PATH)
;
; User language detection and data section positioning to load program messages accordingly
; ----------------------------------------------------
; Détection de la langue utilisateur et placement approprié dans la zone data pour lire les messages du programme
;
Select GetUserLanguage()
Case "FR"
Restore FR
Default
Restore EN
EndSelect
CurrentMessage = 0
Repeat
Read Message.s
Messages(CurrentMessage) = Message
CurrentMessage + 1
Until Message = "EndDataSection"
;
; Data section positioning and read of the key to use to find the place of the usage counter
; ----------------------------------------------------
; Positionnement dans la zone data pour trouver la clé permettant d'accéder au compteur d'utilisation
;
Restore KeyManagement
Read Patch_Marker.s
;
; Program launch loading the encrypted 'usage counter' information
; This information is decrypted and parsed, and eventually updated information is encrypted again for saving in the file.
; ----------------------------------------------------
; Lancement du programme avec chargement de l'information 'compteur d'utilisation' encryptée
; Cette information est décryptée et analysée, puis mise à jour est ré-encryptée et enregistrée dans le fichier.
;
If ReadFile(0, ProgramName)
*Buffer = AllocateMemory(Lof())
ReadData(*Buffer, Lof())
For i = 0 To Lof()
If PeekS(*Buffer + i, 6) = Patch_Marker
CounterAddress = *Buffer + i + 6 ; CounterAddress is the address where the counter stays in the memory buffer
Break
EndIf
Next
If i => Lof()
MessageRequester(Messages(0), Messages(1), #PB_MessageRequester_OK)
EndIf
CloseFile(0)
Else
MessageRequester(Messages(0), Messages(1), #PB_MessageRequester_OK)
EndIf
If CounterAddress
Usage_Counter = Val(Decrypt(PeekS(CounterAddress, 6)))
CounterAddress - *Buffer ; now the counter address is set to the file address, no more in the memory buffer
Else
Usage_Counter = 0
EndIf
FreeMemory(*Buffer)
;
; The counter value is placed in a buffer for editing in the file
; ----------------------------------------------------
; Le compteur est copié dans un buffer pour mise à jour du fichier
;
*Key = AllocateMemory(6)
Usage_Counter + 1
PokeS(*Key, Encrypt(RSet(Str(Usage_Counter), 3, "0")))
;
; Here is the executable patch with the updated count
; ----------------------------------------------------
; Ici se trouve le patch du code exécutable avec le compteur à jour
;
If OpenFile(0, ProgramName)
FileSeek(CounterAddress)
Debug WriteData(*Key, 6)
CloseFile(0)
EndIf
;
; In this skeleton I set the counter to 2. Don't forget to change this if you want to be smart
; ----------------------------------------------------
; Pour ce jeu d'essai j'ai mis le compteur à 2. N'oubliez pas de changer cette valeur pour être sympa dans vos applications
;
If Usage_Counter > 2
MessageRequester(Messages(0), Messages(2), #PB_MessageRequester_OK)
Quit = #TRUE
Else
Quit = #FALSE
EndIf
;
; From there the job is finished for the usage counter and you can place any regular app just using Quit #TRUE / #FALSE to do something or exit.
; ----------------------------------------------------
; A partir de là la gestion de compteur est terminée et on peut placer tout code de programme sous le contrôle éventuel de Quit #TRUE / #FALSE par exemple.
;
If Quit = #FALSE
MessageRequester("OK", "OK", #PB_MessageRequester_OK)
EndIf
End
;
; Data section contains two data blocks corresponding to accepted languages
; ----------------------------------------------------
; La zone data contient les messages du programme avec un bloc pour chaque langue reconnue
;
DataSection
FR:
Data.s "Alerte"
Data.s "Le programme ne peut être lancé : installation défaillante"
Data.s "Le programme a été utilisé au delà de la licence accordée"
Data.s "EndDataSection"
EN:
Data.s "Warning"
Data.s "Can't run the program : bad installation"
Data.s "Program used more than the license authorized"
Data.s "EndDataSection"
EndDataSection
DataSection
KeyManagement:
;
; Marker string to identify the position to use in the binary file
; ----------------------------------------------------
; Chaine marqueur pour identifier la position à utiliser dans le fichier binaire
;
Data.s "SKBLZZ"
;
; Dummy string used as a reserved space in the binary file. This dummy string should not contain a valid number as Val(String) must equal 0.
; It is there only to lay in the binary code after compiling, and it will be changed each time the user will run the executable.
; ----------------------------------------------------
; Chaine factice utilisée comme réservation d'espace dans le fichier binaire. Cette chaine ne doit pas contenir une valeur numérique car la fonction
; Val de la chaine doit retourner 0. Cette chaine est placée de manière à se trouver à la bonne place dans le code généré par le compilateur, et
; sera changée à chaque lancement du programme par l'utilisateur.
;
Data.s "TOTOTO"
EndDataSection