mardi 6 janvier 2009

Fyury's challenge - Keygenme

Il m'a sauvé la vie, le dude. Et moi qui pensait rouiller avec du php... C'est en cette soirée du 06 janvier 2009 que je me résigne à visiter son blog, et là, je tombe sur son challenge de crackme :
Après un petit rappelle de xylitol (merci), je viens vous mettre mon foome I ..

Je l'avais présenté sur FC et donc je n'ai pas vu d'importance à l'exposer sur le blog (vu les critiques :p) .

level : 0.5 || 1
secure : no package ..
Anti debugger (mal implémenté)

Objectifs :

- faire un keygen. ( 1 )
- trouver le serial pour son pseudo. (0.5 )


Article en question : http://fyury.blogspot.com/2008/11/foome-part-i.html.

Je télécharge l'archive sans trop lire les infos, je me focalise juste sur ça :

- faire un keygen. ( 1 )
- trouver le serial pour son pseudo. (0.5 )


Je me suis dit, au début, que je n'arriverai pas à faire le keygen. J'y suis finalement arrivé, après plusieurs essais car je suis quelqu'un de trop pressé.

Allez, je décompresse l'archive dans un dossier, et je lance foome.exe.
C:\Documents and Settings\Geoffrey\Bureau\foome>"foome {part I}.exe"
[ foome part I by fyuw]

Login : Geo0w
pwd : 15612


Une fenêtre apparaît, et me dit "t4pz" avec pour titre "Iz N0t da g00d password". Put*** de foome de m****, j'vais te montrer qui c'est la tapz ! <>

Je me précipite pour ouvrir le bordel avec ollydbg. Je ne tarde pas à trouver la section de code la plus intéressante :
00401431  |> C70424 2C30400>MOV DWORD PTR SS:[ESP],foome_{p.0040302C ; ||||ASCII "                 [ foome part I by fyuw]

Login : "
00401438 |. E8 C7060000 CALL <JMP.&msvcrt.printf> ; |||\printf
0040143D |. 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; |||
00401443 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; |||
00401447 |. C70424 5F30400>MOV DWORD PTR SS:[ESP],foome_{p.0040305F ; |||ASCII "%s"
0040144E |. E8 A9060000 CALL <JMP.&msvcrt.scanf> ; ||\scanf
00401453 |. 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; ||
00401459 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
0040145C |. E8 93060000 CALL 00401461 |. 83F8 04 CMP EAX,4 ; |
00401464 |. 77 1B JA SHORT foome_{p.00401481 ; |
00401466 |. C70424 6230400>MOV DWORD PTR SS:[ESP],foome_{p.00403062 ; |ASCII "Need more 5 char..."
0040146D |. E8 92060000 CALL <JMP.&msvcrt.printf> ; \printf
00401472 |. C785 84FEFFFF >MOV DWORD PTR SS:[EBP-17C],0
0040147C |. E9 F5000000 JMP foome_{p.00401576
00401481 |> 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; ||
00401487 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
0040148A |. E8 65060000 CALL 0040148F |. 83F8 0B CMP EAX,0B ; |
00401492 |. 76 1B JBE SHORT foome_{p.004014AF ; |
00401494 |. C70424 7630400>MOV DWORD PTR SS:[ESP],foome_{p.00403076 ; |ASCII "Need less 10 char..."
0040149B |. E8 64060000 CALL <JMP.&msvcrt.printf> ; \printf
004014A0 |. C785 84FEFFFF >MOV DWORD PTR SS:[EBP-17C],0
004014AA |. E9 C7000000 JMP foome_{p.00401576
004014AF |> C70424 8B30400>MOV DWORD PTR SS:[ESP],foome_{p.0040308B ; |||||ASCII "pwd : "
004014B6 |. E8 49060000 CALL <JMP.&msvcrt.printf> ; ||||\printf
004014BB |. 8D85 B4FEFFFF LEA EAX,DWORD PTR SS:[EBP-14C] ; ||||
004014C1 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; ||||
004014C5 |. C70424 9230400>MOV DWORD PTR SS:[ESP],foome_{p.00403092 ; ||||ASCII "%d"
004014CC |. E8 2B060000 CALL <JMP.&msvcrt.scanf> ; |||\scanf
004014D1 |. 0FBE9D 8AFEFFF>MOVSX EBX,BYTE PTR SS:[EBP-176] ; |||
004014D8 |. 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; |||
004014DE |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |||
004014E1 |. E8 0E060000 CALL 004014E6 |. 89C2 MOV EDX,EAX ; ||
004014E8 |. 89D0 MOV EAX,EDX ; ||
004014EA |. 01C0 ADD EAX,EAX ; ||
004014EC |. 01D0 ADD EAX,EDX ; ||
004014EE |. C1E0 09 SHL EAX,9 ; ||
004014F1 |. 01D0 ADD EAX,EDX ; ||
004014F3 |. 01C3 ADD EBX,EAX ; ||
004014F5 |. 8B85 A0FEFFFF MOV EAX,DWORD PTR SS:[EBP-160] ; ||
004014FB |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
004014FE |. E8 F1050000 CALL <JMP.&msvcrt.strlen> ; |\strlen
00401503 |. 29C3 SUB EBX,EAX ; |
00401505 |. 89D8 MOV EAX,EBX ; |
00401507 |. 83C0 0C ADD EAX,0C ; |
0040150A |. 3985 B4FEFFFF CMP DWORD PTR SS:[EBP-14C],EAX ; |
00401510 |. 74 33 JE SHORT foome_{p.00401545 ; |
00401512 |. C74424 0C 0000>MOV DWORD PTR SS:[ESP+C],0 ; |
0040151A |. C74424 08 9530>MOV DWORD PTR SS:[ESP+8],foome_{p.004030>; |ASCII "Iz N0t da g00d password"
00401522 |. C74424 04 2730>MOV DWORD PTR SS:[ESP+4],foome_{p.004030>; |ASCII "t4pZ"
0040152A |. C70424 0000000>MOV DWORD PTR SS:[ESP],0 ; |
00401531 |. E8 06060000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401536 |. 83EC 10 SUB ESP,10
00401539 |. C785 84FEFFFF >MOV DWORD PTR SS:[EBP-17C],0
00401543 |. EB 31 JMP SHORT foome_{p.00401576
00401545 |> C74424 0C 0000>MOV DWORD PTR SS:[ESP+C],0 ; |
0040154D |. C74424 08 AD30>MOV DWORD PTR SS:[ESP+8],foome_{p.004030>; |ASCII "U win.. make a keygen"
00401555 |. C74424 04 2730>MOV DWORD PTR SS:[ESP+4],foome_{p.004030>; |ASCII "t4pZ"
0040155D |. C70424 0000000>MOV DWORD PTR SS:[ESP],0 ; |
00401564 |. E8 D3050000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA


Je fais un break sur l'adresse 004014CC, qui va appeler la fonction scanf lors de l'input du password. Je lance, et là, une autre fenêtre avec titre "U sUck" et qui m'affiche de nouveau un "t4pZ". Mais quelle connasse ! (même plus envie de censurer, c'est plus fort que moi)

Je me dis donc - toujours sans avoir lu qu'il y avait un antidebuger mal implémenté - qu'il y a une protection à contourner. Miracle, je repère ce bout de code :

00401324  |. C785 98FEFFFF >MOV DWORD PTR SS:[EBP-168],foome_{p.0040>; |ASCII "OLLYDBG.EXE"
0040132E |. C785 9CFEFFFF >MOV DWORD PTR SS:[EBP-164],foome_{p.0040>; |ASCII "idag.exe"
00401338 |. C785 A0FEFFFF >MOV DWORD PTR SS:[EBP-160],foome_{p.0040>; |ASCII "windbg.exe"


Sans hésitation, je modifie les valeurs dans le dump :
- "OLLYDBG.EXE" devient "tasoeur.EXE" ;
- "idag.exe" devient "stfu.exe" ;
- "windbg.exe" devient "azerty.exe".

Je relance, et là... Pas de fenêtre ! C'est qui la tapz ?! Haha !

Je rentre donc en login : Geo0w, et en pwd : 2151 (truc au pif, quoi).

Je continue...

Sans rentrer dans les détails, j'arrive à la ligne suivante après quelques coups de F8 (pour tracer le code sans s'attarder dans les CALLs) :
0040150A  |. 3985 B4FEFFFF  CMP DWORD PTR SS:[EBP-14C],EAX  


Je regarde eax, et il contient 00001E76. En décimal, ça donne : 7798.
Je ferme ollydbg et tout le bordel, puis je relance foome.exe en ligne de commande :


C:\Documents and Settings\Geoffrey\Bureau\foome>"foome {part I}.exe"
[ foome part I by fyuw]

Login : Geo0w
pwd : 7798


Encore une fenêtre, sauf que, dorénavant, son titre est différent : "U win.. make a keygen", puis, elle affiche encore un "t4pZ". Cette saloperie mériterait que je l'insulte comme un DR_KILLER. Au passage, make me a sandwich, saloperie !

Bon, désolé pour la vulgarité, mais bon... C'est éprouvant, ça sera mon premier keygen de ma vie ! Oui, je suis énervé et j'oublie le fait d'avoir pensé tout à l'heure que je n'y arriverai pas. Je fonce, tête baissée !

Je réouvre mon copain ollydbg, je remodifie les valeurs dans le dump :
- "OLLYDBG.EXE" devient "tasoeur.EXE" ;
- "idag.exe" devient "stfu.exe" ;
- "windbg.exe" devient "azerty.exe".

Puis, cette fois, je break sur :
004014CC  |. E8 2B060000    CALL <JMP.&msvcrt.scanf>                 ; |||\scanf


Cette ligne correspond au CALL juste après l'input du password. Hop, je lance, je rentre "albert" en login et "11111" en pwd, puis ça break. Je trace le code :
004014E6  |. 89C2           MOV EDX,EAX                              ; ||
004014E8 |. 89D0 MOV EAX,EDX ; ||
004014EA |. 01C0 ADD EAX,EAX ; ||
004014EC |. 01D0 ADD EAX,EDX ; ||
004014EE |. C1E0 09 SHL EAX,9 ; ||
004014F1 |. 01D0 ADD EAX,EDX ; ||
004014F3 |. 01C3 ADD EBX,EAX ; ||
004014F5 |. 8B85 A0FEFFFF MOV EAX,DWORD PTR SS:[EBP-160] ; ||
004014FB |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
004014FE |. E8 F1050000 CALL <JMP.&msvcrt.strlen> ; |\strlen
00401503 |. 29C3 SUB EBX,EAX ; |
00401505 |. 89D8 MOV EAX,EBX ; |
00401507 |. 83C0 0C ADD EAX,0C ; |
0040150A |. 3985 B4FEFFFF CMP DWORD PTR SS:[EBP-14C],EAX ; |


C'est à la dernière ligne que notre password entré est comparé à la clef véritable. Donc, j'analyse le code assembleur au-dessus, et j'en viens à traduire cela en l'algorithme suivant (après plusieurs sessions de debugging) :

keygen <- longueur(login)
keygen <- keygen * 3
keygen <- keygen * 512
keygen <- keygen + longueur(login) (merci à UnKnOwN*DrAgOoN pour avoir signalé l'oubli)
keygen <- keygen + (valeur entière)login[3]
keygen <- keygen - longueur_chaine("windbg.exe")
keygen <- keygen + 12


Au final, je fais mon keygen :
http://venom630.free.fr/geo/autre_chose/foome__fyuw/keygen_c.txt

Il marche niquel.


Conclusion ?


Eprouvant, très éprouvant. Fyury, si tu passes sur ce blog, je tenais à te remercier d'avoir mis à disposition un tel challenge. J'espère résoudre d'autres de tes oeuvres avec une difficulté croissante ; c'est en forgeant qu'on devient forgeron.

Geo

Edit : ajout de http://xylitol.free.fr/Home/index.php dans la liste des copains. Superbe site sur le reverse engineering à visiter !

"Bambalam!" ou "compile-moi du PHP !"

Mon DS d'éco-droit ayant été littéralement... Foiré, et n'ayant pas envie de réviser mes maths pour demain, je décide de consacrer un article toujours aussi simpliste qui traitera de Bambalam.

Non, ce n'est pas de la musique. Voici, d'ailleurs, en premier lieu, l'URL du site du projet :
http://www.bambalam.se/bamcompile/


On voit en gros sur la page :
Bambalam PHP EXE Compiler/Embedder


Alors que PHP est censé être un langage interprété, on peut le compiler pour :
- Masquer du code ;
- Faire des applications windows portables ;
- (théoriquement) accroître la vitesse d'exécution.

Elle est pas belle, la vie ?

Et puis, si vous utilisez linux, il y a la source du projet à télécharger !

Allez, on télécharge l'archive, on l'extrait dans un dossier, et on regarde le contenu :
- readme.txt : on passe ;
- project_template.bcp : on passe ;
- bamcompile.exe : le fichier qui va recevoir plein d'arguments pour "compiler" notre php ;
- examples : un dossier contenant plein d'exemples intéressants. Je vous laisse regarder.

Pour nous mettre à l'aise, créons un dossier projets. Dans ce dossier projets, créons un dossier hello et allons dans celui-ci. Maintenant, dans ce dossier, créons un fichier nommé hello.php Et mettons-y le code suivant :
<?php
echo 'Hello!';
?>


Il va maintenant falloir le compiler. Tout d'abord, vous avez le choix entre :
- Aller en ligne de commande pour vous déplacer dans le dossier de bambalam puis rentrer vos options à la main ;
- Faire un fichier batch qui va exécuter de façon séquentielle vos commandes et en garder une trace.

Pour ma part, je penche pour la seconde option.

Voyons ce qu'on nous dit sur le site du projet :
Usage:
bamcompile [-options] infile.php [outfile.exe]
bamcompile [-options] project_directory mainfile.php [outfile.exe]
bamcompile projectfile.bcp

Options:
-w Hide console window for windowed applications
-c Compress output exe (using UPX)
-d Do not encode PHP files
-e:extension.dll Embed and use PHP extension
-i:icon.ico Add icon to exe


Testons la première ligne pour compiler notre unique fichier PHP ! Créons un fichier nommé make.bat dans le dossier courant, et mettons-y les lignes de code suivantes :
@echo off
"../../bamcompile.exe" hello.php
rem On va éviter de fermer la console automatiquement
pause


Eh oui, il faut veiller à mettre ../../ pour remonter dans le dossier parent ; je ne vous prends pas pour des imbéciles non plus, mais pensons-y par réflexe !

On lance make.bat et on n'a même pas le temps de dire "Agaga poireau." :
Bambalam PHP EXE Compiler/Embedder 1.21

Mainfile: hello.php
Outfile: hello.exe

Encoding and embedding hello.php

hello.exe created successfully!
Appuyez sur une touche pour continuer...



On a un superbe exécutable qui s'est créé dans le même dossier. On l'ouvre, et il se ferme à la vitesse de l'éclair ; normal.

On va voir ce que ça donne en ligne de commande :
C:\bamcompile1.21\projets\hello>hello.exe

Hello!


La classe, Matias !
Bon, ok, y'a une ligne vide au-dessus de notre phrase, mais on s'en fout pas mal.

Revenons dans le dossier projets, faisons un second dossier nommé age. On va dedans, et on va créer deux fichier :
- main.php (le fichier principal)
<?php
require_once('age.php');
if($_SERVER['argc'] < 2) {
    echo "Utilisation : ".$_SERVER['argv'][0]." [nombre]\n";
    exit(-1);
}
echo AfficherSuivantAge(abs($_SERVER['argv'][1]));
?>


J'explique le code vite fait. On commence par inclure le fichier age.php (qu'on va écrire après), on vérifie qu'on a entré l'argument en ligne de commandes - qui correspond à l'âge d'une personne - et, en suite, on appelle la fonction AfficherSuivantAge() qui sera définie dans le fichier age.php. Enfin, la fonction intval() permet de s'assurer que l'argument sera une valeur numérique, et abs() pour qu'elle soit positive (vous avez déjà vu des gens âgés de -15 ans ? Tss... Menteurs !)

Passons au fichier age.php :
<?php
if(!defined("AGE_PHP")) {
    define("AGE_PHP",TRUE);
    function AfficherSuivantAge($var) {
        return $var >= 18 ? "Tu es majeur" : "Tu es mineur";
    }
}
?>


En bref, je protège le fichier des inclusions multiples (même si ça sert pas à grand-chose ici) et je définis ma fonction. Car, si on définit la fonction avec le même nom plus d'une fois, ça plante ; normal. La fonction retourne une chaîne de caractère :
- "Tu es majeur" si l'âge est supérieur ou égal à 18 ;
- "Tu es mineur" si l'âge est strictement inférieur à 18.

Pour ceux qui ne comprennent pas le principe de l'instruction ternaire, elle consiste à affecter une valeur à une variable suivant une condition. Exemple :
$variable = condition ? "valeur_si_condition_vraie" : "valeur_si_condition_fausse";


Ca me rappelle la terminale, où on faisait du C en électronique logique. J'ai utilisé des instructions ternaires, et le prof m'a sorti "Mais, ça, c'est pas du C !". Enfin, bref. (xD)

Le code équivalent est le même que pour l'exemple ci-dessus :
if(condition)
    $variable = "valeur_si_condition_vraie";
else
    $variable = "valeur_si_condition_fausse";


Une ligne pour l'instruction ternaire ; quatre pour le test de condition ci-dessus. Ca explique pourquoi j'ai choisi l'expression ternaire.

Mais enfin, ne dérivons pas du sujet.

Maintenant, ce que nous allons faire, c'est revenir dans le dossier où se trouve bamcompile.exe. Créons un fichier nommé make_age.bat et mettons-y le code suivant :
@echo off
bamcompile.exe projets/age main.php projets/age/age.exe
pause


En effet, sur le site de bambalam, on nous dit qu'on peut utiliser :
bamcompile [-options] project_directory mainfile.php [outfile.exe]


Par identification :
project_directory = projets/age ;
mainfile.php = main.php ;
outfile.exe (argument optionnel) = projets/age/age.exe

On lance donc notre fichier batch et c'est l'extase (normalement !).

Bambalam PHP EXE Compiler/Embedder 1.21

Mainfile: main.php
Outfile: projets/age/age.exe
Project dir: projets/age

Embedding age.exe
Encoding and embedding age.php
Encoding and embedding main.php

projets/age/age.exe created successfully!
Appuyez sur une touche pour continuer...


On va exécuter age.exe en CLI :

C:\bamcompile1.21\projets\age>age.exe 18
Tu es majeur
C:\bamcompile1.21\projets\age>age.exe 16
Tu es mineur
C:\bamcompile1.21\projets\age>age.exe aaa
Tu es mineur
C:\bamcompile1.21\projets\age>age.exe -4
Tu es mineur
C:\bamcompile1.21\projets\age>age.exe -18
Tu es majeur
C:\bamcompile1.21\projets\age>age.exe 32
Tu es majeur


Ok, le programme n'a pas beaucoup d'intérêt, mais c'est déjà un bon exemple !


J'ai le regret de vous annoncer que le tour de manège est terminé. Disons que cet article m'a occupé à vous présenter un outil que j'adore vraiment (j'ai pu envoyer un exe sympathique à une copine, y'a longtemps) et qui m'amuse toujours autant !

Regardez la section examples, ça vaut le coup. Il y a même un exemple de calculatrice codée avec winbinder - extension PHP pour faire de l'interface graphique. Bref, tout cela pour dire que ça vaut absolument le coup pour ceux qui font des scripts PHP en CLI et qui voudraient les partager avec des utilisateurs qui n'ont pas forcément PHP d'installé sur leur ordinateur.

C'est tout. A la revoyure !

Geo