Avez-vous déjà ressenti le désir de démonter un mécanisme pour savoir comment il fonctionne ? Eh bien, qui ne l’a pas fait. Ce désir est la force motrice de l’ingénierie inverse. Cette compétence est utile pour analyser la sécurité d’un produit, découvrir l’objectif d’un fichier .exe suspect sans l’exécuter, récupérer une documentation perdue, développer une nouvelle solution basée sur un logiciel hérité, etc.

Dans cet article, nous abordons la base de connaissances nécessaire pour effectuer de la rétro-ingénierie, les principes de base de la rétro-ingénierie d’un logiciel Windows, les désassembleurs et les outils. Nous fournissons également un exemple de reverse engineering d’une application, étape par étape.

Écrit par

Sergii Bratus,

Coordinateur de développement,

Équipe de sécurité des réseaux

et

Anton Kukoba,

Responsable de la recherche en sécurité

Contenu

Qu’est-ce que l’inversion de logiciel ?

De quoi avons-nous besoin pour l’ingénierie inverse ?

Connaissances théoriques. Processus de rétroingénierie logicielle

Outils utiles pour la rétroingénierie des logiciels Windows

Désassembleurs

Windows Sysinternals

Outils de surveillance du réseau

Débogueurs

Exemple réel de rétroingénierie logicielle.life software reverse engineering example

How to reverse engineering a driver

Conclusion

Qu’est-ce que le software reversing ?

L’ingénierie inverse est le processus de découverte des principes qui se cachent derrière une pièce de matériel ou de logiciel, comme son architecture et sa structure interne. La question qui anime l’ingénierie inverse est la suivante : Comment cela fonctionne-t-il ?

Evidemment, si vous avez de la documentation, tout le processus devient beaucoup plus simple. Mais il arrive souvent qu’il n’y ait pas de documentation et que vous deviez trouver un autre moyen d’apprendre comment fonctionne un logiciel.

Quand pourriez-vous avoir besoin de faire de l’ingénierie inverse sur un logiciel et comment cela pourrait-il vous aider ?

Il existe de nombreuses utilisations de l’ingénierie inverse dans le domaine de l’informatique, notamment :

  • Recherche de protocoles de communication réseau
  • Détection des algorithmes utilisés dans les logiciels malveillants tels que les virus informatiques, les chevaux de Troie, les rançongiciels, etc.
  • Recherche du format de fichier utilisé pour stocker tout type d’information, par exemple les bases de données de courriels et les images de disque
  • Vérification de la capacité de votre propre logiciel à résister à l’ingénierie inverse
  • Amélioration de la compatibilité du logiciel avec les plateformes et les logiciels tiers
  • Utilisation de fonctionnalités de plateforme non documentées

La légalité de l’ingénierie inverse dépend de son objectif et de la façon dont le logiciel sera utilisé. Tous les buts mentionnés ci-dessus sont tout à fait légitimes, en supposant que vous ayez obtenu une copie du logiciel légalement. Mais si vous avez l’intention, par exemple, de faire de l’ingénierie inverse sur une certaine fonctionnalité d’une application fermée pour ensuite l’implémenter dans une autre application, vous aurez probablement des problèmes.

En ce qui concerne la documentation légale, l’ingénierie inverse est souvent interdite par les contrats de licence de l’utilisateur final (EULA). Mais le US Digital Millennium Copyright Act précise que l’inversion d’un logiciel est légale si elle » est faite pour améliorer la compatibilité avec d’autres produits.

Les exigences légales varient d’un pays à l’autre, alors prenez votre temps pour les rechercher avant de commencer.

Voyons maintenant comment faire de l’ingénierie inverse sur un logiciel.

De quoi avons-nous besoin pour faire de la rétroingénierie ?

Pour commencer à faire de la rétroingénierie de logiciels, vous avez besoin :

  1. de connaissances dans le domaine où vous voulez appliquer la rétroingénierie
  2. d’outils qui vous permettront d’appliquer vos connaissances tout en essayant de désassembler un logiciel.

Prenons un exemple générique qui n’est pas lié aux logiciels. Disons que vous avez une montre et que vous voulez savoir si elle est mécanique, à quartz ou automatique.

Avoir des connaissances dans ce domaine signifie que vous devriez savoir qu’il existe trois types de montres. De plus, vous devriez savoir que s’il y a une batterie, elle est située à l’intérieur de la montre et que vous pouvez la voir si vous l’ouvrez. Vous devez également avoir une connaissance de base de la structure interne d’une montre, de l’aspect de la pile et des outils nécessaires pour ouvrir un boîtier de montre. Avoir les outils pour appliquer vos connaissances signifie que vous devez avoir un tournevis ou un autre outil dédié qui vous donnera la possibilité d’ouvrir la montre.

De même que la rétroconception d’une montre nécessite un ensemble de compétences et d’outils spécifiques, la rétroconception de logiciels nécessite ses propres connaissances et outils spécifiques au domaine.

Connaissances théoriques. Processus de rétroingénierie logicielle

Pour différentes tâches de rétroingénierie logicielle, vous avez besoin de différents types de connaissances. Bien sûr, il y a des connaissances communes qui vous aideront dans la plupart des tâches de rétroingénierie : la connaissance des structures d’application courantes, des langages de programmation, des compilateurs, et ainsi de suite. Cependant, sans connaissances théoriques spéciales, vous ne pouvez pas résoudre des tâches spécifiques de rétroingénierie.

Si vous…

Vous devez connaître…

réaliser l’ingénierie inverse de toute application réseau

les principes des communications interprocessus, la structure des réseaux, les connexions, les paquets réseau, etc.

inverser les algorithmes cryptographiques

cryptographie et les algorithmes les plus populaires utilisés dans le domaine

rechercher les fichiers. structures

concepts de base des fichiers et comment différents systèmes ou composants fonctionnent avec des fichiers

Des techniques spéciales peuvent faire gagner beaucoup de temps lors de l’inversion de types particuliers de logiciels. Dans le cas des interactions de fichiers, faire un test qui écrit des valeurs de type unique dans un fichier tout en enregistrant les décalages et la taille des données dans le fichier de stockage réel peut vous aider à trouver des modèles communs dans les décalages. Cela vous donnera un indice sur les structures internes de ces fichiers.

Lorsqu’ils commencent un processus de rétroconception, les développeurs de logiciels utilisent généralement un désassembleur afin de trouver les algorithmes et la logique du programme en place. Il existe un grand nombre de formats de fichiers exécutables, de compilateurs (qui donnent des résultats différents) et de systèmes d’exploitation différents. Cette diversité de technologies empêche l’utilisation d’une seule technologie pour inverser tous les types de logiciels.

Pour comprendre le code décompilé, il faut avoir quelques connaissances du langage assembleur, des conventions d’appel de fonctions, de la structure de la pile, du concept de stack frames, etc.

Connaître la sortie de l’assembleur pour différents échantillons de code peut vous aider à découvrir la fonctionnalité originale. Considérons quelques exemples pour la plateforme Windows x86.

Disons que nous avons le code suivant :

int count = 0;for (int i = 0; i < 10; ++i){count++;}std::cout << count;

Si nous compilons ce code dans un fichier exécutable, nous verrons ceci dans le désassembleur :

004113DE loc_4113DE:004113DE mov eax, 004113E1 add eax, 1004113E4 mov , eax004113E7 loc_4113E7:004113E7 cmp , 0Ah004113EB jge short loc_4113F8004113ED mov eax, 004113F0 add eax, 1004113F3 mov , eax004113F6 jmp short loc_4113DE004113F8 loc_4113F8:004113F8 mov ecx, ds:004113FE push eax00411400 call ds:<<(int)00411404 xor eax, eax00411406 retn 

Comme nous pouvons le voir, le cycle régulier s’est transformé en code assembleur avec des comparaisons et des sauts. Remarquez que le code d’assemblage n’utilise pas la boucle régulière d’assemblage avec le compteur dans le registre ecx. En outre, les variables locales sont ici désignées par et en conséquence.

Voyons ce qui se passera si nous compilons ce code en utilisant le release build:

00401000 main proc near00401000 mov ecx, ds:00401006 push 0Ah00401008 call ds:<<(int)0040100E xor eax, eax00401010 retn00401010 main endp

Ce morceau de code ne ressemble en rien au précédent. Cela est dû à la façon dont le code a été optimisé. Techniquement, la boucle a été supprimée, puisqu’elle ne fait rien de valable à part incrémenter la variable count à 10. Donc, l’optimiseur a décidé de simplement garder la valeur finale de la variable count et de placer cette valeur directement comme argument pour l’opérateur de sortie count.

Les compilateurs que nous utilisons aujourd’hui sont très bons pour optimiser le code. C’est pourquoi lors de la rétro-ingénierie, il est préférable de comprendre l’idée derrière le code (les principes du code) plutôt que d’essayer d’obtenir le code original lui-même. Si vous comprenez l’idée derrière le code, vous pouvez simplement écrire votre propre prototype qui correspond à la tâche originale.

Il sera très utile de savoir quel code d’assemblage vous obtiendrez si vous compilez différents opérateurs, structures et autres constructions de langage. Comprendre le code d’assemblage résultant est une bonne façon de commencer le processus de rétro-ingénierie C++, mais nous n’entrerons pas dans les détails techniques de celui-ci ici.

Outils utiles pour la rétro-ingénierie des logiciels Windows

Nous avons déjà décrit plusieurs outils de rétro-ingénierie, notamment ProcessMonitor et ProcessExplorer, dans notre recherche sur l’architecture des applications. Ces outils sont absolument indispensables pour la rétroingénierie.

Dans cette section, nous passerons en revue les désassembleurs les plus populaires et quelques autres outils que nous utilisons pour nos projets de rétroingénierie.

Vous pouvez obtenir plus de détails et d’exemples d’utilisation dans notre article sur les meilleurs outils de rétroingénierie logicielle.

Désassembleurs

Un désassembleur est un programme qui traduit un fichier exécutable en langage d’assemblage. Le plus populaire est IDA Pro

IDA Pro

IDA Pro

IDA Pro est un outil pratique et puissant pour le désassemblage. Il dispose d’un très grand nombre d’instruments qui vous permettent de désassembler rapidement un logiciel. Il peut montrer l’arbre d’appel des fonctions, analyser l’importation et l’exportation de l’exécutable, et montrer des informations à leur sujet. Il peut même montrer le code en C. De plus, il supporte plusieurs architectures de CPU, il est donc possible d’utiliser IDA Pro pour désassembler du code pour ARM, AVR, M68k, et beaucoup d’autres architectures.

Radare

Radare

Le désassembleur Radare est une alternative à IDA. Il possède essentiellement toutes les fonctionnalités d’IDA sans être aussi robuste et stable. Mais il est gratuit et open source. Radare lui-même est un outil de console, mais il possède un frontal Cutter, ce qui en fait une véritable alternative à IDA.

Windows Sysinternals

Les utilitaires Windows Sysinternals sont généralement utilisés pour la gestion, le diagnostic, le dépannage et la surveillance de l’environnement Microsoft Windows. Mais ils conviennent également à la rétroconception des logiciels Windows.

TCPView est un renifleur de réseau qui affiche toutes les informations sur les paquets TCP/UDP de tous les processus. Cet outil est utile pour inverser les protocoles réseau.

PortMon est un moniteur de port de système physique. Il surveille les ports série et parallèle et tout le trafic qui passe par eux.

WinObj montre tous les objets globaux du système dans une structure hiérarchique. Cet outil peut être utile lors de la rétroconception d’une application qui fonctionne avec des primitives de synchronisation telles que les mutex et les sémaphores et également lors de la rétroconception de pilotes en mode noyau.

Outils de surveillance du réseau

Wireshark

Wireshark

Wireshark est l’un des renifleurs de réseau les plus puissants. Il vous permet non seulement de capturer le trafic réseau mais contient également des analyseurs pour divers protocoles réseau, en commençant par des protocoles de très bas niveau comme Ethernet, TCP et IP jusqu’aux protocoles spécifiques aux applications comme WebSockets et XMPP.

Fiddler

Fiddler

Fiddler est un proxy web qui enregistre le trafic des navigateurs et vous permet d’analyser les requêtes HTTP/HTTPS. Contrairement à Wireshark, il montre les sessions HTTP au lieu des paquets réseau séparés. Fiddler vous permet également d’analyser les données compressées envoyées sur HTTP et d’analyser les données JSON et XML lors de la surveillance des demandes SOAP, REST et AJAX.

API Monitor

API Monitor

API Monitor est un outil utile pour découvrir quelles API sont appelées par une application et quel comportement l’application attend de ces API. Cet outil dispose d’une base de données puissante et vous permet de voir les appels à un très grand nombre de fonctions d’API non seulement de kernel32 et de ntdll mais aussi de COM, d’environnement géré et autres. En outre, API Monitor fournit des mécanismes de filtrage pratiques.

Débogueurs

Un débogueur est inestimable pour tout développeur pour voir ce qu’un programme fait en ce moment. Vous obtenez le même avantage du débogage lors de l’inversion des applications que vous obtenez du débogage des applications en direct.

Les débogueurs les plus populaires sont OllyDbg, WinDbg, et Windbg Preview.

OllyDbg

OllyDBG

OllyDbg (et son successeur x64dbg) est probablement le meilleur débogueur quand il s’agit de rétroingénierie logicielle. Il a été spécifiquement développé pour les besoins de la rétroconception, et possède tous les outils nécessaires à cet effet :

  • un désassembleur intégré avec la capacité d’analyser et d’identifier les structures de données clés
  • une fonction d’analyse d’importation et d’exportation
  • un moteur d’assemblage et de patching intégré

La capacité d’analyser les fonctions API et leurs paramètres facilite la rétroconception des interactions avec un système. La vue de la pile fournit beaucoup d’informations sur la pile d’appels. Un autre avantage important est que vous pouvez utiliser OllyDbg avec des applications protégées contre le débogage, lorsque les débogueurs habituels ne peuvent tout simplement rien faire.

WinDbg

Windbg

Malgré son interface simple, WinDbg possède des outils puissants pour le débogage. Il a un désassembleur intégré, diverses commandes qui vous permettent de savoir presque tout sur le processus/système que vous déboguez, et la possibilité de faire du débogage en mode noyau, qui est probablement la fonctionnalité la plus précieuse. C’est un gros avantage pour inverser les pilotes, les pilotes en mode noyau en particulier.

Windbg Preview

Windbg Preview

Windbg Preview est une nouvelle version de Windbg développée par Microsoft. Elle est distribuée uniquement via le Windows Store. Elle possède toutes les fonctionnalités du Windbg classique couplées à une nouvelle interface utilisateur et plusieurs nouvelles fonctionnalités. L’une de ces nouvelles fonctionnalités est le débogage par voyage dans le temps, qui vous permet d’enregistrer une certaine période d’exécution du programme et de la rejouer autant de fois que nécessaire. De cette façon, vous pouvez exécuter les parties intéressantes du code par étape, sans avoir peur d’exécuter un certain code accidentellement et de perdre le contexte ou toutes les données.

Lisez aussi :
9 Meilleurs outils de rétroingénierie pour 2018

Exemple réel de rétroingénierie logicielle

Nous allons maintenant voir un exemple de rétroingénierie d’un logiciel. Imaginons que vous ayez un fichier exécutable suspect. Vous devez découvrir ce que fait ce programme et s’il est sûr pour les utilisateurs.

Considérant le scénario, c’est une bonne idée de ne pas exécuter cet exécutable sur votre ordinateur de travail mais d’utiliser plutôt une machine virtuelle. Démarrons l’application dans notre machine virtuelle.

Le processus crée un service

Comme nous pouvons le voir, ce fichier crée un service Windows nommé TestDriver. Il a le type kernel, donc nous savons que c’est un pilote. Mais où prend-il le fichier du pilote pour s’exécuter ? Nous pouvons utiliser ProcessMonitor de Sysinternals Suite pour le découvrir. Lorsque nous ouvrons ProcessMonitor, nous pouvons configurer des filtres pour nous montrer uniquement l’activité des fichiers du processus qui nous intéresse. Son journal d’activité ressemble à ceci:

FileMon information

Le fichier du pilote est créé par le processus que nous inversons, et ce processus place ce fichier dans le répertoire temp de l’utilisateur. Il n’y a pas besoin de chercher le fichier dans le répertoire temporaire puisque nous voyons que le processus le supprime juste après son utilisation. Que fait donc le processus avec ce fichier ? S’il décompresse le fichier, nous pouvons essayer de le trouver dans la section des ressources du processus, puisque c’est un endroit habituel pour stocker de telles données. Cherchons là. Nous allons utiliser un autre outil – Resource Hacker – pour examiner les ressources. Exécutons-le:

Examiner les ressources avec Resource Hacker

Bingo ! Comme nous pouvons le voir d’après le contenu des ressources trouvées, il s’agit probablement du fichier exécutable Windows, puisqu’il commence par une signature MZ et possède la chaîne « Ce programme ne peut pas être exécuté en mode DOS. » Vérifions s’il s’agit de notre fichier pilote. Pour cela, nous extrayons la ressource en utilisant Resource Hacker et l’ouvrons dans le désassembleur.

Écran du désassembleur

Comme nous le savons, DriverEntry est le point d’entrée des pilotes en mode noyau dans les systèmes Windows. Nous pouvons continuer nos recherches, car il semble que nous ayons trouvé le bon pilote.

Comment rétroconcevoir un pilote

Pour commencer à rétroconcevoir le pilote, nous examinons les fonctions qui sont appelées depuis DriverEntry une par une. Si nous allons à sub_14005, nous ne trouvons rien d’intéressant, donc nous continuons avec sub_110F0 et trouvons ce code :

Code pièce 1

Code pièce 2

Code pièce 3

Code pièce 4

Certaines lignes sont omises ici pour des raisons de simplicité.

Dans le premier listing, une chaîne unicode est créée, et cette chaîne pointe vers le chemin C:\hello.txt. Après cela, la structure OBJECT_ATTRIBUTES est remplie de valeurs régulières ; nous savons que cette structure est souvent nécessaire lors de l’appel de fonctions comme ZwCreateFile.

Dans le deuxième listing, nous voyons que ZwCreateFile est effectivement appelé, ce qui nous rend à peu près sûrs que le pilote crée le fichier – et nous savons où se trouve ce fichier après sa création.

D’après les troisième et quatrième listings, nous pouvons voir que le pilote prend la chaîne unicode et l’écrit dans le tampon (cela se produit dans la fonction sub_11150), et le tampon sera écrit dans le fichier en utilisant la fonction ZwWriteFile. A la fin, le pilote ferme le fichier en utilisant l’API ZwClose.

Résumons. Nous avons découvert que le programme original extrait le fichier du pilote de ses ressources, le place dans le dossier temp de l’utilisateur actuel, crée le service Windows pour ce pilote et l’exécute. Après cela, le programme s’arrête et supprime le service et le fichier du pilote original du répertoire temporaire. D’après ce comportement et l’analyse du désassemblage, il semble que le pilote ne fasse rien d’autre que de créer un fichier sur le lecteur C nommé hello.txt et d’écrire la chaîne « Hello from driver ».

Maintenant, nous devons vérifier si nous avons raison. Exécutons le programme et vérifions le lecteur C :

Écran d’application

Merveilleux ! Nous avons fait de l’ingénierie inverse sur ce programme simple et maintenant nous savons qu’il peut être utilisé en toute sécurité.

Nous aurions pu obtenir ce résultat de nombreuses façons différentes – en utilisant le débogage ou l’API Mon, en écrivant des tests, etc. Vous pouvez trouver vos propres façons de faire de la rétroingénierie logicielle qui fonctionnent pour vous.

Conclusion

La rétroingénierie de logiciels Windows nécessite une solide formation et une expérience de la programmation. Pour effectuer du reverse engineering, vous devez combiner des compétences en désassemblage, surveillance du réseau, débogage, intégration d’API, plusieurs langages de programme, compilateurs, etc. Vous devez également être très prudent lorsque vous inversez un logiciel afin de ne pas enfreindre les lois sur le droit d’auteur ou endommager votre système.

À Apriorit, nous avons une équipe expérimentée d’ingénieurs inverseurs. Si vous voulez appliquer les compétences en ingénierie inverse à votre projet, n’hésitez pas à nous contacter !

.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.