Techniques d obfuscation de code chiffrer du clair avec du clair.pdf
(
323 KB
)
Pobierz
Techniques d’obfuscation de code : chiffrer du clair avec
du clair
La plupart des infections informatiques (vers, virus, chevaux de Troie, etc.) utilisent désormais le
chiffrement pour changer de peau. Elles utilisent également d'autres types de transformations pour
rendre la vie plus difficile aux " laborantins " des sociétés éditrices de produits antivirus. Vous
découvrirez dans ces pages quelquesunes de ces techniques.
Introduction
Les transformations d'obfuscation sont utilisées et donc étudiées depuis longtemps dans les cartes à
puce. Elles sont depuis peu utilisées pour la protection (purement logicielle) de contenu et la gestion
numérique des droits.
Cette famille de mécanismes, à défaut d'être purement cryptographique, est présente dans la
cryptographie opérationnelle pour assurer la protection des clés et autres secrets. Nous expliquons
son utilité pour les virus.
Après avoir donné une définition formelle de la notion d'obfuscation, nous examinons quelques
techniques d'obfuscation, tentons d'en établir une classification et donnons quelques critères pour
mesurer leur pertinence. De nombreux exemples illustrent l'exposé (en C dans la mesure du
possible).
Définition : obfuscation
Un obfuscateur
Ƭ
peut être vu comme un compilateur particulier. Il prend en entrée un programme
ou un circuit P et produit un nouveau programme
Ƭ
(P) qui possède deux propriétés :
•
•
Ƭ
(P) a les mêmes fonctionnalités que P. En d'autres termes,
Ƭ
(P) calcule les mêmes
fonctions que P.
Ƭ
(P) est inintelligible, dans le sens où
Ƭ
(P) constitue une boîte noire virtuelle.
Une telle boîte noire virtuelle
Ƭ
(P) est caractérisée, du point de vue de la théorie de la complexité,
par le fait que quiconque est capable de réaliser un calcul effectif au moyen de
Ƭ
(P), peut alors
réaliser ce même calcul en ayant accès par le biais d'un oracle au programme P (c'estàdire en
pouvant disposer d'une infinité de couples (entrée/sortie) du programme). Cela signifie simplement
que si quelqu'un est capable de faire des calculs avec
Ƭ
(P), alors il peut réaliser ces mêmes calculs
en observant uniquement les entrées/sorties du programme P.
Nous parlerons plus loin des implications théoriques de cette définition.
Un mécanisme d'utilité virale
Pour les virus, l'obfuscation de code (permet de rendre le code viral difficile à comprendre) fait
partie des mécanismes de base, au même titre que la furtivité (permet de rendre le code viral
difficile à localiser sur le système) ou le polymorphisme (permet de rendre difficile l'identification
par signature unique d'un programme viral).
Les transformations permettant de remplacer du code en clair avec du code en clair
fonctionnellement équivalent, présentent un intérêt évident pour les virus :
•
Elles permettent de contourner les moteurs d'analyse spectrale ou tout autre moteur fondé sur
une mesure de l'entropie (ces transformations conservent le plus souvent la distribution des
•
•
opcodes ainsi que l'entropie. Le code résultant d'une opération de chiffrement classique sera
identifié comme suspect par de tels moteurs de détection).
Elles permettent de protéger les clés et l'algorithme de chiffrement utilisé, le cas échéant. Le
résultat de ces transformations est un camouflage de certaines structures de données et
certaines zones de code (ces transformations participent alors à la gestion des clés (et
peuvent être assimilées à ce titre à des primitives de nature cryptographique).
De manière générale, les transformations d'obfuscation de code permettent de protéger les
données critiques statiques du virus, c'estàdire les valeurs qui ne doivent pas pouvoir être
modifiées, qui doivent rester secrètes ou qui sont indispensables à l'exécution sécurisée des
routines vitales du virus (contrôle d'intégrité, détection d'une exécution en mode pas à pas,
de la présence d'un débogueur sur le système ou d'une exécution sous émulateur ou système
de virtualisation, etc.).
Le code permettant de réaliser une transformation d'obfuscation peut facilement être modifié afin
d'assurer également une fonction de diversification (réalisation d'instances équivalentes
fonctionnellement au programme original et difficiles à analyser, fondée sur l'utilisation conjointe
d'une ou plusieurs sources d'aléa du système hôte). Cette amélioration permet de participer au
polymorphisme et d'augmenter l'effort requis pour lever les protections et automatiser le processus
de désinfection. Elle permet donc d'augmenter les chances de survie du programme viral.
Un mécanisme cryptographique ?
La cryptographie malicieuse ou cryptovirologie peut se définir comme l'étude des mécanismes
cryptographiques dans le contexte de leur utilisation par des infections informatiques [21]. Des
mécanismes cryptographiques classiquement dédiés à la sécurité ou à la sûreté de fonctionnement
sont pervertis dans leur utilisation et appliqués au développement d'infections informatiques
toujours plus robustes.
Des techniques de génération environnementale de clés de chiffrement, fondées sur l'utilisation de
fonctions à sens unique et initialement développées pour augmenter la résistance des agents
logiciels mobiles [18], vont également pouvoir s'appliquer au développement de programmes viraux
hautement résistants à l'analyse par rétroconception (les virus dirigés [10]).
Ces techniques purement cryptographiques permettent de résoudre le problème de la protection des
clés de chiffrement, mais au prix d'une perte d'indépendance du programme viral (le virus est dirigé
par son concepteur). Pour pallier ce type de problème, les techniques de protection de contenu
comme les transformations d'obfuscation apparaissent indispensables, d'un point de vue
opérationnel.
On distingue en général le chiffrement de l'obfuscation : une transformation d'obfuscation, même si
elle est le plus souvent paramétrée par une clé (voir par exemple [2]), effectue par le biais de
substitutions successives, la transformation d'un message clair en un autre message clair.
Les primitives cryptographiques d'obfuscation des données, telles que les permutations paramétrées
par une clé, sont des contremesures naturelles aux attaques non intrusives logiques (voir par
exemple [12] pour une description de ces attaques). Ces primitives sont très adaptées à la réalisation
de brouilleurs matériels dans les cartes à puce : brouillage du bus de données entre le
microprocesseur et la mémoire ou entre le CPU et le cryptoprocesseur, brouillage de la RAM. Ces
primitives peuvent être incorporées dans des fonctions de brouillage de données non linéaires plus
évoluées. Appliquant le paradigme confusion/diffusion de Shannon, ces primitives peuvent être
utilisées sous la forme de petites matrices de substitution en couches alternées avec des fonctions
affines. Ce type de construction n'assure cependant pas le même niveau de sécurité que l'utilisation
d'un système de chiffrement par blocs classique.
Virologie et protection de contenu : un combat unifié contre la
rétroingénierie
La virologie informatique et la problématique de protection de contenu sont étrangement
symétriques dans l'utilisation de la cryptographie :
•
•
Un programme viral implémente des mécanismes cryptographiques pour contourner les
logiciels antivirus et ralentir l'analyse de son code.
Un logiciel implémente des mécanismes comparables pour protéger une licence d'utilisation
ou protéger le contenu ou les secrets de conception de l'application contre l'analyse.
La communauté des développeurs de virus montre une grande motivation quant à l'utilisation de
techniques d'obfuscation de code. Leur approche est aujourd'hui encore très empirique, mais nous
pouvons sentir d'ores et déjà une volonté d'augmenter le niveau de modularité et de sophistication
des programmes viraux [22].
De nouvelles techniques cryptographiques naissent du besoin plus impérieux d'assurer la protection
d'une application par voie purement logicielle. Nous pouvons prédire que ces techniques seront
perverties par les concepteurs de virus.
Qualification des transformations
d'obfuscation
Après avoir rappelé les résultats théoriques les plus importants concernant les transformations
d'obfuscation, nous donnons des critères théoriques et empiriques permettant de qualifier une
transformation d'obfuscation.
Obfuscation : la théorie
Nous avons vu en introduction qu'un obfuscateur
Ƭ
doit rendre le programme
Ƭ
(P) inintelligible
dans le sens où tout ce que l'on peut apprendre du programme
Ƭ
(P), en ayant accès à son code et à
ses états internes lors de son exécution, peut être obtenu uniquement à partir des entrées/sorties du
programme P. En d'autres termes, tout ce que l'on peut espérer apprendre lors d'une analyse du
programme protégé, on peut l'apprendre en exécutant le programme et en observant ses
entrées/sorties.
Avec une telle définition, et en construisant une famille de fonctions qui ne sont pas obfuscables, il
est démontré qu'un obfuscateur parfait, c'estàdire qui puisse rendre un programme inintelligible au
sens défini précédemment, n'existe pas [1].
Cela ne signifie pas qu'il n'y a pas de méthodes permettant de rendre un programme inintelligible
dès lors qu'un sens moins absolu est donné à ce terme. Une définition affaiblie de la notion
d'obfuscation, c'estàdire une définition qui évite le paradigme de la boîte noire virtuelle, peut être
donnée (en remplaçant le paradigme de la boîte noire virtuelle par une propriété plus faible, assurant
l'existence d'un obfuscateur
Ƭ
qui, étant donné deux circuits C1 et C2 calculant la même fonction,
assure que
Ƭ
(C1) et
Ƭ
(C2) sont impossibles à distinguer l'un de l'autre).
Qualification : critères théoriques
Même si un obfuscateur parfait n'est théoriquement pas réalisable, une évaluation au regard de la
théorie de la complexité/décidabilité reste indispensable pour qualifier complètement une
transformation d'obfuscation.
L'idée est de prouver que la transformation permet d'augmenter suffisamment la difficulté d'une
analyse de type boîte noire (reconstruction du graphe des états par observation des entrées/sorties)
en diversifiant les sorties. Chaque transition d'état lors de l'exécution d'un programme dissémine
une certaine quantité d'information dans son environnement. La somme de ces informations peut
être suffisante à un observateur pour déterminer l'espace des états du programme. La quantité
moyenne d'information fournie par chaque observation doit être la plus petite possible, afin
d'augmenter l'effort nécessaire à la désobfuscation.
Par exemple, dans le cas des transformations interprocédurales utilisant des tableaux de pointeurs
de fonctions (voir cidessous), il est possible d'apporter une preuve théorique de leur efficacité : la
complexité de l'analyse interprocédurale d'un programme protégé par ce type de primitive croît de
manière exponentielle avec la taille du programme [16].
Qualification : critères empiriques
De nombreuses transformations d'obfuscation sont très utiles, même s'il n'est pas toujours possible
de prouver leur pertinence au regard de la théorie de la complexité. Des critères plus souples
permettent de décrire et de classifier ces transformations. Ces critères, même s'ils reposent sur des
mesures de complexité, sont empiriques.
Nous donnons cidessous quelques critères permettant d'évaluer l'efficacité d'une transformation
d'obfuscation.
La puissance
Étant donné une transformation d'obfuscation
Ƭ
, nous pouvons définir le niveau d'obfuscation
comme le degré de gêne imposée par cette transformation à un attaquant humain. Étant donné une
métrique µ, notons cµ(P) la complexité du programme P au regard de cette mesure de la complexité.
Pour fixer les idées, la métrique µ considérée pour mesurer la complexité d'un programme peut être
par exemple la longueur du programme. cµ(P) augmente alors avec le nombre d'instructions
(opérateurs et opérandes) dans P. D'autres métriques, empruntées à la théorie de l'optimisation,
pourront être trouvées dans [5].
Nous définissons alors la puissance d'une transformation d'obfuscation
Ƭ
relativement à un
programme P par :
La résistance
Étant donné une transformation d'obfuscation
Ƭ
, nous pouvons définir le niveau d'obfuscation
comme une mesure de l'effort requis pour défaire la transformation. Nous pouvons identifier deux
axes d'effort :
•
•
L'effort de développement d'un outil automatique de désobfuscation capable de réduire
effectivement la puissance de la transformation.
La quantité de mémoire et de cycles CPU requis par l'outil automatique de désobfuscation.
Ces deux axes permettent de définir une matrice R dont les valeurs correspondent aux résistances
d'une transformation d'obfuscation
Ƭ
relativement à un programme P :
où
Ƭ
1(P) donne une mesure de l'effort de développement requis pour mettre au point l'outil, en
fonction du périmètre de la transformation (locale à un bloc d'instruction du graphe CFG, globale,
interprocédurale, interprocessus) et
Ƭ
2(P) une mesure de l'effort requis par l'outil (polynomial,
exponentiel).
Le coût
Le coût
Ƭ
cost(P) d'une transformation d'obfuscation
Ƭ
(appliquée à un programme P) correspond à
une mesure de la consommation supplémentaire, en termes de ressources (temps CPU/espace
mémoire), induite par la protection. Le coût augmente avec la complexité induite (constante,
linéaire, polynomiale, exponentielle).
La furtivité
La définition de ce critère vient de l'observation suivante : si une transformation introduit du code
nouveau dans le programme protégé
Ƭ
(P), un attaquant pourra facilement le détecter et exploiter
cette faiblesse pour lever la protection. Nous définissons donc un ensemble de caractéristiques du
langage utilisé par un programme, (P). Notons (
Ƭ
) l'ensemble des caractéristiques du langage
introduites par la transformation d'obfuscation
Ƭ
. Nous définissons la furtivité de la transformation
Ƭ
relativement au programme P par :
Si la transformation n'enrichit pas le langage des programmes qu'elle protège (on a alors (
Ƭ
)=0), la
furtivité
Ƭ
ste(P) est maximale et égale à 1.
La qualité
Nous pouvons à présent définir la qualité d'une transformation d'obfuscation relativement à un
programme P par :
où f est une fonction décroissante du coût (les autres paramètres étant fixés) et croissante des autres
critères.
Exemple de mesure de qualité
Nous pouvons par exemple définir la qualité d'une transformation par :
où
ω
i,i=1,2,3 sont des constantes fixées en fonction du contexte opérationnel d'utilisation des
transformations d'obfuscation
(ici, nous avons choisi :
Plik z chomika:
qfx
Inne pliki z tego folderu:
Bypassing Stack Cookies, SafeSeh, HW DEP and ASLR.pdf
(3140 KB)
Analyse du fonctionnement d un programme suspect.pdf
(2383 KB)
Analyse de code malveillant.pdf
(1760 KB)
Analyse d un packer de trojan et programmation d un unpacker.pdf
(756 KB)
Control Flow Obfuscations in Malwares.pdf
(1716 KB)
Inne foldery tego chomika:
Pliki dostępne do 21.01.2024
Pliki dostępne do 27.02.2021
Cisco
Classic Computers
Courseware
Zgłoś jeśli
naruszono regulamin