VT2017 Cdoe Obofsucaitn
Présentation Veille Technologique
- Sujet : Cdoe Obofsucaitn
- Auteur : Lucas Lesage
- Date : 6 Octobre 2017
- Enseignants : Didier Donsez, Georges-Pierre Bonneau
Résumé
Un anagramme de "Code Obfuscation", littéralement "Obscurcissement de code" avec pour définition d'obfuscation : "The action of making something obscure, unclear, or unintelligible." Il s'agit dans le cas du code d'utiliser diverses méthodes pour rendre difficile la lecture de tout ou une partie du code source d'un programme ou un logiciel. La finalité étant de compliquer le reverse engineering de code ainsi que le vol de celui-ci. Pour cela, il ne suffit pas de changer les noms de variables ou de supprimer les espaces entres caractères autant que possible, de plus, le code doit rester entièrement fonctionnel que ce soit le code de base ou celui "obscurcit".
Mots clés
Code, Cryptographie, Programmation bas-niveau, Sécurité, Propriété individuelle
Abstract
An anagram for "Code Obfuscation", meaning : "The action of making something obscure, unclear, or unintelligible." In the case of coding, this concerns the use of multiple methods to make harder the readability of a part or all of a source code from a program/software. The goal is to complicate the code reverse-engineering as well as its theft. In order to do that, changing variables' name or removing as much white spaces as possible is not enough, moreover, code obfuscation implies that the code has to be fully functional as if it wasn't "modified".
Keywords
Code, Cryptographie, Low-level Programming, Security, Personal Property
Synthèse
Introduction du terme
La protection des données logicielles est un problème qui existe depuis plusieurs dizaines d'années, des conventions sont même apparues pour rassembler les programmeurs les plus créatifs, comme l'IOCCC depuis 1984 ! Déjà à l'époque il s'agissait d'un soucis de récupération de code par les concurrents, voire de modification directe du code source, car celui-ci doit être fourni au client avec le logiciel.
Il est donc naturel de souhaiter rendre son code irrécupérable mais entièrement fonctionnel, mais très souvent, il n'est pas possible d'utiliser une formule magique et d'obtenir un code obscurcit, c'est d'ailleurs une partie de la problématique, comment cacher son code de façon récurrente et non décryptable. De plus, et c'est la deuxième problématique, les langages comme le C, le Perl ou l'assembleur offrent un accès aisé à la programmation bas niveau et ainsi permet de réaliser du code extrêmement illisible pour un être humain, même aidé par des programmes (Exemple 1). Mais les autres langages ne permettent pas un tel contrôle du code, et ainsi, comment créer un processus de cryptage du code qui soit applicable pour tout langage?
Problématique
Situation actuelle
But : Trouver un obfuscateur universel pour tous les langages et qui garantit la protection du code en le rendant illisible. L'intêret pour l'obfuscation de code est revenu lors de la mise en relation avec la cryptographie , à partir des années 2000, car elle était jusque là assez précaire.
Satoshi Hada et Boaz Barak sont deux chercheurs ayant beaucoup étudiés cette relation et au cours de leurs recherches, ont essayés de créer une méthode d'obfuscation universelle. La première méthode, nommée Blackbox obfuscation a pour logique : "Anything that can be efficiently computed from O(P) can be efficiently computed given oracle access to P." (Extrait de leurs papier). Cette logique est que pour tout résultat à partir d'un programme obfusqué, on devrait pouvoir obtenir le même résultat avec le programme normal. Mais cette méthode pose problème au niveau de fonctions probabilistes et de nombreuses fonctions et libraries non obfusquable.
En conclusion de leurs papier, ils énoncent plusieurs pistes sur d'autres méthodes obfuscation, dont une en particulier qui semblait plus réalisable, l'Indistinguishable Obfuscation. Dans celle-ci, les programmes sont vus comme des circuits électroniques, et sont donc composés de plusieurs composants. Ainsi, soit un un résultat souhaité R, on peut former plusieurs programmes Cx tels que ceux-ci renvoient le même résultat, mais sont formés différemments (dans ce cas, différentes combinaisons de ET, OU, OUEX, NOT). Vu qu'on ne connait que le résultat à partir de ces programmes obfusqués, et que ce résultat est identique, on assume alors qu'ils sont indistinguable l'un de l'autre. Ainsi, il n'est pas possible de savoir quel programme est lancé et cela offre une abstraction totale sur l'utilisation du code.
Cependant, il y a un très grand problème de taille de code et de consommation ressources (plusieurs minutes pour obtenir resultat).
Recherche de l'obfuscateur idéal
Grâce à l'étude du théorique Indistinguishable Obfuscation, une symétrie vers la cryptographie a été notée, particulièrement vers l'Homomorphic encryption. Le principe de l'iO est similaire à la méthode RSA, on possède un programme crypté qui peut seulement être décrypté avec la "clé", on est également libre pour l'entrée du programme, et obtenons en sortie un résultat clair. Ainsi une piste vers la réalisation de l'iO pourrait être une variante de la cryptographie, mais cet aide n'est pas unilatérale, car dans le cas où on puisse crypter n'importe quel programme de façon sûre et durable, alors il serait possible d'obfusquer l'algorithme de génération de clé et de le rendre publique, car son fonctionnement ne serait pas révélé.
L'iO reste une idée, on a des moyens d'essayer de le faire, mais rien de suffisamment sécurisé n'en découle et donc n'a pour le moment aucune véritable utilité. Mais dans le futur, on finira par trouver une réalisation de l'iO et cela entrainera une vague de renouveau dans la sécurité de l'encryption et dans la programmation.
Avantages et inconvénients
Avantages
- Peut sécuriser d'autres aspects de l'informatique (ex : clé d'encryption)
- Peut être utilisé pour réduire la taille de code.
- Décourage les petits voyous de l'internet.
Inconvénients
- Virus et autres malwares plus difficilement contrés.
- Pas de retour en arrière après obscurcissement. (Sauf avec une méthode d'obscurcissement => Mais devient plus facile à décoder)
- Code visuellement "étrange", donc peu provoquer de la méfiance.
- Pour le moment, cher à mettre en place et le rapport ressources/sécurité n'est pas haut.
Conclusion
L'obfuscation de code reste un sujet délicat car beaucoup trop théorique. Il est possible de cacher son code, mais rien de permanent ou de suffisamment sécurisé n'existe encore, cependant les solutions existantes suffisent à décourager la majorité des potentiels "voleurs de code". Il est bon néanmoins de garder en tête que les tentatives de sécurités les plus poussées en informatique entraînent une émergence d'attaquants souhaitant démanteler le système.
Exemples
Exemple 1
[[]+1/!1][1^1] [1>>1]+({}+[]) [1<<1^11>>1]+([]+!!- [])[1<<1]+[/~/+{}] [+!1][-~1<<1]+/\ [[^1]+\]/[([]+![]) [1<<1<<1]+(/|/[(1+{}) [1+11>>>1]+[[]+{}] [+!1][1]+([]+1/[]) [1<<1>>1]+([1<1]+[]) [1+11>>>1+1]+[[!!1]+1] [+[]][1-1]+([]+!!/!/) [1|1]+(/1/[1]+[]) [!1%1]+(-{}+{}) [-1+1e1-1]+(1+[!!1]) [1]+([]+1+{}) [1<<1]+[!!/!!/+[]] [+[]][1&1]]+/=/) [1e1+(1<<1|1)+(([]+/-/ [(!!1+[])[1>>1]+(!!1+[]) [1<<1^1]+(!1+[]) [1|1<<1]+(!!1+[])[1^1]]) [1^1]==+!1)]+(!![]+{}) [1|1<<1]+[1+{}+1][!1+!1] [(11>>1)+1]](([]+/-/ [(!!1+[])[1>>1]+(!!1+[]) [1<<1^1]+(!1+[]) [1|1<<1]+(!!1+[]) [1^1]]))[1&.1] [11>>>1]+([,][~1]+[]) [1-~1]+[[]+{}][!1.1% 1[11111.1%11.1*111e 11|!1]+(/1/+1/[1<1] [1%1])[1^11]+[[],[]+{}] [1<<1>>>1][1||1]+(/ [<+>]/[1&1|1]+[1.1]) [1/11.1&1.11]
Ce code, écrit en JavaScript, est un parfait exemple de manipulation de chaines de caractères et de bit. En effet, le résultat obtenu est la chaine : "I love you". Le programme jouant avec la particularité du langage, avec comme par exemple :
[[]+1/!1][1^1][1>>1]
Qui récupère la chaine "Infinity", se positionne au début de celle-ci et en extrait la première lettre.
Exemple 2
#include<stdio.h> #include<string.h> main() { char*O,l[999]="'`acgo\177~|xp .-\0R^8)NJ6%K4O+A2M(*0ID57$3G1FBL"; while(O=fgets(l+45,954,stdin)){ *l=O[strlen(O)[O-1]=0,strspn(O,l+11)]; while(*O)switch((*l&&isalnum(*O))-!*l){ case-1:{char*I=(O+=strspn(O,l+12)+1)-2,O=34; while(*I&3&&(O=(O-16<<1)+*I---'-')<80); putchar(O&93?*I&8||!(I=memchr(l,O,44))?'?':I-l+47:32); break; case 1: ;}*l=(*O&31)[l-15+(*O>61)*32]; while(putchar(45+*l%2),(*l=*l+32>>1)>35); case 0: putchar((++O,32));} putchar(10);} }
Ce code en C est un "simple" convertisseur ASCII -> Morse.
Exemple d'utilisation avec entrée "Menacingly":
-- . -. .- -.-. .. -. --. .-.. -.--