Introduction
Elastic Security Labs analyse divers logiciels malveillants qui passent par nos pipelines de chasse aux menaces et nos files d'attente de télémétrie. Nous avons récemment rencontré une nouvelle famille de logiciels malveillants appelée DOUBLELOADER, que l'on peut voir aux côtés du voleur d'informations RHADAMANTHYS. Une caractéristique intéressante de DOUBLELOADER est qu'il est protégé par un obscurcisseur à source ouverte, ALCATRAZ, publié pour la première fois en 2023. Bien que ce projet trouve son origine dans la communauté des pirates informatiques, il a également été observé dans le domaine de la cybercriminalité et a été utilisé dans le cadre d'intrusions ciblées.
L'objectif de ce billet est d'examiner les différentes techniques d'obscurcissement employées par ALCATRAZ, tout en soulignant les méthodes pour combattre ces techniques en tant qu'analystes de logiciels malveillants. Ces techniques comprennent l'aplatissement du flux de contrôle, la mutation des instructions, le déploiement des constantes, la dissimulation des constantes LEA, les astuces anti-désassemblage et l'obscurcissement des points d'entrée.
Principaux points abordés dans cet article
- L'obfuscateur à code source ouvert ALCATRAZ a été vu dans de nouveaux logiciels malveillants déployés en même temps que les infections RHADAMANTHYS.
- Les techniques d'obscurcissement telles que l'aplatissement du flux de contrôle continuent de servir de barrage aux analystes.
- En comprenant les techniques d'obscurcissement et en sachant comment les contrer, les organisations peuvent améliorer leur capacité à trier et à analyser efficacement les binaires protégés.
- Elastic Security Labs publie un outil pour désobfusquer les binaires protégés d'ALCATRAZ sont publiés avec ce post
DOUBLE CHARGEUR
En décembre dernier, notre équipe a observé un malware générique de type backdoor associé à des infections de type RHADAMANTHYS stealer. D'après le chemin PDB, ce logiciel malveillant se décrit lui-même comme DOUBLELOADER.
Ce logiciel malveillant exploite des appels de système tels que NtOpenProcess
, NtWriteVirtualMemory
, NtCreateThreadEx
pour lancer du code non sauvegardé dans le gestionnaire de bureau/fichier de Windows (explorer.exe
). Le logiciel malveillant recueille des informations sur l'hôte, demande une version mise à jour de lui-même et commence à envoyer des balises à une IP codée en dur (185.147.125.81
) stockée dans le binaire.
Les échantillons de DOUBLELOADER comprennent une section non standard (.0Dev
) avec des autorisations d'exécution, il s'agit d'une marque d'outil laissée sur la base de la poignée de l'auteur pour l'outil d'obscurcissement binaire, ALCATRAZ
.
Les obscurcisseurs tels qu'ALCATRAZ finissent par accroître la complexité du triage des logiciels malveillants. Son principal objectif est d'entraver les outils d'analyse binaire et d'augmenter la durée du processus de rétro-ingénierie par le biais de différentes techniques, telles que la dissimulation du flux de contrôle ou la difficulté à suivre la décompilation. Vous trouverez ci-dessous un exemple de flux de contrôle obscurci d'une fonction à l'intérieur de DOUBLELOADER.
Le reste de ce billet se concentre sur les différentes techniques d'obscurcissement utilisées par ALCATRAZ. Nous utiliserons la première étape de DOUBLELOADER ainsi que des exemples de code de base pour mettre en évidence les caractéristiques d'ALCATRAZ.
ALCATRAZ
ALCATRAZ Aperçu
Alcatraz est un obfuscateur open-source publié initialement en janvier 2023. Si le projet est reconnu par la communauté des pirates informatiques comme un outil fondamental pour l'apprentissage des techniques d'obscurcissement, il a également été constaté que des groupes de cybercriminalité et d' APT en abusaient.
La base de code d'Alcatraz contient 5 fonctions principales centrées sur les techniques standard d'obscurcissement du code ainsi que sur l'amélioration de l'obscurcissement du point d'entrée. Son flux de travail suit un format standard bin2bin
, ce qui signifie que l'utilisateur fournit un binaire compilé et qu'après les transformations, il recevra un nouveau binaire compilé. Cette approche est particulièrement attrayante pour les pirates et les développeurs de logiciels malveillants en raison de sa facilité d'utilisation, qui ne nécessite qu'un effort minimal et aucune modification au niveau du code source.
Le développeur peut choisir d'obscurcir toutes les fonctions ou certaines d'entre elles, ainsi que de choisir les techniques d'obscurcissement à appliquer à chaque fonction. Après la compilation, le fichier est généré avec la chaîne (obf
) ajoutée à la fin du nom de fichier.
Techniques d'obscurcissement dans ALCATRAZ
Les sections suivantes présentent les différentes techniques d'obscurcissement mises en œuvre par ALCATRAZ.
Obfuscation des points d'entrée
Faire face à un point d'entrée obscurci, c'est comme avoir un pneu crevé au début d'un voyage en famille. L'idée est centrée sur la confusion des analystes et des outils binaires où il n'est pas directement clair où le programme commence, ce qui entraîne une confusion au tout début du processus d'analyse.
Voici la vue d'un point d'entrée propre (0x140001368
) d'un programme non obscurci dans IDA Pro.
En activant l'obscurcissement du point d'entrée, ALCATRAZ déplace le point d'entrée puis inclut un code supplémentaire avec un algorithme pour calculer le nouveau point d'entrée du programme. Vous trouverez ci-dessous un extrait de la vue décompilée du point d'entrée obscurci.
Comme ALCATRAZ est un obfuscateur open-source, nous pouvons trouver le code du point d'entrée personnalisé pour voir comment le calcul est effectué ou inverser notre propre exemple obfusqué. Dans notre décompilation, nous pouvons voir que l'algorithme utilise quelques champs de l'en-tête PE tels que Size of the Stack Commit
, Time Date Stamp
ainsi que les quatre premiers octets de la section .0dev
. Ces champs sont analysés puis utilisés avec des opérations par bit telles que la rotation vers la droite (ROR) et le OU exclusif (XOR) pour calculer le point d'entrée.
Vous trouverez ci-dessous un exemple de sortie du script Python IDA (annexe A) qui analyse l'EP et trouve le véritable point d'entrée, confirmant le point de départ original (0x140001368
) avec l'échantillon non obscurci.
Anti-démontage
Les développeurs de logiciels malveillants et les obscurcisseurs utilisent des astuces anti-désassemblage pour confondre ou casser les désassembleurs afin de rendre l'analyse statique plus difficile. Ces techniques abusent des faiblesses lors des balayages linéaires et du désassemblage récursif, empêchant ainsi la reconstruction d'un code propre où l'analyste est alors contraint de corriger manuellement ou automatiquement les instructions sous-jacentes.
ALCATRAZ met en œuvre une forme de cette technique en modifiant toutes les instructions commençant par l'octet 0xFF
en ajoutant une courte instruction de saut ( 0xEB
) devant. L'octet 0xFF
peut représenter le début de plusieurs instructions valides concernant les appels, les sauts indirects, les poussées sur la pile. En ajoutant le saut court 0xEB
devant, on passe effectivement à l'octet suivant 0xFF
. Même s'il n'est pas complexe, le mal est fait, cassant le démontage et nécessitant une intervention.
Pour corriger cette technique spécifique, le fichier peut être corrigé en remplaçant chaque occurrence de l'octet 0xEB
par des NOP. Après avoir été corrigé, le code est remis dans un état plus propre, ce qui permet de désassembler correctement l'instruction call
suivante.
Mutation d'instruction
Une technique courante utilisée par les obscurcisseurs est la mutation d'instructions, où les instructions sont transformées d'une manière qui préserve leur comportement d'origine, mais rend le code plus difficile à comprendre. Des cadres tels que Tigress ou Perses sont d'excellents exemples de recherche sur l'obscurcissement autour de la mutation des instructions.
Vous trouverez ci-dessous un exemple de cette technique mise en œuvre par ALCATRAZ, où toute addition entre deux registres est modifiée, mais où son équivalence sémantique reste intacte. La simple instruction add
est transformée en 5 instructions différentes (push
, not
, sub
, pop
, sub
).
Pour y remédier, nous pouvons utiliser le filtrage pour trouver ces instructions 5 ensemble, désassembler les octets pour trouver quels registres sont impliqués, puis utiliser un assembleur tel que Keystone pour générer les octets correspondants corrects.
Un déploiement constant
Cette technique d'obscurcissement est répandue dans l'échantillon DOUBLELOADER et est une méthode largement utilisée dans diverses formes de logiciels malveillants. Le concept est ici axé sur l'inversion du processus de compilation ; au lieu d'optimiser les calculs connus au moment de la compilation, l'obscurcisseur "déplie" ces constantes, ce qui rend le désassemblage et la décompilation complexes et déroutants. Vous trouverez ci-dessous un exemple simple de cette technique où la constante connue (46
) est décomposée en deux opérations mathématiques.
Dans DOUBLELOADER, cette technique est utilisée à tout moment lorsque des valeurs immédiates sont déplacées dans un registre. Ces valeurs immédiates sont remplacées par de multiples opérations par bit masquant ces valeurs constantes, ce qui perturbe tout contexte et le flux de l'analyste. Par exemple, dans le désassemblage ci-dessous, du côté gauche, il y a une instruction de comparaison de la valeur EAX à l'adresse (0x18016CD93
). En examinant les instructions précédentes, il n'est pas évident ou clair de savoir quelle devrait être la valeur de l'EAX en raison de multiples calculs obscurs par bit. Si nous déboguons le programme, nous pouvons voir que la valeur EAX est fixée à 0
.
Afin de nettoyer cette technique d'obscurcissement, nous pouvons confirmer son comportement avec notre propre exemple où nous pouvons utiliser le code source suivant et voir comment la transformation est appliquée.
#include <iostream>
int add(int a, int b)
{
return a + b;
}
int main()
{
int c;
c = add(1, 2);
printf("Meow %d",c);
return 0;
}
Après la compilation, nous pouvons voir le désassemblage de la fonction main
dans la version propre à gauche et voir ces deux constantes (2,1
) déplacées dans les registres EDX et ECX. À droite, la version transformée, les deux constantes sont cachées parmi les instructions nouvellement ajoutées.
En utilisant des techniques de filtrage, nous pouvons rechercher ces séquences d'instructions, émuler les instructions pour effectuer les différents calculs afin de récupérer les valeurs d'origine, puis patcher les octets restants avec des NOP pour s'assurer que le programme s'exécutera toujours.
Obfuscation de la LEA
À l'instar de la technique décrite précédemment, l'obscurcissement LEA (Load Effective Address) vise à masquer les valeurs immédiates associées aux instructions LEA. Un calcul arithmétique avec soustraction suivra directement l'instruction LEA pour calculer la valeur originale prévue. Bien que cette modification puisse sembler mineure, elle peut avoir un impact significatif sur la rupture des références croisées aux chaînes de caractères et aux données, qui sont essentielles pour une analyse binaire efficace.
Vous trouverez ci-dessous un exemple de cette technique dans DOUBLELOADER où la valeur du registre RAX est déguisée par un modèle de chargement d'une valeur initiale (0x1F4DFCF4F
), puis de soustraction (0x74D983C7
) pour obtenir une nouvelle valeur calculée (0x180064B88
).
Si nous nous rendons à cette adresse dans notre échantillon, nous accédons à la section des données en lecture seule, où nous pouvons trouver la chaîne de caractères référencée bad array new length
.
Afin de corriger cette technique, nous pouvons utiliser la recherche de motifs pour trouver ces instructions spécifiques, effectuer le calcul, puis reconstruire une nouvelle instruction LEA. En mode 64 bits, LEA utilise l'adressage relatif RIP, de sorte que l'adresse est calculée sur la base du pointeur d'instruction actuel (RIP). En fin de compte, nous obtenons une nouvelle instruction qui ressemble à ceci : lea rax, [rip - 0xFF827]
.
Vous trouverez ci-dessous les étapes à suivre pour produire cette instruction finale :
Avec ces informations, nous pouvons utiliser IDA Python pour corriger tous ces schémas. Vous trouverez ci-dessous un exemple d'instruction LEA fixe.
Obfuscation du flux de contrôle
L'aplatissement du flux de contrôle est une technique d'obscurcissement puissante qui perturbe la structure traditionnelle du flux de contrôle d'un programme en éliminant les constructions conventionnelles telles que les branches et les boucles conditionnelles. Au lieu de cela, il restructure l'exécution à l'aide d'un répartiteur centralisé, qui détermine le prochain bloc de base à exécuter sur la base d'une variable d'état, ce qui rend l'analyse et la décompilation nettement plus difficiles. Vous trouverez ci-dessous un diagramme simple qui illustre les différences entre un flux de contrôle non aplati et un flux de contrôle aplati.
Notre équipe a observé cette technique dans divers logiciels malveillants tels que DOORME et il n'est pas surprenant, dans ce cas, que l'aplatissement du flux de contrôle soit l'une des principales caractéristiques de l'obfuscateur ALCATRAZ. Afin d'aborder l'aplatissement, nous nous sommes concentrés sur l'outillage établi en utilisant le plugin IDA D810 écrit par le chercheur en sécurité Boris Batteux.
Nous reprendrons notre programme d'exemple précédent en utilisant la fonction courante _security_init_cookie
utilisée pour détecter les débordements de mémoire tampon. Vous trouverez ci-dessous le diagramme de flux de contrôle de la fonction d'initialisation du cookie sous une forme non obscurcie. Sur la base du graphique, nous pouvons voir qu'il y a six blocs de base, deux branches conditionnelles, et nous pouvons facilement suivre le flux d'exécution.
Si nous prenons la même fonction et appliquons la fonction d'aplatissement du flux de contrôle d'ALCATRAZ, le flux de contrôle du programme semble très différent avec 22 blocs de base, 8 branches conditionnelles, et un nouveau distributeur. Dans la figure ci-dessous, les blocs remplis de couleur représentent les blocs de base précédents de la version non obscurcie, les blocs restants en blanc représentent le code obscurcisseur ajouté utilisé pour distribuer et contrôler l'exécution.
Si nous examinons la décompilation, nous pouvons voir que la fonction est maintenant divisée en différentes parties à l'intérieur d'une boucle while
où une nouvelle variable state
est utilisée pour guider le programme ainsi que des restes de l'obscurcissement, y compris des instructions popf/pushf
.
Pour nettoyer cette fonction, le D810 applique deux règles différentes (UnflattenerFakeJump
, FixPredecessorOfConditionalJumpBlock
) qui transforment le microcode afin d'améliorer la décompilation.
2025-04-03 15:44:50,182 - D810 - INFO - Starting decompilation of function at 0x140025098
2025-04-03 15:44:50,334 - D810 - INFO - glbopt finished for function at 0x140025098
2025-04-03 15:44:50,334 - D810 - INFO - BlkRule 'UnflattenerFakeJump' has been used 1 times for a total of 3 patches
2025-04-03 15:44:50,334 - D810 - INFO - BlkRule 'FixPredecessorOfConditionalJumpBlock' has been used 1 times for a total of 2 patches
Lorsque nous actualisons le décompilateur, l'aplatissement du flux de contrôle est supprimé et le pseudocode est nettoyé.
Bien qu'il s'agisse d'un bon exemple, la correction de l'obscurcissement du flux de contrôle peut souvent être un processus manuel et opportun qui dépend de la fonction. Dans la section suivante, nous rassemblerons certaines des techniques que nous avons apprises et les appliquerons à DOUBLELOADER.
Nettoyage d'une fonction du chargeur double
L'un des défis de l'obscurcissement dans les logiciels malveillants n'est pas tant les techniques d'obscurcissement individuelles que la superposition de ces techniques. En outre, dans le cas de DOUBLELOADER, de grandes parties du code sont placées dans des morceaux de fonction aux limites ambiguës, ce qui rend l'analyse difficile. Dans cette section, nous examinerons un exemple pratique montrant le processus de nettoyage d'une fonction DOUBLELOADER protégée par ALCATRAZ.
Lors du lancement de l'exportation Start
, l'un des premiers appels est adressé à loc_18016C6D9
. Ceci semble être une entrée dans une fonction plus large, mais IDA n'est pas en mesure de créer une fonction en raison d'instructions non définies sur 0x18016C8C1
.
Si nous nous rendons à cette adresse, nous pouvons voir que la première perturbation est due à la technique d'anti-désassemblage par saut court que nous avons vue plus tôt dans le billet de blog (EB FF
).
Après avoir corrigé 6 des occurrences voisines de cette même technique, nous pouvons revenir à l'adresse de départ (0x18016C6D9
) et utiliser la fonction MakeFunction. Bien que la fonction soit décompilée, elle est encore fortement obscurcie, ce qui n'est pas idéal pour une analyse.
En revenant au désassemblage, nous pouvons voir la technique d'obscurcissement LEA utilisée dans cette fonction ci-dessous où la constante de chaîne ”Error”
est maintenant récupérée en utilisant la solution précédente.
Un autre exemple ci-dessous montre la transformation d'un paramètre obscurci pour un appel LoadIcon
où le paramètre lpIconName
est nettoyé en 0x7f00
(IDI_APPLICATION
).
Maintenant que la décompilation s'est améliorée, nous pouvons finaliser le nettoyage en supprimant l'obscurcissement du flux de contrôle avec le plugin D810. Vous trouverez ci-dessous une démonstration montrant les effets avant et après.
Cette section a couvert un scénario réel de nettoyage d'une fonction obfusquée malveillante protégée par ALCATRAZ. Bien que les rapports d'analyse des logiciels malveillants indiquent souvent les résultats finaux, une bonne partie du temps est souvent consacrée en amont à la suppression de l'obscurcissement et à la correction du binaire afin qu'il puisse être correctement analysé.
Scripts Python IDA
Notre équipe publie une série de scripts IDA Python de démonstration de faisabilité utilisés pour gérer les techniques d'obscurcissement par défaut imposées par l'obscurcisseur ALCATRAZ. Ils sont destinés à servir d'exemples de base pour l'utilisation de ces techniques et doivent être utilisés à des fins de recherche. Malheureusement, il n'existe pas de solution miracle en matière d'obscurcissement, mais le fait de disposer d'exemples et de stratégies générales peut s'avérer précieux pour relever des défis similaires à l'avenir.
YARA
Elastic Security a créé des règles YARA pour identifier cette activité.
Observations
Les observables suivants ont été examinés dans le cadre de cette recherche.
Observable | Type | Nom | Référence |
---|---|---|---|
3050c464360ba7004d60f3ea7ebdf85d9a778d931fbf1041fa5867b930e1f7fd | SHA256 | DoubleLo.dll | DOUBLE CHARGEUR |
Références
Les éléments suivants ont été référencés tout au long de la recherche ci-dessus :