/
Ransomware Containment

Démystifier les techniques de ransomware en utilisant les assemblages .Net : Assemblages EXE ou DLL

Dans la première partie de cette série, nous avons examiné certaines techniques utilisées par les logiciels malveillants, en particulier les rançongiciels. Comme nous l'avons vu, ces techniques individuelles telles que les téléchargeurs, les droppers et les loaders ainsi que l'encodage et le cryptage sont toutes des capacités légitimes et programmables offertes par le cadre logiciel .Net (point net) et de nombreux autres cadres de programmation et langages de code. Vous trouverez ci-dessous un collage de certaines des techniques abordées dans l'article précédent.

Dans ce deuxième article, nous allons examiner les principes fondamentaux des assemblages dans le cadre de Microsoft .Net. Nous approfondirons les différences entre les assemblages (EXE vs. DLL) et leurs relations qui permettent d'exécuter ces capacités à partir d'un code initial de haut niveau comme le code de programmation C#. Nous utiliserons le code introduit dans l'article précédent pour explorer ces différences et ces relations.‍

Qu'est-ce que Microsoft .Net ?

Microsoft .Net est un cadre de développement logiciel conçu pour prendre en charge plusieurs langages de programmation et cibler différents systèmes d'exploitation. Les langages de programmation pris en charge tels que C# (prononcé C sharp) sont compilés et exécutés en tant que code géré (par opposition au code non géré ou natif). Pour ce faire, .Net exécute son code dans une machine virtuelle dédiée plutôt que directement sur la plate-forme cible. Cette machine virtuelle est connue sous le nom de Common Language Runtime (CLR) . Il peut être considéré comme l'intermédiaire commun qui exécute finalement le code compilé ou assemblé de tous les différents langages de programmation, tels que C#, VB.Net et F#, pris en charge par .Net. L'exemple ci-dessous reprend le code du langage de programmation C# de l'article précédent.

Le code géré signifie que le code de haut niveau du langage de programmation C# ci-dessus et d'autres langages comme F# et VB.Net sont d'abord compilés dans un langage intermédiaire (IL). Le code de haut niveau C# illustré ci-dessus se compile en instructions de langage intermédiaire, comme le montre l'image ci-dessous. Ce code ressemble à la syntaxe de la programmation assembleur de bas niveau.

Ce langage intermédiaire (IL) est ensuite compilé en code natif ou en code machine ciblant la plate-forme de la machine concernée. Cette compilation est effectuée par un autre composant .Net appelé compilateur Just-in-Time (JIT).

Le code natif ou code machine est l'ensemble des instructions (zéros et uns) que le processeur d'un ordinateur particulier (CPU) comprend. Cette dernière étape est gérée par le Common Language Runtime (CLR) qui contient également le JIT. Le CLR est l'environnement d'exécution ou la machine virtuelle de .Net. Java est un autre cadre logiciel qui utilise le concept de temps d'exécution intermédiaires. À l'instar de la machine virtuelle Java, il s'agit d'un élément essentiel de l'indépendance de la plate-forme .Net. Le code .Net  est appelé code géré parce que le code de programmation est géré par le CLR intermédiaire et n'est pas exécuté directement par l'unité centrale de l'ordinateur.

Un avantage du code géré dans .Net est la gestion automatique de la mémoire et du ramassage des ordures. Cela signifie que le développeur ne doit pas se préoccuper d'allouer et de désallouer la mémoire informatique dans son code pour économiser les ressources du système, comme c'est le cas pour un code C ou C++. Dans .Net, il y a le ramasse-miettes qui s'exécute périodiquement pour gérer la mémoire allouée. Il peut également être appelé par le programmeur en cas de besoin. Le schéma ci-dessous présente l'architecture d'une application .Net.

En revanche, les compilateurs non.Net tels que VB6, C et C++ compilent leur code de haut niveau directement dans le code machine de la plate-forme cible (système d'exploitation et processeur). L'exécutable ou l'assemblage de code qui en résulte est donc lié à la plate-forme de la machine cible du compilateur. On parle également de code non géré ou de code natif. Bien que l'architecture soit différente, il est possible d'utiliser du code provenant d'assemblages, en particulier des DLL développées en code natif, dans une application gérée par .Netau moyen d'une capacité connue sous le nom d'Interop Marshalling (Platform Invoke). Il s'agit par exemple de l'utilisation de DLL natives du système d'exploitation Windows ou de bibliothèques externes telles que du code écrit en C++ référencé dans une application .Net gérée pour permettre certaines fonctionnalités de bas niveau du système d'exploitation. Dans ce cas, .Net lui-même peut être considéré comme une enveloppe sûre autour des DLL natives sur lesquelles le système d'exploitation Windows s'appuie et dont une grande partie est écrite en C++.‍

Qu'est-ce qu'un assemblage .Net ?

Microsoft décrit les assemblages .Net comme une unité de déploiement unique. Cela signifie qu'un assemblage est une collection de divers types de code et de fichiers associés qui ont été compilés (assemblés) sous une forme qui peut être exécutée sur n'importe quelle plate-forme cible .Net compatible. L'exécution est réalisée par le moteur d'exécution du langage commun .Net. Dans le système d'exploitation Windows, les fichiers exécutables (.exe) et les fichiers de bibliothèques de classes ou de liens dynamiques (.dll) sont des exemples d'assemblages.  

En approfondissant l'exemple de code, l'image ci-dessous montre l'assemblage exécutable C# à gauche et un autre code d'assemblage DLL C# (également connu sous le nom de bibliothèque de classe) à droite. Le code exécutable fait référence au fichier DLL et appelle ensuite une méthode (fonction) spécifique du code DLL pendant l'exécution. Ces références et appels ont été mis en évidence dans l'image ci-dessous. Nous expliquerons les détails de ces deux éléments de code plus loin dans cet article. Nous montrerons également dans cette série comment cette combinaison peut être utilisée à des fins malveillantes.

Dans l'exemple suivant, le fichier DLL est référencé manuellement dans le code exécutable. Cela signifie que la DLL et les informations relatives à ses métadonnées ainsi que le code (composé de modules, de classes et de méthodes) sont référencés lors de la compilation du code exécutable.

En tant que bibliothèque partagée, le code DLL ne peut pas être exécuté directement. Du point de vue du code, cela est dû au fait que les DLL n'ont pas de fonction de point d'entrée principal à partir de laquelle s'exécuter et ne peuvent donc pas être exécutées en tant que code autonome comme le ferait un code exécutable (.exe). À titre d'exemple, le message d'erreur ci-dessous montre les conséquences d'une tentative d'exécution d'une bibliothèque de classes ou d'un fichier DLL directement à partir d'un compilateur.

Le code exécutable, quant à lui, aura une fonction ou une méthode de point d'entrée principal où l'exécution commence, mais une DLL n'a pas vraiment besoin d'une fonction de point d'entrée principal puisqu'il s'agit principalement d'une bibliothèque de blocs de code référencés par d'autres assemblages.

Une fois référencé, le code spécifique du fichier DLL qui vous intéresse peut être appelé pour être exécuté. Comme indiqué dans l'article précédent, les exemples de code (EXE et DLL) ci-dessous réitèrent ce point.  

L'application exécutable s'exécute et appelle le code de la DLL qu'elle a référencée pour produire le résultat illustré dans l'image suivante.

Ce programme simple montre comment les assemblages .Net tels que les EXE et les DLL peuvent être utilisés ensemble.

Le code DLL mentionné ci-dessus comporte une méthode (fonction) qui prend deux paramètres par entrée - un prénom et un âge - et affiche ensuite un message d'accueil à l'aide de ces informations. Le code exécutable, quant à lui, exécute un code qui accepte les données d'entrée de l'utilisateur, à savoir le prénom et l'âge, à partir de la ligne de commande, puis transmet ces informations à la méthode DLL en tant qu'arguments ou entrées. Le message du code DLL est ensuite affiché sur l'écran de la console à l'aide des informations que l'application EXE a recueillies auprès de l'utilisateur.

Analyse des assemblages .Net

‍L'analyse statique de l'exécutable montre les différentes références des DLL et autres composants importés pour l'exécution. Outre notre propre DLL personnalisée, l'assemblage exécutable importe également d'autres DLL associées à .Net, telles que mscorlib, une DLL qui contient le code de base (classes, types, etc.) et dont notre programme a besoin pour fonctionner correctement.

Dans notre environnement de développement de code Visual Studio, nous pouvons confirmer l'utilisation de mscorlib  en retrouvant ses origines dans l'un des types de données (dans ce cas, string de System.String dans .Net). Cela révèle l'assemblage .Net intégré d'où provient ce type, à savoir mscorlib, comme le montre l'illustration ci-dessous.

La chaîne est un type de données en termes de programmation où le texte saisi par l'utilisateur et affiché en retour est stocké. Nous pouvons également voir dans notre analyse statique la DLL nommée "DLL_dontNet_Assembly". Il s'agit de notre DLL personnalisée qui contient la méthode "DisplayMsgMethod" qui affiche un message à l'utilisateur après qu'il a saisi ses coordonnées.

Dans notre exemple, nous avons référencé et chargé notre DLL personnalisée manuellement pendant la compilation de tout notre code avant que le programme ne commence à s'exécuter. Il est également possible de référencer une DLL pendant l'exécution d'un exécutable. Cela peut s'avérer particulièrement utile dans les cas où nous n'avons pas accès à la DLL souhaitée lors de la compilation de notre code. Ce processus est connu sous le nom de réflexion et permet d'examiner un assemblage .Net (métadonnées et attributs) et d'utiliser le code (modules, classes, méthodes et propriétés) qu'il contient pendant l'exécution de notre programme. Cette technique peut également être détournée à des fins malveillantes dans ce que l'on appelle les attaques par injection de DLL réfléchies.‍

Les assemblages .Net (exécutables et bibliothèques de classes) se composent également d'un fichier manifeste qui contient des métadonnées sur l'assemblage et le code du langage intermédiaire (IL) qui, ensemble, permettent au moteur d'exécution du langage commun d'exécuter l'assemblage sur n'importe quelle plate-forme compatible avec .Net. L'image ci-dessous montre les instructions d'assemblage IL et la structure du manifeste des deux assemblages - EXE et DLL. Le fichier manifeste contient les métadonnées relatives à l'assemblage .Net, telles que le numéro de version, la description, etc.

Nous devrions maintenant avoir une compréhension fondamentale du cadre logiciel .Net, de ses assemblages associés et de la manière dont ils peuvent interagir les uns avec les autres.

Dans le prochain article, nous regrouperons les techniques et les capacités dont nous avons discuté et que nous avons apprises jusqu'à présent dans un seul exécutable de ransomware malveillant.

Apprenez-en plus sur la façon dont la segmentation zéro confiance d'Illumio peut vous aider à contenir les brèches de ransomware.

Sujets connexes

No items found.

Articles connexes

Étude sur le coût mondial des ransomwares : Ce que les chiffres nous apprennent
Ransomware Containment

Étude sur le coût mondial des ransomwares : Ce que les chiffres nous apprennent

Découvrez comment les attaquants s'orientent vers la perturbation des opérations, pourquoi la prévention ne suffit pas et comment la confiance zéro et la microsegmentation limitent l'impact des ransomwares.

Pourquoi les pare-feu ne suffisent pas à contenir les ransomwares
Ransomware Containment

Pourquoi les pare-feu ne suffisent pas à contenir les ransomwares

Découvrez les raisons pour lesquelles les pare-feu sont trop lents pour faire face aux menaces et pourquoi la microsegmentation est essentielle pour contenir les ransomwares.

Comment stopper les attaques du ransomware Clop avec Illumio
Ransomware Containment

Comment stopper les attaques du ransomware Clop avec Illumio

Découvrez comment la variante de ransomware Clop fonctionne et comment Illumio peut aider votre organisation à contenir l'attaque grâce à la microsegmentation.

Démystifier les techniques de ransomware à l'aide d'assemblages .Net : 5 techniques principales
Ransomware Containment

Démystifier les techniques de ransomware à l'aide d'assemblages .Net : 5 techniques principales

Découvrez 5 techniques de ransomware utilisant le cadre logiciel .Net.

Comment contenir les attaques du ransomware LockBit avec Illumio
Ransomware Containment

Comment contenir les attaques du ransomware LockBit avec Illumio

Découvrez comment le ransomware LockBit fonctionne et comment la segmentation Illumio Zero Trust a permis de contenir une attaque de ransomware LockBit à l'été 2022.

Supposons une rupture.
Minimiser l'impact.
Augmenter la résilience.

Vous souhaitez en savoir plus sur la segmentation zéro confiance ?