FlashGet 1.40 : keygenning (2/2)

Compétences requises : posséder quelques bases en coding.
Je pense qu'il est inutile de le rappeler, mais vous êtes également censé avoir lu la première partie de ce tutoriel !
Matériel requis : FlashGet 1.40 (pour tester nos serials).

Introduction

Nous avons vu précédemment quelles étaient les conditions à respecter pour qu'un serial soit potentiellement valide.
Il nous reste maintenant à mettre en pratique ces connaissances, afin de réaliser un key generator (ou keygen), produisant de clés à la volée et prenant en compte toutes les possibilités.
Pour mener à bien ce travail, nous allons procéder par étapes, en alternant les phases de rélexion et celles de coding à proprement parler. À ce propos, pour ne pénaliser personne en ce qui concerne les compilateurs, les IDEs, etc... nous utiliserons le langage JavaScript pour les exemples. Une fois que vous aurez compris le principe, libre à vous ensuite de reproduire l'algorithme dans le langage de votre choix.

Problématique et solution

Je rappelle tout d'abord à quoi doit ressembler notre serial :

Ceci correspond à ce que nous avons étudié en première partie.
Nous pouvons déjà nous faire une idée sur les moyens nécessaires pour générer un bon serial :

En quoi consiste le principe de la brute force ?
Il s'agit en fait de tester toutes les valeurs possibles que peuvent prendre les 4 caractères en question, et ce dans le but de trouver les combinaisons qui rendent la condition vraie. Lorsqu'il y a peu de caractères comme c'est le cas ici, c'est une technique qui se révèle très efficace puisqu'il y a un faible nombre de combinaisons.
Dans notre cas, si l'on prend des caractères alphanumériques uniquement (avec les lettres seulement en minuscules), cela fait 26 + 10 = 36 valeurs différentes pour chaque caractère. Le nombre de tests à effectuer est donc de 36 * 36 * 36 * 36, soit 1679616. Ceci peut paraître assez important au premier abord, mais en réalité quelques instants suffisent à un ordinateur pour effectuer cette série de tests.

Je crois qu'un petit exemple ne ferait pas de mal. Le code ci-dessous utilise la méthode que nous avons décrite précédemment pour afficher l'ensemble des possibilités de la 1ère condition.

<script language="JavaScript">

// Crée un tableau
chars = new Array();

// Remplit ce tableau avec les caractères alphanumériques (36 valeurs)
for(i = 0x30; i <= 0x39; i++)
  chars.push(i);

for(i = 0x61; i <= 0x7a; i++)
  chars.push(i);

// Teste toutes les valeurs possibles pour chaque caractère à l'aide de plusieurs boucles imbriquées
for(i = 0; i < chars.length; i++) {
  char1 = chars[i];

  for(j = 0; j < chars.length; j++) {
    char2 = chars[j];

    for(k = 0; k < chars.length; k++) {
      char3 = chars[k];

      for(l = 0; l < chars.length; l++) {
        char4 = chars[l];

        // Si la condition se révèle vraie, affiche la combinaison
        if(((char3 ^ char2) * char4 + char1) % 0x6b == 0)
          document.write(String.fromCharCode(char1) + String.fromCharCode(char2) + String.fromCharCode(char3) + String.fromCharCode(char4) + "<br/>");

      }

    }

  }

}

</script>


Enregistrez-le dans un nouveau document texte, et changez l'extension du fichier en *.htm. Lancez-le, votre navigateur va s'afficher et faire quelques calculs... Attention, le temps d'éxécution peut-être plus ou moins long selon la rapidité de votre processeur. Ne vous inquiétez donc pas si votre ordinateur rame un peu...
Vous avez sous alors les yeux les 17116 valeurs possibles. Pas mal, n'est-ce pas ?
On peut faire pareil pour les conditions 2 et 3, je vous laisse essayer.

Vous avez vu la puissance de ce système mais aussi ses limites. En effet, c'est une manière peu esthétique et plutôt lente pour trouver un serial, et puis notre keygen n'a pas besoin d'afficher toutes les possibilités lors de chaque clic sur le bouton Générer, mais bien une seule choisie de manière aléatoire. Ceci pose problème, car contrairement aux cas où le serial est calculé à partir du nom de l'utilisateur, nous avons ici cette notion de valeur aléatoire à prendre en compte. Et il y a aussi cette difficulté à rendre les conditions vraies, puisque l'on est obligé d'avoir recours à la brute force.

Mais il y a une chose dont nous n'avons pas parlé jusqu'à présent : il s'agit du temps de calcul d'une possibilité, et non de toutes à la fois. Vous ne voyez pas où je veux en venir ? Prenez le temps d'éxécution du script précédent, divisez-le par 17116. Vous remarquerez que l'on peut générer une possibilité de manière quasi-instantanée. Voilà une chose de réglée pour notre keygen.
Nous devons maintenant modifier notre script pour que les boucles ne commencent pas à partir du premier caractère parmi les valeurs possibles, mais aléatoirement par l'une de ces valeurs.

Je crois que je vais vous laisser découvrir le script, on reparlera de cela après :

<script language="JavaScript">

// Crée un tableau
chars = new Array();

// Remplit ce tableau avec les caractères alphanumériques (36 valeurs)
for(i = 0x30; i <= 0x39; i++)
  chars.push(i);

for(i = 0x61; i <= 0x7a; i++)
  chars.push(i);

// Fonction retournant l'index d'un caractère au hasard
function randomChar() {
  return Math.round(Math.random() * (chars.length - 1));
}

rc = new Array(4);

// Génération aléatoire d'une possibilité 
// -----------------------------------------------------------------------------
exit = false;

// Tire 4 valeurs au hasard
for(i = 0; i < 4; i++)
  rc[i] = randomChar();

// Teste toutes les valeurs possibles pour chaque caractère à l'aide de plusieurs boucles imbriquées
for(i = 0; i < chars.length; i++) {
  char1 = chars[(rc[0] + i) % chars.length];

  for(j = 0; j < chars.length; j++) {
    char2 = chars[(rc[1] + j) % chars.length];

    for(k = 0; k < chars.length; k++) {
      char3 = chars[(rc[2] + k) % chars.length];

      for(l = 0; l < chars.length; l++) {
        char4 = chars[(rc[3] + l) % chars.length];

        // Si la condition se révèle vraie, affiche la combinaison et sort de la boucle
        if(((char3 ^ char2) * char4 + char1) % 0x6b == 0) {
          dword1 = String.fromCharCode(char1) + String.fromCharCode(char2) + String.fromCharCode(char3) + String.fromCharCode(char4);

          exit = true;
        }

        if(exit)
          break;

      }

      if(exit)
        break;

    }

    if(exit)
      break;

  }

  if(exit)
    break;

}
// -----------------------------------------------------------------------------

// Affiche la combinaison
document.write(dword1);

</script>


Ne vous laissez pas impressionner par les modifications, il n'y a en fait que deux changements principaux :

Essayez avec votre navigateur, et vous verrez que le résultat est plutôt concluant !

On peut appliquer cette technique avec les deux autres conditions, et au final... on a notre keygen !

Le listing complet

Voici ce que l'on peut obtenir en allant jusqu'au bout :

<html>
  <head>
    <title>FlashGet 1.40 keygen</title>
    <script language="JavaScript">
      function generateKey() {
        chars = new Array();

        for(i = 0x30; i <= 0x39; i++)
          chars.push(i);

        for(i = 0x61; i <= 0x7a; i++)
          chars.push(i);

        function randomChar() {
          return Math.round(Math.random() * (chars.length - 1));
        }

        rc = new Array(4);

        // DWORD 1
        // -----------------------------------------------------------------------------
        exit = false;

        for(i = 0; i < 4; i++)
          rc[i] = randomChar();

        for(i = 0; i < chars.length; i++) {
          char1 = chars[(rc[0] + i) % chars.length];

          for(j = 0; j < chars.length; j++) {
            char2 = chars[(rc[1] + j) % chars.length];

            for(k = 0; k < chars.length; k++) {
              char3 = chars[(rc[2] + k) % chars.length];

              for(l = 0; l < chars.length; l++) {
                char4 = chars[(rc[3] + l) % chars.length];

                if(((char3 ^ char2) * char4 + char1) % 0x6b == 0) {
                  dword1 = String.fromCharCode(char1) + String.fromCharCode(char2) + String.fromCharCode(char3) + String.fromCharCode(char4);

                  exit = true;
                }

                if(exit)
                  break;

              }

              if(exit)
                break;

            }

            if(exit)
              break;

          }

          if(exit)
            break;

        }
        // -----------------------------------------------------------------------------


        // DWORD 2
        // -----------------------------------------------------------------------------
        exit = false;

        for(i = 0; i < 4; i++)
          rc[i] = randomChar();

        for(i = 0; i < chars.length; i++) {
          char5 = chars[(rc[0] + i) % chars.length];

          for(j = 0; j < chars.length; j++) {
            char6 = chars[(rc[1] + j) % chars.length];

            for(k = 0; k < chars.length; k++) {
              char7 = chars[(rc[2] + k) % chars.length];

              for(l = 0; l < chars.length; l++) {
                char8 = chars[(rc[3] + l) % chars.length];

                if(((char7 & char6) * char8 + char5) % 0x65 == 8) {
                  dword2 = String.fromCharCode(char5) + String.fromCharCode(char6) + String.fromCharCode(char7) + String.fromCharCode(char8);

                  exit = true;
                }

                if(exit)
                  break;

              }

              if(exit)
                break;

            }

            if(exit)
              break;

          }

          if(exit)
            break;

        }
        // -----------------------------------------------------------------------------

        // DWORD 4
        // -----------------------------------------------------------------------------
        exit = false;

        for(i = 0; i < 4; i++)
          rc[i] = randomChar();

        for(i = 0; i < chars.length; i++) {
          char13 = chars[(rc[0] + i) % chars.length];

          for(j = 0; j < chars.length; j++) {
            char14 = chars[(rc[1] + j) % chars.length];

            for(k = 0; k < chars.length; k++) {
              char15 = chars[(rc[2] + k) % chars.length];

              for(l = 0; l < chars.length; l++) {
                char16 = chars[(rc[3] + l) % chars.length];

                if(((char15 | char14) * char16 + char13) % 0x69 == 0) {
                  dword4 = String.fromCharCode(char13) + String.fromCharCode(char14) + String.fromCharCode(char15) + String.fromCharCode(char16);

                  exit = true;
                }

                if(exit)
                  break;

              }

              if(exit)
                break;

            }

            if(exit)
              break;

          }

          if(exit)
            break;

        }
        // -----------------------------------------------------------------------------

        serial = Math.round(Math.random()) == 0 ? "fgc-" : "fgf-";
        serial += dword1;
        serial += dword2;

        for(i = 0; i < 4; i++)
          serial += String.fromCharCode(chars[randomChar()]);

        serial += dword4;

        for(i = 0; i < 24; i++)
          serial += String.fromCharCode(chars[randomChar()]);

        return serial;
      }
    </script>
  </head>
  <body>
    <h1>FlashGet 1.40 keygen</h1>
    <form action="">
      <div>
        <input type="text" value="" size="64" maxlength="44" readonly="readonly"/>
        <input type="button" value="Generate" onclick="javascript:document.forms[0].elements[0].value = generateKey()"/>
      </div>
    </form>
    <address>By Canterwood &lt;<a href="mailto:charloweb@hotmail.com">charloweb@hotmail.com</a>&gt;</address>
  </body>
</html>


Vu la longueur du code, je vous épargnerai les explications... De toute façon, il n'y a presque rien de nouveau par rapport à ce que nous avons déjà vu.

Conclusion

Ouf, cette série de tutoriaux sur FlashGet est terminée ! Vous avez pu constater que l'on est partis de choses très basiques (du cracking standard) pour aboutir à la création d'un keygen. On a gardé le meilleur (et aussi le plus dur) pour la fin mais je pense que ça en valait la peine, n'est-ce pas ? Pour information, FlashGet n'est pas un logiciel très facile à keygenner, je pense que vous l'avez remarqué !
Autrement, j'espère que vous avez globalement compris; si cependant certaines choses vous échappent, n'hésitez pas à m'écrire et je répondrai à vos questions.

Vous pouvez maintenant vous entraîner à coder le keygen dans un autre langage (envoyez-moi vos créations, ça me fera un petit souvenir), et surtout essayez de vous attaquer à d'autres programmes ! C'est en forgeant que l'on devient forgeron...

Remerciements : Nitrogen (TSRh), The Analyst, Lise_Grim ainsi que la ShmeitCorp pour leurs tutoriaux.
Je salue par ailleurs les membres de la ICIteam, et tous les gens fréquentant le CrFF !

Canterwood <charloweb@hotmail.com>