Il y a quelques jours, j’ai travaillé sur la sécurité d’une application web. Cette dernière demandait à l’utilisateur de payer une licence afin de faire disparaitre le texte “version demo”. Je montrerai le travail de recherche et d’analyse du code PHP et Javascript la semaine prochaine, pour le moment intéressons nous à la création d’un keygen (générateur de clé) à partir d’un algorithme donné. Je précise une fois de plus que cet article a pour but de faire “découvrir” une petite partie de la “sécurité informatique” et non d’inciter au piratage.
Rappel sur les keygens :
Un générateur de clés, aussi appelé keygenerator ou tout simplement keygen, est un logiciel générant des numéros de série afin d'installer/déverrouiller/lancer une application.
Un générateur de clés a deux moyens pour trouver une clé-cd valide : la méthode brute force et la méthode qui consiste à reconstituer l'algorithme utilisé par la société éditrice du logiciel.
J’en profite aussi pour préciser les expressions algorithmiques utilisées dans cet article :
- POS(X) : retourne le caractère à la position X, en partant de 0, d’une string quelconque.
- X MOD Y : retourne X modulo Y
- LEN(STR) : retourne la longueur d’une string
Les postulats sur lesquels nous nous baserons :
- On se basera sur la string DK suivante (si quelqu’un connait le nom technique je suis intéressé) : 123456789ABCDEFGHJKLMNPQRSTUVWXYZ
- La clé (licence key) que doit entrer l’utilisateur est de 11 caractères ou plus.
- Nous comptons, pour les positions de caractère par exemple, à partir de 0.
Une fois la clé de licence spécifiée, le programme va effectuer les traitements suivants afin de définir la validité d’une clé :
- Création d’une seconde clé (clé temporaire/intermédiaire à partir de la clé de licence entrée par l’utilisateur) sous la forme : [11][0][8][12]
- [11] est la caractère en 11ème position de la licence originale
- Si la licence originale est ZK5JC9EO6IEGP alors la clé intermédiaire sera GZ6P
- On vérifie à partir de cette clé intermédiaire que :
- Le modulo de la position du second caractère sur DK est différent de 1. On trouvera alors [0] c’est à dire le caractère en 0ème position de notre clé de licence finale.
- Par exemple pour 12 :
12 MOD 5 = 2 //12 est valide (modulo différent de 1) on cherche donc le caractère correspondant
POS(12) = C //C est donc un caractère possible en position 1 pour notre clé intermédiaire et en position 0 pour notre clé finale
[0] = C
- On prends aléatoirement les positions des 0ème et 2ème caractères sur DK
- La position du 3ème caractère doit être égale à (j'ai décomposé le code pour une lecture plus aisée) :
X = POS([11]) + POS([8]) //on additionne les positions sur DK de 0ème et 3ème caractère
X *= 9
X = X Mod (Len(DK) - 1) //on repositionne X sur DK
[12] = POS(X) //le 3ème caractère de notre clé intermédiaire est donc à la position X sur DK
- Le modulo de la position du second caractère sur DK est différent de 1. On trouvera alors [0] c’est à dire le caractère en 0ème position de notre clé de licence finale.
L’idée est donc de générer aléatoirement des licences qui correspondent à cet algorithme. Voici un code VB6 permettant de résoudre cette problématique :
Randomize '(re)initialisation du moteur de nombre aléatoire
Dim dK as String
dK = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim sr(12) As String 'clé de licence finale que nous allons générer
'#########################################
' Traitement sur la clé intermédiaire
'#########################################
Dim tmp0, tmp1, tmp2, tmp3 As Integer
'Recherche du 2ème caractère
tmp = 1
Do While ((tmp Mod 5) = 1)
tmp = rand(1, Len(dK))
Loop
sr(1) = Mid(dK, tmp, 1)
'On créé le 0ème & 2ème caractère
tmp0 = rand(0, Len(dK) - 1)
tmp2 = rand(0, Len(dK) - 1)
sr(0) = Mid(dK, tmp0 + 1, 1)
sr(2) = Mid(dK, tmp2 + 1, 1)
'Le 3ème caractère doit être égal à
tmp3 = tmp0 + tmp2
tmp3 = tmp3 * 9
tmp3 = tmp3 Mod (Len(dK) - 1)
sr(3) = Mid(dK, tmp3 + 1, 1)
'#########################################
' On en déduit ensuite la clé finale
'#########################################
'Ordre : [11][0][8][12]
sr(11) = sr(0)
sr(0) = sr(1)
sr(8) = sr(2)
sr(12) = sr(3)
sr(1) = Mid(dK, rand(1, Len(dK)), 1)
sr(2) = Mid(dK, rand(1, Len(dK)), 1)
sr(3) = Mid(dK, rand(1, Len(dK)), 1)
sr(4) = Mid(dK, rand(1, Len(dK)), 1)
sr(5) = Mid(dK, rand(1, Len(dK)), 1)
sr(6) = Mid(dK, rand(1, Len(dK)), 1)
sr(7) = Mid(dK, rand(1, Len(dK)), 1)
sr(9) = Mid(dK, rand(1, Len(dK)), 1)
sr(10) = Mid(dK, rand(1, Len(dK)), 1)
'La clé finale = Join(sr, "")
J’utilise des variables intermédiaires et de nombreux appelles à la fonction rand. Ce code est très facilement optimisable mais j’ai préféré le décomposer afin de faire ressortir l’algorithme de base et pour que cet article soit accessible au plus grand nombre.
Si vous avez aimé cet article ou si vous avez des demandes particulières, n’hésitez pas à le faire savoir en commentaire. N’oubliez pas de vous inscrire au flux rss du blog :).