1 Utilisation d un compilateur pour évaluer la résistance des obfuscations de programmes C Stéphanie Riaud INRIA & DGA-MI Directrice de thèse : Sandrine Blazy
2 L obfuscation *Collberg] : une solution de lutte contre la rétro-conception Transformer le code source, binaire, ou une représentation intermédiaire d un programme. Rendre le code binaire désassemblé le moins intelligible possible Protéger un secret contenu dans le code du programme : un savoir, une donnée sensible etc. Temps nécessaire à la rétro-conception équivalent au temps de conception.
3 Obfuscation de programmes C Pourquoi obfusquer au niveau du langage C? Perte d information liée au passage du langage C au langage assembleur. Paramètres de fonctions Types des variables Structures de données accès calculés antérieurement par le compilateur etc. Le processus d optimisation peut avoir un impact sur l efficacité des obfuscations. Il faut être certain que le fichier binaire est bien transformé! Concevoir des transformations qui ne seront pas annulées lors de la compilation : Valider les obfuscations Mesurer le degré de résistance des transformations face au processus de compilation : Evaluer et comparer l efficacité des transformations
4 Architecture du processus de test Trois étapes : obfuscation, compilation et optimisation puis désassemblage
5 Sommaire Obfuscation Structures de données Compilation et optimisation Le compilateur GCC Optimisations dans GCC Fichiers d informations générés lors de la compilation Les optimisations à risques Réduction Scalaire des Agrégats Analyse des fichiers générés Elimination ou modification d expressions Analyse des fichiers générés Désassemblage IDA Pro Réduction Scalaire des Agrégats BinDiff Elimination ou modification d expressions
6 Obfuscation Structures de données Analyse Dynamique : masquer l emplacement des données l emplacement des données est modifié en temps réel Déplacées dynamiquement Analyse Statique : masquer les accès les accès sont remplacés par des appels à une fonction struct test{int a;int b;}; int main (void){ struct test t; t.a = 10; t.b = 20; int c = t.a + t.b; return c; } struct test {int a;int b;}; int compteur_acces; int tab_acces[4] = { 0, 1, 0, 1, }; int *tab_adresses[2]; int *accede(void) { } int main(void) { struct test t; int c; c = 0; *(tab_adresses + 1) = &t.b; *(tab_adresses + 0) = &t.a; *(accede())= 10; *(accede())= 20; c = *accede() + *accede(); return c; } Tableau d'adresses (tab_adresses) Tableau d'accès (tab_acces) Compteur d'accès (compteur_acces) Fonction d'accès (accede) :
Architecture du processus de test 7
8 Compilation et optimisation [GCC] Utilisation du compilateur Gcc Sources et documentation disponibles Fortement optimisant Optimisations dans GCC [GlekHubicka] Intra-procédurales Inlining Optimisations scalaires : éliminations de code morts propagation de copies etc. Réduction scalaire arguments de fonctions champs de structures etc. Optimisation de la gestion des exceptions etc. Construction du graphe d appel et de la liste des variables externes et statiques du programme [Briggs al.] Inter-procédurales Propagation de constantes Inlining Propagation de profil etc.
9 Compilation et optimisation Génération des fichiers d informations détaillés Pour les passes intra-procédurales : -fdump-tree-all-details Arbres originel & optimisé Vue globale sur les modification apportées Difficilement lisibles Forme Gimple et SSA Fichier de statistiques Détail sur les passes qui ont modifié le programme Permet d accéder aux fichiers intéressants Fichiers générés par les passes Informations précises (Arbre Gimple ou SSA et commentaires propres à l optimisation) Pour les passes inter-procédurales : -fdump-ipa-all-details Graphe d appel détaillé Informations sur les variables statiques et externes Fichiers générés par les passes Informations précises (Arbre Gimple et commentaires propres à l optimisation)
10 Compilation et optimisation Etude effectuée Analyse des optimisations au sein de la chaîne d optimisation Uniquement sur la partie intra-procédurale (étude en cours) Sélection d optimisations à risques : Obfuscation de structures Remplacement scalaire des agrégats Elimination de l élément modifié Remplacement d opérations scalaires simples par une suite d opérations complexes Optimisations scalaires Elimination de code mort Propagation de copies et de constantes Elimination des sous expressions communes Simplification des opérations liées à l obfuscation Tests effectués sur la suite de tests du compilateur
11 Les optimisations à risque Réduction Scalaire des Agrégats [Jambor] Remplace les champs des structures par des variables scalaire structures définies localement paramètres de fonctions Séquence de trois passes intra-procédurales Niveaux d optimisation O et O2 Implémentation dans GCC Tous les champs ne sont pas candidats à l optimisation nature des champs pas d adresse mémoire (ex : référence) remplaçable par une variable scalaire etc. Les champs candidats peuvent être disqualifiés nature des accès un accès au moins etc. struct simplestruct { int t1; int t2; }deuxentiers; int main (){ } int res; deuxentiers.t1 = 2; deuxentiers.t2 = 4; res = deuxentiers.t1+deuxentiers.t2; return res; Rejeté Champ Disqualifié Candidat int main (){ } Optimisé int res, _4, _5; _4 = 2; _5 = 4; res = _4 + _5; return res;
12 Réduction Scalaire des Agrégats Analyse des fichiers générés : - un champ obfusqué n est jamais optimisé les champs optimisés n ont pas été modifiés - un champ disqualifié est rejeté après obfuscation les champs disqualifié n ont pas été modifiés Un champ obfusqué est rejeté lors du processus d optimisation - Raison invoquée : needs to live in memory - Initialisation de tableaux, références ou variables globales Initialisation du tableau d adresses au début de l obfuscation Nom du Nombre de champs optimisés dans le programme non obfusqué Nombre de Nombre de champs optimisés dans le programme obfusqué programme de champs esra sra eipa_sra test obfusqués esra sra eipa_sra D O D O D O D O D O D O eipa-sra-1 0 1 0 1 0 1 2/3 0 0 0 0 0 0 eipa-sra-2 0 0 0 0 0 2 2/3 0 0 0 0 0 0 eipa-sra-3 2 0 0 0 0 2 4/6 0 0 0 0 0 0 sra-3 1 0 0 0 0 0 2/2 0 0 0 0 0 0 sra-6 6 6 0 0 0 0 12/24 0 0 0 0 0 0 sra-8 4 4 1 0 0 0 2/8 2 2 0 0 0 0 sra-9 2 1 2 0 0 0 3/4 1 0 0 0 0 0 sra-11 1 2 1 0 0 0 0 1 2 1 0 0 0 sra-12 5 0 0 0 0 0 10/10 0 0 0 0 0 0
13 Les optimisations à risque Elimination ou modification d expressions *Muchnick] Élimination de code mort Suppression des instructions qui n impactent pas la sortie du programme dépendances de branches et corps de boucles Propagation de constantes Remplacement des variables ayant une valeur constante par une constante prédicats des structures conditionnelles Propagation de copies Remplacement des copies de variables par la variable d origine Élimination des sous-expressions communes Remplacement des expressions identiques par une variable Appelées plusieurs fois
14 Analyse des fichiers générés Deux cas mis en avant : fonction d accès non-inlinée les accès aux champs doivent toujours s effectuer grâce à un appel la fonction d accès ne doit pas être trop simplifiées échange des données dans le tableau d adresses retour d une adresse lue à partir des deux tableaux fonction d accès inlinée échange des données à chaque accès (ou presque) lecture de l adresse à partir des deux tableaux Beaucoup plus d expressions optimisées lorsque la fonction d accès est inlinée cumul de plusieurs fonctions inlinées recopiées plusieurs fois augmentation du nombre d expressions optimisés en fonction du nombre de fonctions inlinées Moins d expressions optimisées lorsque la fonctions d accès n est pas inlinée expressions contenant des tableaux globaux ou des appels très peu optimisable Les expressions sur lesquelles repose l obfuscation ne sont pas supprimées échange de valeurs accès depuis les tableaux
Architecture du processus de test 15
16 Désassemblage Objectif : vérifier les résultats précédents Analyse des fichiers binaires générés (obfusqués et optimisés) Plus réaliste que le code assembleur généré par le compilateur IDA Pro (Hex Rays [HexRay]) Désassembleur interactif Listing assembleur. Généré automatiquement Amélioré par l utilisateur Modification Annotation Propagation des informations Construction des CFG et CG Facilité de navigation Interfaces spécifiques Chaines de caractères Fonctions (internes / externes) Structures Etc. Logo IDA Pro
IDA Pro 17
18 Désassemblage : Réduction Scalaire des Agrégats Vérifier que les structures sont toujours présentes Segment.data déclarées et définies globalement Pile d exécution définies localement Champs stockés séquentiellement Pointeur de structure identifiant conservé (option g) Accédés grâce à des offset constants Résultats conformes à ceux obtenus lors de l analyse des fichiers générés lors de la compilation champs rejetés
19 Désassemblage BinDiff (Zynamics [Zynamics]) Greffon au logiciel IDA pro Comparaison de deux binaires désassemblés Représentation du programme sous forme d un graphe d appel chaque nœud est le graphe de flot de contrôle d une fonction Correspondance entre les adresses des deux fichiers binaires désassemblés code couleur simple Calcul de pourcentage de similarité / différence entre les fonctions permet de repérer les fonctions très impactées
BinDiff 20
21 Désassemblage : Elimination ou modification d expressions Utilisation du greffon BinDiff pour comparer les fichiers binaires expressions modifiées ou supprimées Résultats observés similaires à ceux obtenus en analysant les fichiers d informations appels de fonctions non supprimés opérations sur les tableaux conservées Pas d impact sur la qualité de l obfuscation Les options de compilations d impactent pas l efficacité de l obfuscation
22 Conclusion Résistance de l obfuscation aux optimisations tableaux globaux appels de fonctions Vérifier ce résultat avec : inlining plus poussé les optimisations inter-procédurales des exemples plus réalistes Génération automatique de résultats : chaque transformation doit être vérifiée ainsi comparaison des transformations en fonction de leur degré de résistance aux optimisations
23 Bibliographie [HexRay] https://www.hex-rays.com [Zynamics] http://www.zynamics.com/bindiff.html [Gcc] http://www.gcc.gnu.org [GlekHubicka] Optimizing real-world applications with GCC Link Time Optimization, Taras Glek (Mozilla Corporation) et Jan Hubicka (SuSE CR s.r.o). [Jambor] Interprocedural optimizations of function parameters, Martin Jambor (SUSE Labs). [Briggs al.] WHOPR Fast and Scalable Whole Program Optimizations in GCC, Preston Briggs, Doug Evans, Brian Grant, Robert Hundt, William Maddox, Diego Noviollo, Seongbae Park, David Sehr, Ian Taylor, Olli Wild (Google). [Muchnick] Advanced Compiler Design Implementation, Steven S.Munchnick. [Collberg] Surreptitious Softawe, obfuscation, watermarking and tamperproofing, Christian Collberg and Jasvir Nagra