Décompilation d'application flash
Le 28-07-2010
Les décompilateurs sont une préocuppation majeure des créateurs d'applications flash. En quelques minutes, il est possible de les explorer et d'en extraire le contenu. Votre propriété intellectuelle peut être volée en un clic ! C'est un grave problème pour les contenus de type image/audio/video, mais aussi pour la sécurité de l'ensemble de l'application.
Dans la suite de ce post, nous allons voir différents moyens de protection et d'attaque d'une application flash.
Explication de l'application flash
L'application créée pour l'occasion est rudimentaire : elle affiche un compte à rebours de 60 secondes, une fonctionnalité totalement révolutionnaire ! Elle a été conçue pour ne se lancer que pendant l'année 2009. Voilà la protection qu'il nous faudra contourner pour pouvoir utiliser cette merveilleuse application à loisir.
public function init() : void
{
if (this.date.fullYear != 2009)
{
this.statusTextField.text = "Please buy me !";
return;
}
this.myTimer.start();
this.statusTextField.text = "You have " + this.delay * this.repeat / 1000 + " seconds to wait.";
this.myTimer.addEventListener(TimerEvent.TIMER, this.timerHandler);
this.myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, this.completeHandler);
return;
}// end function
Dès lors deux options s'offrent à nous : changer la date de notre machine ou supprimer la vérification de l'application. Dans un pur intérêt pédagogique, nous allons envisager la deuxième solution.
Le format de fichier
Selon le fichier de spécifications du format de fichier SWF version 10 (http://www.adobe.com/devnet/swf/pdf/swf_file_format_spec_v10.pdf), un fichier swf est composé d'un entête contenant des informations générales et plusieurs blocs de données identifiés par des tags.
L'entête est défini comme ci dessous :
| Nom du champ | Type | Commentaire |
| Signature | Entier non signé sur 8 bits | C indique que le fichier est compressé F indique que le fichier est décompressé (SWF 6 et ultérieur) |
| Signature | Entier non signé sur 8 bits | Toujours le caractère 'W' |
| Signature | Entier non signé sur 8 bits | Toujours le caractère 'S' |
| Version | Entier non signé sur 8 bits | Version flash supportée |
| FileLenght | Entier non signé sur 32 bits | Taille du fichier |
| FrameSize | RECT (voir fichier de spécification) | Dimensions des frames |
| FrameRate | Entier non signé sur 16 bits | Vitesse des frames |
| FrameCount | Entier non signé sur 16 bits | Nombre de frame |
Le champ signature est soit CWS (0x43 0x57 0x53) soit FWS (0x46 0x57 0x53). CWS indique que les données hormis l'entête sont compressées grâce au standard ZLIB. Cette compression permet un téléchargement des applications flash plus rapide.
Ensuite viennent les blocs de données qui contiennent les images, les sons mais aussi les instructions qui seront exécutées. Ces instructions appelées bytecode sont générées à la compilation à partir du code source. Le bytecode sera ensuite interprété par une machine virtuelle nommée ActionScript Virtual Machine 2 dont voici les spécifications (http://www.adobe.com/devnet/actionscript/articles/avm2overview.pdf).
Décompilation
Grâce à un des nombreux outils de décompilation tel que Flash Decompiler Trillix (http://www.flash-decompiler.com), Sothink Swf Decompiler (http://www.sothink.com/product/flashdecompiler/index.htm), etc... il est possible d'accéder aux codes sources de l'application originelle. Rien de magique ! Comme vu précédemment les codes sources ne sont pas embarqués dans l'application flash, le décompileur va les reconstituer grâce au bytecode !
| Données binaires : | ... 0x24 0x02 0x24 0x03 0xa0 0x73 0xd5 ... |
| ByteCode | 0x24 0x02 0x24 0x03 0x0a 0x73 0xd5 |
| ByteCode (human readable) | pushbyte 2 pushbyte 3 add convert_i setlocal1 |
| Code source | __loc1__ = (int) 2 + 3; |
Le décompilateur reconstitue l'ensemble du code source de la même manière. Nemo440 (http://www.docsultant.com/nemo440/) est un très bon outil pour visualiser le bytecode d'une application flash.
Obfuscation
L'obfuscation est un processus permettant de complexifier la décompilation d'une application. Elle repose sur plusieurs techniques dont les plus célèbres sont :
- la génération de code poubelle; un code superflu est ajouté pour rendre la lisibilité difficile
- le cryptage des chaînes de caractère; les chaînes de caractères nécessitent un processus de décryptage pour retrouver leur forme originelle
- le changement de nom des variables et nom de fonction; Exemple : null.this(ddd-a(); au lieu de voiture.accelere();
De nombreux logiciels d'obfuscation sont disponibles offrant des niveaux de protection très variables. Nous avons utilisé SecureSwf de KindiSoft (http://www.kindisoft.com/) pour protéger notre application. Le code source obtenu après une nouvelle décompilation est plutôt surprenant. On peine à croire qu'une chose pareille puisse s'exécuter.
public function init() : void
{
var _loc_1:Boolean = true;
;
var _loc_2:* = ((null & false) + 1 in null) % NaN;
do
{
return;
if (false)
{
this.default.addEventListener(TimerEvent.TIMER_COMPLETE, this.completeHandler);
}while (true)
this.default.addEventListener(TimerEvent.TIMER, this.timerHandler);
if (!(_loc_2 && this))
{
;
do
{
this._20else.text = "You have " + this.break * this.repeat / 1000 + " seconds to wait.";
}
if (_loc_1)
{
do
{
this.default.start();
}while (true)
return;
}while (true)
break;
if ((!(-(_loc_3 in this))).case20.fullYear == 2009) goto 135;
this._20else.text = "Please buy me !";
}
;
}
return;
}// end function
Effectivement le code source obtenu est très endommagé. On voit nettement le résultat des processus de renommage de variables "this._else20.text" et d'ajout de code poubelle "do { return;". Un tel code est impossible à recompiler notamment à cause de l'emploi de mots clefs réservés dans le nommage des variables (Ex: this.break).
Attaque
Le code source obtenu n'est pas sans utilité. Il nous permet avant tout de localiser l'endroit du test de protection : la fonction init(). Une fois cette information connue, nous pouvons lancer nemo440 pour afficher le bytecode de la fonction ciblée.
On identifie rapidement qu'une protection sur la valeur de l'année en cours a lieu lors de l'initialisation de cette application grâce aux bytecodes :
164 getproperty private::case 166 getproperty fullYear 168 pushshort 2009 171 ifeq L14 175 getlocal0 176 getproperty else 178 pushstring "Please buy me !" 181 setproperty text
Le test d'égalité est effectué grâce à l'opérateur ifeq (0x13) entre l'entier court "2009" et fullYear qui est un attribut de la classe Date. On pourrait utiliser l'application si l'opérateur ifeq était remplacé par l'opérateur ifne (0x14), si l'entier court était "2010", etc...
Rien de plus simple ! Il nous suffit de rechercher la suite hexadécimale "ifeq getlocal0 getproperty" (0x13 0xd0 0x66) avec un bon éditeur hexadécimal après avoir décompresser l'application (SWF Compressor Decompressor sur http://www.dcomsoft.com/). Une fois cette séquence trouvée, nous changeons la valeur 0x13 par 0x14 et nous recompressons le tout.
L'application est maintenant utilisable pour l'éternité !
Ce post est une démonstration des difficultés à protéger une application flash. L'obfuscation du code source ne suffit pas à protéger votre application et encore moins votre système entier.
On vous rappelle ?
Indiquez votre numéro de téléphone
ainsi que la tranche horaire où vous êtes disponible. Nous vous appellerons dans les plus brefs délais
Actualités
- 30-07-2010 Sécurité de Typo3 & entropie de rand()
- 28-07-2010 Décompilation d'application flash
- 06-04-2010 Les 9 objections à la sécurité des sites internet - Développement externalisé
