Introduction au Reverse Engineering

Outils et techniques utilisés
Outils utilisés
De nombreux outils sont utilisés afin de réussir son Reverse. Pour cela, on peut les dissocier en plusieurs types :
Tout d'abord, la rolls royce des systèmes d'exploitation est spécialisée dans le domaine de la sécurité : Kali linux. De nombreux outils liés au reverse y sont installés, comme par exemple :
- Le débugger / désassembleur ollydgb,
- Le décompileur jad, pour JAva Decompiler,
- Flasm, le désassembleur d'animation flash (format SWF),
- Javasnoop, qui permet d'intercépter les appels de méthode ou de changer les données pour tester la sécurité d'une application Java,
- et bien d'autres ...
Concernant les outils d'analyse réseaux, on peut citer (liste non exhaustive):
- netstat: Permet de réaliser des statistiques sur l'état du réseau : Connexions entrantes et sortantes, tables de routage, etc... (NETwork STATistics),
- nmap: Outils de scan permettant de repérer hôtes et services d'un réseau (Network MAPper),
- tcpdump: Permet d'analyser l'ensemble des paquets reçus par le réseau (réseaux filaire ou sans fils).
Une analyse de binaires peut se faire de la manière suivante (liste non exhaustive):
- strings: affiche les caractères interprétables,
- nm: donne les informations concernant les symboles d'un exécutable,
- ltrace: trace les appels aux librairies,
- strace: trace les appels aux appels systèmes,
On peut également utiliser des outils comme objdump en parallèle, qui permet d'obtenir des informations sur un binaire, comme le code assembleur associé au binaire. D'autres outils, plus interactifs, permettent d'observer le code assembleur et d'éditer le code hexadécimal associé, comme hte.
- Pour pouvoir revenir au code source, et éviter la partie assembleur un peu trop complexe, on peut utiliser des décompilateurs, comme boomerang, ou Hex-Rays IDA (licence payante). Le code généré est similaire au programme source d'origine, mais sans la syntaxe associée (dûe à la perte de ces données au moment de la compilation).
Attention, certains programmes peuvent faire de l'obfuscation et parasiter la compréhension de l'analyse du binaire.
D'autres possibilités permettent de protéger les logiciels, comme la protection par Serial, etc...
Vous pouvez aller voir ici pour plus d'informations sur les protections.

Techniques employées
Les techniques les plus employées sont divisées en fonction du contexte d'analyse, c'est-à-dire soit en boîte blanche, soit en boîte noire.
Pour une analyse en boîte noire, on y retrouve :
Avec une analyse active, comme l'on peut interagir avec les entrées et sorties, la technique la plus courrament utilisée est le fuzzing. On peut distinguer plusieurs types de fuzzing, ou fuzz testing, comme par exemple :
- Le fuzzing 'standard' correspond à envoyer un grand nombre de données aléatoires en entrées et à vérifier que le programme ne se crash pas, ou ne provoque pas de memory-leak.
- Le fuzzing 'intelligent' correspond à adapter les entrées, plutôt qu'à les générer de manière aléatoire en fonction de la valeur de sortie du programme.
Avec une analyse passive, comme l'on ne peut pas interagir avec les entrées et sorties, la technique utilisée est le plus souvent une analyse des entrées et sorties du programme (trames générées, valeur de sortie en fonction de telle entrée, etc...)
Pour une analyse en boîte blanche, on peut trouver :
- Avec une analyse statique, on peut retrouver la technique dite d'interpréation abstraite : On va chercher à approximer la sémantique du programme, avec notamment son ensemble de données, son orchestration, etc... Cette technique peut également être utilisée en analyse dynamique, en exécutant partiellement le programme.
Avec une analyse dynamique, de nombreuses techniques sont possibles :
- On retrouve le fuzzing : Avec une analyse en boîte noire, on pouvait obtenir des bugs sur un programme. Avec l'analyse en boîte blanche, le but est d'étudier le comportement du programme avec les entrées ayant réaliser le bogue.
Il existe aussi l'exécution symbolique dynamique, aussi apellée exécution concolique (pour concrète symbolique). Pour la comprendre, prenons un exemple :
Programme | Execution concrète | Execution symbolique 1: var x = 3; | x <- 3 | x <- 3 2: var y = x-2; | y <- 1 | y <- x-2 3: if(x<0) | 3<0? | x<0? 4: x=-x; | ---- | ---- 5: if(y<10) | 1<10? | x-2<10? 6: y=-y; | y <- -1 | y <- -x+2
L'exécution concolique consite à associer une exécution concrète (var x=3, var y = 1, etc...) à une exécution symbolique (var x=3, var y = x-2, etc...)
L'intérêt est d'utiliser la trace concrète pour choisir la branche à emprunter, et la trace symbolique permettra d'accumuler les conditions rencontrées pour obtenir une formule dont la solution est l'ensemble des entrées produisant le même chemin. Ainsi, si cette formule n'a pas de solution, c'est que le chemin n'est pas possible.
Cela permet notamment d'augmenter la couverture d'une analyse dynamique, ainsi que la couverture de code.
Pour notre exemple, la formule sera : P(x) = (x>0) & (x-2 <10). Pour solution, on observe bien le fait que l'exécution concrète choisira toujours le même chemin, dûe à la valeur initiale de x : 1, 2, 6.



There's a fine line between wrong and visionary. Unfortunately, you have to be a visionary to see it.; Big Bang Theory, Sheldon