Maîtriser le renforcement de la sécurité des applications : une analyse approfondie de l’obfuscation

Obfuscations et vous

Sécurité de l'application C'est désormais un fait établi. Tout le monde sait qu'il en a besoin, et les attaquants savent comment contourner les protections de base ; distribuer une application non protégée n'est tout simplement pas envisageable. Toute protection robuste repose sur deux piliers : la prévention par analyse statique et la détection dynamique des attaques. L'analyse statique est un outil puissant qui offre aux attaquants une connaissance approfondie des spécificités d'implémentation de l'application. Elle expose les points faibles de l'application, permettant ainsi d'accélérer une attaque ou de dérober des informations confidentielles précieuses. Le code source, ainsi que les données, obfuscation est un élément important de toute protection par analyse statique. Voici quelques façons de transformer le code et les données pour ralentir les acteurs malveillants. Plus ils doivent travailler, plus… safenotre monde peut l'être.

Privatisez votre protection

Bien que les applications ne devraient pas être distribuées sans une forme d'obfuscation, toutes les obfuscations ne se valent pas. Deux composantes essentielles d'une obfuscation efficace sont la adresse IP privée et l'aléatoire. Les obfuscateurs open source actuellement disponibles peuvent être tout aussi utiles aux attaquants qu'aux développeurs d'applications. Le niveau de protection qu'ils offrent est insuffisant pour sécuriser de manière fiable les applications d'entreprise. Une obfuscation efficace doit transformer le code source en quelque chose d'illisible pour les humains et d'irréversible par les outils d'attaque automatisés. Les techniques d'obfuscation publiques constituent leur propre pierre de Rosette, permettant de les contrer. L'utilisation de techniques d'obfuscation personnalisées et non accessibles au public empêche Timmy Turner de déchiffrer l'obfuscation d'une application à l'aide de ses fées d'IA génératives. Associez ces algorithmes privés à un aléatorisme inhérent pour garantir qu'aucun humain, ni même un LLM, ne puisse démêler le tout.

PRNG contre-attaque

Les attaquants peuvent recueillir de nombreuses informations en comparant différentes versions d'une même application. Il est donc absolument essentiel que les techniques d'obfuscation varient d'une version à l'autre. La plupart des moteurs de pseudo-randomisation utilisent une graine pour garantir la prévisibilité tout en préservant l'aléatoire inhérent, et les techniques d'obfuscation ne font pas exception. Le simple fait d'incrémenter ou de décrémenter cette graine a un impact considérable sur les techniques d'obfuscation appliquées à une application. Cela permet la reproductibilité en cas de besoin, mais oblige les attaquants à tout recommencer lorsqu'ils tentent de rétro-ingénierer une application après la publication d'une nouvelle version. C'est comme si l'attaquant déneigeait la moitié de l'allée, prenait une pause chocolat chaud et revenait pour trouver de la neige fraîche. Une sécurité robuste vise à éviter ce gaspillage de temps. rétro-ingénierie Le temps, et un paysage en constante évolution, est l'un des meilleurs moyens de perdre son temps.

Obfuscation Obfuscation Obfuscations

Conceptuellement, l'obfuscation est l'inverse de l'optimisation. De même que les compilateurs effectuent souvent plusieurs passes d'optimisation, nous effectuons plusieurs passes d'obfuscation. Autrement dit, nous appliquons l'obfuscation aux obfuscations qui viennent d'être ajoutées. Le résultat est extrêmement difficile à lire.

Figure 1 : Plusieurs passes d'obfuscation réduisent considérablement l'efficacité d'outils tels que Ghidra pour résoudre le flux de contrôle du programme.

Une simple instruction `add` ou `mov` peut rapidement se transformer en cinquante, voire des centaines d'instructions. Un brouillage efficace des paires `adrp add` peut anéantir la capacité d'un outil automatisé (comme Ghidra ou IDA) à analyser le flux d'exécution du programme. Des brouillages apparemment mineurs peuvent rendre presque impossible pour un attaquant de localiser le début, la fin ou même le milieu de l'appel à la fonction `acceptUserCredentials`. Des centaines de brouillages cumulatifs et variés contraignent les attaquants potentiels à tenter de comprendre comment le code peut s'exécuter correctement.

Tape-le, tords-le, configure-le

Tous les appels de méthode ou de fonction ne sont pas sensibles dans une application, et certains peuvent avoir un impact considérable sur les performances. Bien qu'une obfuscation uniforme de l'ensemble de l'application soit nettement préférable à l'absence d'obfuscation, cette stratégie peut impacter significativement les performances d'exécution. Offrir aux ingénieurs en sécurité la possibilité d'obfusquer fortement les appels sensibles, tout en minimisant l'obfuscation des appels gourmands en ressources, contribue à fournir un outil de protection de pointe. Toute protection dynamique (Garde) injectée dans l'application requiert le même niveau d'obfuscation que le code source sous-jacent. Appliquer les mêmes techniques d'obfuscation de haute sécurité à ces gardes actifs permet de garantir leur protection et leur fonctionnement, et de ralentir les efforts des attaquants pour les identifier et les supprimer. La configurabilité est essentielle pour toute organisation axée sur la sécurité, et les outils de protection doivent évoluer aussi rapidement que la stratégie de l'entreprise. Comme mentionné précédemment, certaines obfuscations sont conçues différemment. Voici quelques concepts que tout moteur d'obfuscation sérieux propose, et comment il peut bloquer le trafic non autorisé.

Flux de contrôle calculé

Les attaquants peuvent obtenir de précieuses informations sur une application simplement en analysant le flux des appels de fonctions. Pour contrer cela, nos techniques d'obfuscation utilisent le flux de contrôle calculé (CCF). Le CCF empêche les décompilateurs de relier les appels de fonctions et les références d'étiquettes au point d'entrée principal de l'application. Il s'agit d'un élément essentiel de toute protection de pointe. Lorsqu'un décompilateur analyse un binaire, il est souvent aisé de déterminer comment une fonction en appelle une autre. Prenons par exemple les instructions `b.eq 0x10055bc42` et `bl 0x100abcdef`. Un décompilateur sait précisément ce qui se trouve à ces adresses mémoire virtuelles. Dans le cas de ces deux instructions, il s'agit soit d'étiquettes au sein d'une fonction, soit de l'appel de fonction lui-même. Tout décompilateur digne de ce nom révélera un réseau complexe d'appels de fonctions imbriqués, illustrant clairement le chemin d'exécution au sein de l'application. Combinez cela avec d'autres techniques de base, comme repérer l'emplacement du message « connexion réussie » dans le code assembleur, et il devient très facile pour un attaquant d'identifier le code exploitable. Le flux de contrôle calculé est un ensemble d'opérations mathématiques injectées avant les appels de flux de contrôle évidents. Ces opérations empêchent un décompilateur de connaître l'adresse virtuelle relative exacte vers laquelle le saut est effectué, le rendant incapable de générer un graphe de flux de contrôle.

Figure 2 : Le flux de contrôle calculé (à droite) empêche un décompilateur de connaître l'adresse virtuelle relative exacte vers laquelle le saut est effectué, détruisant ainsi sa capacité à générer un graphe de flux de contrôle fonctionnel (à gauche).

Aplatissement du flux de contrôle

Le flux de contrôle calculé (CFF) est déjà un véritable fléau pour les décompilateurs ; il serait regrettable de l'aggraver. Une autre stratégie pour perturber le flux de contrôle logique est appelée aplatissement du flux de contrôle (CFF). Il existe différentes variantes de CFF, mais une variante récemment ajoutée (nommée Nexus) redonne un nouveau souffle à cette technique d'obfuscation cruciale. Nous avons tous déjà écrit un jeu d'échecs dans la fonction `main`, mais imaginez écrire une application complète de niveau production dans une seule instruction `switch` autoréférentielle ! Nexus permet justement cela, tout en privilégiant les performances d'exécution. On trouve une multitude d'informations sur le CFF, son importance et son fonctionnement. Il est impossible de surestimer à quel point cette technique d'obfuscation complique la tâche des attaquants, et aucune application ne devrait quitter l'environnement de test sans en être dotée.

C hopup

Aucun ensemble de couteaux en acier inoxydable ne serait complet sans une paire de ciseaux assortie, et Chopup complète l'obfuscation du flux de contrôle de la même manière. Les formats de fichiers binaires sont généralement compactés pour économiser de l'espace disque. Cela signifie que la plupart des appels de fonctions liés sont très proches les uns des autres. Par conséquent, un binaire désassemblé tend à regrouper les fonctions liées et les présente presque toujours comme un bloc contigu. C'est beaucoup trop facile à déchiffrer, et c'est vraiment agaçant. Chopup change la donne. Aucune restriction technique n'impose aux appels de fonctions d'être contigus en mémoire dans un binaire, et une bonne paire de ciseaux (avec un peu de colle flexible) peut laisser un binaire fonctionner comme prévu tout en obligeant les attaquants à explorer chaque recoin du binaire à la recherche du flux de contrôle logique.

Figure 3 : Chopup oblige les attaquants à parcourir chaque recoin du binaire à la recherche d'un flux de contrôle logique.

mgDaea et réparation

Bien que l'obfuscation du flux d'exécution du code soit une couche de protection cruciale, l'obfuscation des données sous-jacentes de l'application est tout aussi nécessaire. Les mécanismes de dommage et de réparation sont à la fois le Mal chaotique et le Bien loyal des protections contre l'analyse statique, et ils sont presque toujours indissociables. Endommager une donnée, voire, dans certains cas, une portion de code, puis la réparer juste avant sa lecture ou son exécution rend l'analyse statique pratiquement impossible. Le dommage transforme les données spécifiées en ce qui ressemble à de la mémoire indéfinie. Lorsque ces mêmes données sont exposées à un appel de réparation, elles retrouvent leur forme originale, souvent juste avant d'être utilisées. Ces données peuvent ensuite être endommagées à nouveau après être sorties de la portée et ne seront utilisées que lors du prochain appel de la fonction. La clé API pourrait initialement ressembler à « 1#&at0d$*nd@@z » dans le binaire, mais rassurez-vous, elle sera corrigée avant d'être utilisée.

Renommage des symboles

Même avec l'obfuscation du code source et des données, des noms de symboles subsistent dans un binaire compilé. Par exemple, un symbole associé à une fonction comme « acceptContinuousPayment » permet d'accéder directement à son implémentation. Une fois cette implémentation découverte, il est très facile de modifier le code assembleur et d'accéder à des fonctionnalités premium sans payer. Un renommage complet des symboles masque ces symboles résiduels et ne laisse aucune trace exploitable aux attaquants. Supprimer toute indication ou indice concernant les fonctionnalités sensibles d'un binaire protégé peut dissuader les attaquants d'utiliser l'analyse statique.

Figure 4 : Le renommage complet des symboles masque les artefacts restants et ne laisse rien aux attaquants.

La Fin

Ce ne sont là que quelques exemples de bonnes pratiques et méthodologies d'obfuscation, et cette liste est loin d'être exhaustive. Laisser une application sans protection en production offre à quiconque une visibilité complète sur son adresse IP et permet à tout attaquant d'accéder sans difficulté à la logique métier. Avec l'essor fulgurant de l'IA générative et des outils d'analyse de code source, écrire du code, et même le rétro-ingénierie, est devenu infiniment plus simple. Dans un environnement aussi dynamique, seul un engagement collectif en faveur de la mise en œuvre de solutions de sécurité robustes est envisageable. Protégez le travail acharné de vos développeurs.

 

Lisez l'analyse d'IDC sur l'importance de obfuscation et protection contre la falsification dans le cadre de votre DevSecOps entraine toi.

Vous aimerez aussi