Overview
Elastic Security Labs überwacht weiterhin aktive Bedrohungen wie GULOADER, auch bekannt als CloudEyE – ein ausweichender Shellcode-Downloader, der seit Jahren sehr aktiv ist und ständig weiterentwickelt wird. Eine dieser jüngsten Änderungen ist das Hinzufügen von Ausnahmen zu seinem Vectored Exception Handler (VEH) in einer neuen Kampagne, die die ohnehin schon lange Liste von Anti-Analyse-Tricks noch komplexer macht.
Während sich die Kernfunktionalität von GULOADER in den letzten Jahren nicht drastisch verändert hat, machen diese ständigen Aktualisierungen ihrer Verschleierungstechniken die Analyse von GULOADER zu einem zeitaufwändigen und ressourcenintensiven Prozess. In diesem Beitrag werden wir die folgenden Themen bei der Sichtung von GULOADER ansprechen:
- Überprüfen des anfänglichen Shellcodes und des Entpackvorgangs
- Den Einstiegspunkt des entschlüsselten Shellcodes finden
- Diskutieren Sie das Update des VEH von GULOADER, das die Ablaufsteuerung verschleiert
- Bereitstellung einer Methodik zum Ausbessern von VEH
Anfänglicher Shellcode
In unserem Beispiel wird GULOADER vorverpackt in einem NSIS-Installationsprogramm (Nullsoft Scriptable Install System) geliefert. Wenn das Installationsprogramm extrahiert wird, sind die Hauptkomponenten:
- NSIS-Skript - In dieser Skriptdatei werden alle verschiedenen Konfigurations- und Installationsaspekte beschrieben.
- System.dll - Befindet sich unter dem
$PLUGINSDir
. Diese Datei wird in einem temporären Ordner abgelegt, um den GULOADER-Shellcode zuzuweisen/auszuführen.
- Shellcode - Der verschlüsselte Shellcode wird in einem verschachtelten Ordner vergraben.
Eine schnelle Methode, um die Datei zu lokalisieren, in der der Shellcode gehostet wird, kann durch Überwachen ReadFile
Ereignisse aus dem Process Monitor von SysInternal nach dem Ausführen von GULOADER durchgeführt werden. In diesem Fall können wir sehen, dass der Shellcode aus einer Datei eingelesen wird (Fibroms.Hag
).
GULOADER führt Shellcode über Callbacks mit verschiedenen Windows-API-Funktionen aus. Der Hauptgrund dafür besteht darin, Erkennungen zu vermeiden, die sich auf herkömmliche Windows-APIs konzentrieren, die für die Prozessinjektion verwendet werden, z. B. CreateRemoteThread
oder WriteProcessMemory
. Wir haben EnumResourceTypesA
und CallWindowProcW
beobachtet, die von GULOADER verwendet werden.
Wenn wir uns die MSDN-Dokumentation für EnumResourceTypesA
ansehen, können wir sehen, dass der zweite Parameter einen Zeiger auf die Rückruffunktion erwartet. Aus dem obigen Screenshot können wir sehen, dass der neu zugewiesene Shellcode in dieses Argument eingefügt wird.
Suchen des Haupt-Shellcode-Einstiegspunkts
In neueren Beispielen hat GULOADER die Komplexität am Anfang des anfänglichen Shellcodes erhöht, indem es viele verschiedene Junk-Befehle und Sprünge einfügt. Das Reverse Engineering des Downloaders kann den Umgang mit einem langwierigen Prozess des Entladens der Code-Verschleierung erfordern, der dazu dient, die Demontage und den Kontrollfluss in einigen Tools zu unterbrechen, was es frustrierend macht, den tatsächlichen Start des Kern-GULOADER-Shellcodes zu finden.
Eine Methode zum Auffinden des ersten Aufrufs kann die Nutzung der Diagrammansicht in x64dbg und die Verwendung eines Bottom-to-Top-Ansatzes sein, um nach der call eax
Anweisung zu suchen.
Eine weitere Technik zur Verfolgung des anfänglichen Kontrollflusses besteht darin, das Reversing-Engineering-Framework Miasmzu nutzen. Unten sehen Sie ein kurzes Beispiel, in dem wir den Shellcode übergeben und die Anweisungen disassemblieren können, um dem Ablauf zu folgen:
from miasm.core.locationdb import LocationDB
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine
with open("proctoring_06BF0000.bin", "rb") as f:
code = f.read()
loc_db = LocationDB()
c = Container.from_string(code, loc_db)
machine = Machine('x86_32')
mdis = machine.dis_engine(c.bin_stream, loc_db=loc_db)
mdis.follow_call = True
mdis.dontdis_retcall = True
asm_cfg = mdis.dis_multiblock(offset=0x1400)
Miasm durchschneidet die 142 jmp
Anweisungen und navigiert durch die Junk-Anweisungen, wo wir es so konfiguriert haben, dass es bei der Anrufanweisung an EAX (Adresse: 0x3bde
) stoppt.
JMP loc_3afd
-> c_to:loc_3afd
loc_3afd
MOV EBX, EAX
FADDP ST(3), ST
PANDN XMM7, XMM2
JMP loc_3b3e
-> c_to:loc_3b3e
loc_3b3e
SHL CL, 0x0
PSRAW MM1, MM0
PSRLD XMM1, 0xF1
JMP loc_3b97
-> c_to:loc_3b97
loc_3b97
CMP DL, 0x3A
PADDW XMM3, XMM5
PXOR MM3, MM3
JMP loc_3bde
-> c_to:loc_3bde
loc_3bde
CALL EAX
Das Ende des Miasmus
GULOADER’s VEH Update
Eine der charakteristischen Techniken von GULOADER dreht sich um die Vectored Exception Handling (VEH)-Funktion. Dieses Feature gibt Windows-Anwendungen die Möglichkeit, Ausnahmen abzufangen und zu behandeln, bevor sie den standardmäßigen Ausnahmeprozess durchlaufen. Malware-Familien und Softwareschutzanwendungen nutzen diese Technik, um es für Analysten und Tools schwierig zu machen, dem bösartigen Code zu folgen.
GULOADER startet diesen Prozess, indem es den VEH mit RtlAddVectoredExceptionHandler
hinzufügt. Während der Ausführung des GULOADER-Shellcodes gibt es Code, der absichtlich platziert wurde, um diese verschiedenen Ausnahmen auszulösen. Wenn diese Ausnahmen ausgelöst werden, sucht der VEH nach Hardware-Breakpoints. Wenn sie nicht gefunden wird, ändert GULOADER den EIP direkt über die CONTEXT-Struktur unter Verwendung eines Ein-Byte-XOR-Schlüssels (Änderungen pro Stichprobe) mit einem Offset-Verhältnis von einem Byte von der Stelle, an der die Ausnahme aufgetreten ist. Ein konkretes Beispiel für diese Technik werden wir im folgenden Abschnitt betrachten. Nachfolgend sehen Sie die Dekompilierung des VEH unseres Beispiels:
Obwohl diese Technik nicht neu ist, fügt GULOADER im Laufe der Zeit immer wieder neue Ausnahmen hinzu. Wir haben kürzlich diese beiden Ausnahmen beobachtet, die in den letzten Monaten hinzugefügt wurden:
EXCEPTION_PRIV_INSTRUCTION
EXCEPTION_ILLEGAL_INSTRUCTION
Wenn neue Ausnahmen zu GULOADER hinzugefügt werden, kann es dazu kommen, dass die Tools, die zur Beschleunigung des Analyseprozesses für Forscher verwendet werden, beschädigt werden.
EXCEPTION_PRIV_INSTRUCTION
Sehen wir uns die beiden kürzlich hinzugefügten Ausnahmen an, um dem VEH-Workflow zu folgen. Die erste Ausnahme (EXCEPTION_PRIV_INSTRUCTION
) tritt auf, wenn versucht wird, eine privilegierte Anweisung im Befehlssatz eines Prozessors auf einer Berechtigungsstufe auszuführen, auf der sie nicht zulässig ist. Bestimmte Anweisungen, wie das untenstehende Beispiel mit WRSMR , erwarten Privilegien von der Kernel-Ebene, so dass das Programm, wenn es aus dem Benutzermodus ausgeführt wird, die Ausnahme aufgrund falscher Berechtigungen auslöst.
EXCEPTION_ILLEGAL_INSTRUCTION
Diese Ausnahme wird aufgerufen, wenn ein Programm versucht, eine ungültige oder nicht definierte CPU-Anweisung auszuführen. Wenn wir in unserem Beispiel auf Intel-Virtualisierungsanweisungen wie vmclear
oder vmxon
stoßen, löst dies eine Ausnahme aus.
Sobald eine Ausnahme auftritt, bestimmt der GULOADER VEH-Code zunächst, welcher Ausnahmecode für die Ausnahme verantwortlich war. Wenn die Ausnahme in unserem Beispiel mit einer der fünf folgenden Ausnahmen übereinstimmt, nimmt der Code unabhängig davon denselben Pfad an.
EXCEPTION_ACCESS_VIOLATION
EXCEPTION_ILLEGAL_INSTRUCTION
EXCEPTION_PRIV_INSTRUCTION
EXCEPTION_SINGLE_STEP
EXCEPTION_BREAKPOINT
GULOADER sucht dann nach Hardware-Breakpoints, indem es den CONTEXT-Datensatz in der EXCEPTION_POINTERS Struktur durchläuft. Wenn Hardware-Breakpoints in den verschiedenen Debug-Registern gefunden werden, gibt GULOADER einen 0
in den CONTEXT-Datensatz zurück, der zum Absturz des Shellcodes führt.
Wenn es keine Hardware-Breakpoints gibt, ruft GULOADER ein einzelnes Byte ab, das 7 Byte von der Adresse entfernt ist, die die Ausnahme verursacht hat. Wenn Sie das letzte Beispiel mit vmclear
verwenden, wird das Byte (0x8A
) abgerufen.
Anschließend wird unter Verwendung dieses Bytes eine XOR-Operation mit einem anderen hartcodierten Byte ausgeführt. In unserem Fall (0xB8
) ist dies pro Stichprobe einzigartig. Mit einem abgeleiteten Offset- 0x32
(0xB8 ^ 0x8A
) ändert GULOADER nun die EIP-Adresse direkt aus dem CONTEXT-Datensatz, indem 0x32
zur vorherigen Adresse (0x7697630
) hinzugefügt wird, die die Ausnahme verursacht hat, was dazu führte, dass der nächste Code von der Adresse (0x7697662
ausgeführt wurde ).
Mit unterschiedlichen Junk-Anweisungen dazwischen und wiederholten Ausnahmen (wir haben 229 eindeutige Ausnahmen in unserer Stichprobe gezählt) ist es nicht schwer zu erkennen, warum dies verschiedene Tools beschädigen und die Zeit für Analysten erhöhen kann.
Reinigung der Ablaufsteuerung
Um das Befolgen der Ablaufsteuerung zu vereinfachen, kann ein Analyst die VEH umgehen, indem er die Ausführung nachverfolgt, die Ausnahmen protokolliert und den Shellcode mit dem zuvor beschriebenen EIP-Änderungsalgorithmus patcht. Für dieses Verfahren haben wir TinyTracer genutzt, ein von @hasherezade geschriebenes Tool, das Pin, ein dynamisches binäres Instrumentierungsframework, nutzt. Auf diese Weise können wir die verschiedenen Adressen abfangen, die die Ausnahme ausgelöst haben, so dass wir anhand des obigen Beispiels mit vmclear
sehen können, dass die Adresse 0x7697630
wurde, eine Ausnahme generiert hat, die KiUserExceptionDispatcher
aufruft, eine Funktion, die für die Behandlung von Ausnahmen im Benutzermodus verantwortlich ist.
Sobald alle Ausnahmen gesammelt und gefiltert sind, können diese an ein IDAPython-Skript übergeben werden, in dem wir jede Adresse durchgehen, den Offset mit dem 7. Byte über und der XOR-Taste (0xB8
) berechnen und dann alle Anweisungen auspatchen, die Ausnahmen mit kurzen Sprüngen erzeugen.
Die folgende Abbildung ist ein Beispiel für das Patchen von Anweisungen, die Ausnahmen an den Adressen 0x07697630
und 0x0769766C
auslösen.
Unten sehen Sie eine Grafik, die das Ablaufsteuerungsdiagramm darstellt, bevor das Patching global angewendet wird. Unser Basisblock mit der vmclear
Anleitung ist orange hinterlegt. Durch die Implementierung des VEH flacht GULOADER das Kontrollflussdiagramm ab, wodurch es schwieriger wird, die Programmlogik zu verfolgen.
Nachdem das VEH mit jmp
Anweisungen gepatcht wurde, transformiert dies die Basisblöcke, indem es sie miteinander verbindet, wodurch die Komplexität hinter dem Fluss des Shellcodes reduziert wird.
Die Verwendung dieser Technik kann den Reinigungsprozess beschleunigen, aber es ist wichtig zu beachten, dass es sich nicht um eine kugelsichere Methode handelt. In diesem Fall gibt es immer noch eine gute Menge an Code/Funktionalität, die noch analysiert werden muss, aber dies trägt definitiv wesentlich zur Vereinfachung des Codes bei, indem das VEH entfernt wird. Das vollständige POC-Skript finden Sie hier.
Fazit
GULOADER verfügt über viele verschiedene Funktionen, die die Demontage unterbrechen, den Kontrollfluss behindern und die Analyse für Forscher erschweren können. Obwohl dies und der Prozess unvollkommen ist, können wir diesen Merkmalen durch verschiedene statische oder dynamische Prozesse entgegenwirken, um die Analysezeit zu verkürzen. Zum Beispiel haben wir beobachtet, dass wir bei neuen Ausnahmen im VEH immer noch durch sie hindurch verfolgen und den Shellcode patchen können. Dieser Prozess bringt den Analysten auf den richtigen Weg, näher an den Zugriff auf die Kernfunktionalität mit GULOADER.
Indem wir einige unserer Arbeitsabläufe teilen, hoffen wir, Ihnen mehrere Erkenntnisse liefern zu können, wenn Sie GULOADER in freier Wildbahn begegnen. Basierend auf den Änderungen von GULOADER ist es sehr wahrscheinlich, dass zukünftige Verhaltensweisen neue und andere Strategien erfordern werden. Für die Erkennung von GULOADER enthält der folgende Abschnitt YARA-Regeln, und das IDAPython-Skript aus diesem Beitrag finden Sie hier. Aktuelle Informationen zu den neuesten Forschungsergebnissen zu Bedrohungen finden Sie in unserem Abschnitt zur Malware-Analyse des Elastic Security Labs-Teams.
YARA
Elastic Security hat verschiedene YARA-Regeln erstellt, um diese Aktivität zu identifizieren. Nachfolgend finden Sie ein Beispiel für eine YARA-Regel zur Identifizierung von GULOADER.
rule Windows_Trojan_Guloader {
meta:
author = "Elastic Security"
creation_date = "2023-10-30"
last_modified = "2023-11-02"
reference_sample = "6ae7089aa6beaa09b1c3aa3ecf28a884d8ca84f780aab39902223721493b1f99"
severity = 100
arch = "x86"
threat_name = "Windows.Trojan.Guloader"
license = "Elastic License v2"
os = "windows"
strings:
$djb2_str_compare = { 83 C0 08 83 3C 04 00 0F 84 [4] 39 14 04 75 }
$check_exception = { 8B 45 ?? 8B 00 38 EC 8B 58 ?? 84 FD 81 38 05 00 00 C0 }
$parse_mem = { 18 00 10 00 00 83 C0 18 50 83 E8 04 81 00 00 10 00 00 50 }
$hw_bp = { 39 48 0C 0F 85 [4] 39 48 10 0F 85 [4] 39 48 14 0F 85 [7] 39 48 18 }
$scan_protection = { 39 ?? 14 8B [5] 0F 84 }
condition:
2 of them
}
Beobachtungen
Alle Observables stehen auch im ECS- und STIX-Format zum Download zur Verfügung.
Die folgenden Observablen wurden in dieser Studie diskutiert.
Observable | Typ | Name | Referenz |
---|---|---|---|
6ae7089aa6beaa09b1c3aa3ecf28a884d8ca84f780aab39902223721493b1f99 | SHA-256 | Windows.Trojan.Guloader | GULOADER Downloader |
101.99.75[.]183/MfoGYZkxZIl205.bin | URL | NA | GULOADER C2 URL |
101.99.75[.]183 | IPv4-ADDR | NA | GULOADER C2 IP |