Daniel Stepanic

Mit GULOADER klebrig werden: Entschleierung des Downloaders

Elastic Security Labs führt Sie durch die aktualisierten Gegenmaßnahmen für die GULOADER-Analyse.

13 Minuten LesezeitMalware-Analyse
Mit GULOADER klebrig werden: Entschleierung des Downloaders

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 EnumResourceTypesAansehen, 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 RtlAddVectoredExceptionHandlerhinzufü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 vmxonstoß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 vmclearverwenden, 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 (0x7697662ausgefü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 vmclearsehen können, dass die Adresse 0x7697630wurde, eine Ausnahme generiert hat, die KiUserExceptionDispatcheraufruft, 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 0x0769766Causlö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.

ObservableTypNameReferenz
6ae7089aa6beaa09b1c3aa3ecf28a884d8ca84f780aab39902223721493b1f99SHA-256Windows.Trojan.GuloaderGULOADER Downloader
101.99.75[.]183/MfoGYZkxZIl205.binURLNAGULOADER C2 URL
101.99.75[.]183IPv4-ADDRNAGULOADER C2 IP

Referenzen