Intermedioensambladorcriptografiamalwarereverse-engineeringanalisis-estatico

Cifrado en Ensamblador: XOR, RC4, AES y Deteccion

Como identificar y analizar algoritmos de cifrado en ensamblador durante el analisis de malware. Patrones de XOR loops, implementacion de RC4, deteccion de AES por S-box, uso de FindCrypt y tecnicas para extraer claves.

MalwareIntel Research··11 min lectura
Serie: Lenguaje Ensamblador — Parte 12

Cifrado en malware: de lo trivial a lo robusto

Practicamente todo el malware moderno usa algun tipo de cifrado. Desde un simple XOR de un byte para ocultar strings hasta AES-256-CBC para cifrar la comunicacion con el C2. Como analista, identificar el algoritmo y extraer la clave es frecuentemente el paso que desbloquea todo el analisis.

Este articulo recorre los algoritmos mas comunes en malware, como se ven en ensamblador, y las tecnicas para identificarlos y romperlos.

XOR: el cifrado ubicuo del malware

XOR de clave fija (un byte)

El caso mas simple. El malware XOR cada byte del texto cifrado con un valor constante.

En ensamblador x86:

; XOR loop tipico: descifrar buffer en memoria
    lea  esi, [encrypted_data]    ; puntero al buffer cifrado
    mov  ecx, 0x100               ; tamano: 256 bytes
    mov  al, 0x5A                 ; clave XOR: 0x5A
.loop:
    xor  byte [esi], al           ; descifrar byte actual
    inc  esi                      ; avanzar al siguiente byte
    dec  ecx                      ; decrementar contador
    jnz  .loop                    ; repetir si no es cero

Caracteristicas identificables en el desensamblador:

  • Un registro cargado con un valor constante (la clave)
  • Un XOR dentro de un loop que usa ese registro
  • El XOR opera sobre memoria indexada, no sobre si mismo (XOR EAX, EAX es zero-out, no cifrado)

XOR multi-byte

Clave de varios bytes. El malware indexa la clave ciclicamente:

; XOR con clave de 4 bytes "ABCD" (0x41424344)
    lea  esi, [encrypted_data]
    lea  edi, [xor_key]           ; "ABCD"
    mov  ecx, buffer_size
    xor  ebx, ebx                 ; indice en la clave = 0
.loop:
    mov  al, [edi + ebx]          ; byte de la clave
    xor  [esi], al                ; descifrar
    inc  esi
    inc  ebx
    cmp  ebx, 4                   ; longitud de la clave
    jb   .no_reset
    xor  ebx, ebx                 ; reset indice a 0
.no_reset:
    dec  ecx
    jnz  .loop

La diferencia visible: hay un segundo puntero que se resetea ciclicamente. El CMP con un valor pequeno (4, 8, 16, 32) sugiere la longitud de la clave.

XOR rolling

Cada byte descifrado se usa como clave para el siguiente:

; XOR rolling: cada byte depende del anterior
    lea  esi, [encrypted_data]
    mov  ecx, buffer_size
    mov  al, 0x5A                 ; semilla inicial
.loop:
    xor  [esi], al                ; descifrar byte actual
    mov  al, [esi]                ; el byte descifrado es la nueva clave
    inc  esi
    dec  ecx
    jnz  .loop

Este patron es mas resistente a analisis estadistico que XOR fijo, pero sigue siendo fragil. Si conoces un byte del plaintext (como un null terminator al final de un string), puedes derivar la clave de vuelta.

Deteccion de XOR: tecnicas practicas

Buscar instrucciones XOR en un loop: en Ghidra o IDA, busca instrucciones XOR que no sean XOR reg, reg (zero-out). Filtra por XOR que operen sobre memoria.

Entropy analysis: los datos cifrados con XOR tienen entropia alta. Herramientas como binwalk o DIE (Detect It Easy) muestran la entropia por secciones. Una seccion .data con entropia mayor a 7.0 (en escala de 0-8) probablemente contiene datos cifrados.

Known plaintext: si sospechas que el texto descifrado contiene "http://" o "MZ" (cabecera PE), XOR esos bytes con los datos cifrados. Si obtienes un patron repetitivo, has encontrado la clave.

# Python: encontrar clave XOR con known plaintext
encrypted = bytes.fromhex("1a0b1c06")
known = b"http"
key = bytes(e ^ k for e, k in zip(encrypted, known))
print(f"Clave: {key.hex()}")  # Si se repite, es la clave

RC4: el favorito del malware

Por que RC4

RC4 es el algoritmo de cifrado de flujo mas usado en malware por varias razones:

  • Implementacion muy simple (unas 20 lineas de C)
  • No tiene constantes detectables (a diferencia de AES)
  • La clave puede ser de cualquier longitud
  • Es rapido incluso en ensamblador manual

Familias que usan RC4: TrickBot, Emotet (variantes), Gootloader, AsyncRAT, AgentTesla, y muchas mas.

RC4 en ensamblador: KSA (Key Scheduling Algorithm)

La primera fase de RC4 inicializa la S-box (array de 256 bytes) usando la clave:

; KSA: inicializar S-box con la clave
; S[0..255] = 0..255 inicialmente
    lea  edi, [s_box]
    xor  ecx, ecx
.init_loop:
    mov  [edi + ecx], cl          ; S[i] = i
    inc  ecx
    cmp  ecx, 256
    jb   .init_loop

; Permutacion con la clave
    xor  ecx, ecx                 ; i = 0
    xor  edx, edx                 ; j = 0
.ksa_loop:
    movzx eax, byte [edi + ecx]   ; S[i]
    add  dl, al                    ; j = j + S[i]
    movzx ebx, byte [key + ecx % key_len]
    add  dl, bl                    ; j = j + key[i % key_len]
    ; Swap S[i] y S[j]
    movzx ebx, byte [edi + edx]   ; temp = S[j]
    mov  [edi + edx], al           ; S[j] = S[i]
    mov  [edi + ecx], bl           ; S[i] = temp
    inc  ecx
    cmp  ecx, 256
    jb   .ksa_loop

RC4 en ensamblador: PRGA (Pseudo-Random Generation Algorithm)

La segunda fase genera el keystream y lo XOR con los datos:

; PRGA: generar keystream y descifrar
    xor  ecx, ecx                 ; i = 0
    xor  edx, edx                 ; j = 0
    lea  esi, [ciphertext]
    mov  ebp, data_length
.prga_loop:
    inc  cl                        ; i = (i + 1) mod 256
    movzx eax, byte [edi + ecx]   ; S[i]
    add  dl, al                    ; j = (j + S[i]) mod 256
    ; Swap S[i] y S[j]
    movzx ebx, byte [edi + edx]
    mov  [edi + edx], al
    mov  [edi + ecx], bl
    ; Generar byte de keystream
    add  al, bl                    ; S[i] + S[j]
    movzx eax, byte [edi + eax]   ; K = S[(S[i] + S[j]) mod 256]
    xor  [esi], al                 ; descifrar: plaintext = ciphertext XOR K
    inc  esi
    dec  ebp
    jnz  .prga_loop

Como reconocer RC4 en desensamblado

Patrones clave que delatan RC4:

  1. Inicializacion de array de 256 bytes con valores secuenciales (0x00 a 0xFF). Un loop que llena 256 posiciones con su propio indice.

  2. Dos loops consecutivos sobre 256 iteraciones: primero el init, luego el KSA.

  3. Swaps frecuentes: muchos MOV para intercambiar bytes usando un temporal.

  4. Modulo 256 implicito: operaciones con registros de 8 bits (AL, CL, DL) que naturalmente hacen modulo 256 por overflow.

  5. Sin constantes detectables: a diferencia de AES o MD5, RC4 no tiene tablas ni constantes fijas. FindCrypt no lo detecta.

Extraer la clave RC4

Si identificas la funcion KSA, la clave suele estar en el primer argumento o en la ubicacion que se carga justo antes de la llamada:

; Llamada tipica a funcion RC4
push  16                  ; longitud de la clave
push  offset rc4_key      ; puntero a la clave
push  data_size           ; tamano de los datos
push  offset ciphertext   ; datos cifrados
call  rc4_decrypt

Extrae los bytes en la direccion de rc4_key con la longitud indicada. Esa es tu clave.

AES: cifrado de grado militar en malware

Por que AES en malware

AES aparece en malware que necesita cifrado robusto:

  • Ransomware: cifra archivos de la victima (LockBit, BlackCat, REvil)
  • C2 cifrado: comunicacion con el servidor de comando (Cobalt Strike)
  • Configuracion protegida: el payload cifra su configuracion embebida

Detectar AES: la S-box

AES tiene una S-box (Substitution Box) de 256 bytes que es una constante conocida. Los primeros bytes son:

63 7C 77 7B F2 6B 6F C5 30 01 67 2B FE D7 AB 76
CA 82 C9 7D FA 59 47 F0 AD D4 A2 AF 9C A4 72 C0

FindCrypt busca esta secuencia exacta en el binario. Si la encuentra, confirma la presencia de AES.

Tambien busca las constantes Rcon (Round Constants):

01 02 04 08 10 20 40 80 1B 36

Y la tabla de multiplicacion por 2 en GF(2^8) usada en MixColumns.

AES en ensamblador: patrones

Las implementaciones de AES en ensamblador varian mucho. Tres categorias principales:

AES con instrucciones nativas (AES-NI): procesadores Intel/AMD modernos tienen instrucciones hardware para AES:

; AES-NI: cifrado ultra-rapido
aesenc   xmm1, xmm2     ; una ronda de cifrado AES
aesenclast xmm1, xmm2   ; ultima ronda de cifrado
aesdec   xmm1, xmm2     ; una ronda de descifrado
aeskeygenassist xmm1, xmm2, imm8  ; generacion de claves de ronda

Si ves estas instrucciones, es AES sin duda. El malware que las usa es sofisticado y busca rendimiento.

AES con tablas T: implementacion comun en software. Usa cuatro tablas T de 1024 bytes cada una (Te0, Te1, Te2, Te3) que combinan SubBytes, ShiftRows y MixColumns. Busca cuatro arrays de 256 DWORDs consecutivos.

AES con S-box directa: implementacion basica que aplica la S-box explicitamente, luego ShiftRows, luego MixColumns. Mas lenta pero mas facil de reconocer.

Extraer la clave AES

La clave AES puede estar:

  • Hardcodeada en el binario (busca 16, 24 o 32 bytes cerca de la S-box o de las llamadas a funciones de cifrado)
  • Derivada de un password con PBKDF2 o similar
  • Recibida del C2 durante la comunicacion inicial
  • Calculada a partir de propiedades del sistema (hostname, MAC address)

Para ransomware, frecuentemente hay una clave simetrica por archivo, cifrada con RSA. La clave privada RSA esta en el servidor del atacante.

Otros algoritmos frecuentes

Base64 (codificacion, no cifrado)

No es cifrado, pero aparece constantemente. Patron en ensamblador:

; Tabla Base64 como string
db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

; Loop de codificacion: toma 3 bytes, produce 4 caracteres
; Operaciones con SHR (shift right) y AND para extraer grupos de 6 bits
shr  eax, 2           ; primeros 6 bits
and  eax, 0x3F        ; mascara 6 bits

Busca el string completo de la tabla Base64 o variantes (Base64url usa - y _ en lugar de + y /).

XOR + Base64 (combo clasico)

Patron extremadamente comun: el malware cifra con XOR y luego codifica en Base64 (o viceversa). Si descifras Base64 y obtienes datos que parecen aleatorios, aplica XOR con claves comunes.

Chacha20

Creciendo en popularidad en ransomware moderno (reemplazo de RC4 para velocidad). Tiene constantes detectables:

"expand 32-byte k"   ; constante en la inicializacion del estado

Si encuentras este string, es Chacha20.

Herramientas de deteccion

FindCrypt (IDA Pro)

Instalacion: copiar findcrypt-yara a la carpeta de plugins de IDA. Ejecutar desde Edit, Plugins, FindCrypt.

Detecta: AES, DES, 3DES, Blowfish, RC2, MD5, SHA-1, SHA-256, SHA-512, CRC32, TEA/XTEA, Serpent, Twofish, Camellia.

No detecta: RC4 (sin constantes), XOR (trivial), algoritmos custom.

Ghidra FindCrypt equivalente

Para Ghidra, el script FindCrypt-Ghidra (disponible en GitHub) ofrece funcionalidad similar:

# Ejecutar desde Script Manager de Ghidra
# FindCrypt.py busca constantes criptograficas conocidas

KANAL (PEiD plugin) y Detect It Easy

Herramientas standalone que escanean el binario buscando constantes criptograficas sin necesidad de desensamblador completo.

Entropy analysis con binwalk

binwalk -E malware.exe
# Muestra grafico de entropia por offset
# Picos de entropia alta = datos cifrados o comprimidos

Flujo de trabajo para analisis de cifrado en malware

Paso 1: detectar presencia de cifrado

  • Ejecutar FindCrypt o equivalente
  • Revisar entropia por secciones
  • Buscar strings sospechosamente ausentes (pocos strings = cifrado)

Paso 2: identificar el algoritmo

  • FindCrypt dice AES: buscar S-box, AES-NI instructions, key schedule
  • FindCrypt no detecta nada: buscar loops con XOR (probable RC4 o XOR custom)
  • Constantes "expand 32-byte k": Chacha20
  • Tabla Base64 presente: probablemente codificacion (no cifrado)

Paso 3: localizar la clave

  • Trazar xrefs hasta la funcion de cifrado/descifrado
  • Los parametros antes del CALL contienen: puntero a datos, tamano, puntero a clave, longitud de clave
  • En el decompilador, la firma de la funcion revela los parametros

Paso 4: descifrar

  • Extraer clave y datos cifrados del binario
  • Aplicar el algoritmo identificado
  • Verificar que el resultado tiene sentido (strings legibles, cabecera PE valida, JSON)
# Python: descifrar RC4 extraido de un sample
from Crypto.Cipher import ARC4

key = bytes.fromhex("5a3b4c2d1e0f")
ciphertext = open("encrypted_config.bin", "rb").read()

cipher = ARC4.new(key)
plaintext = cipher.decrypt(ciphertext)
print(plaintext)

Paso 5: documentar IOCs

Los datos descifrados contienen los IOCs que buscas: URLs de C2, dominios de backup, mutex names, claves de registro de persistencia. Documenta todo con su contexto criptografico (algoritmo, clave, offset en el binario).

Conclusiones

El cifrado en malware sigue un patron predecible: la mayoria usa XOR o RC4 para strings y configuracion, y AES para payload y comunicaciones. Saber reconocer estos patrones en ensamblador te permite desbloquear el analisis en minutos.

La clave (literalmente) esta en encontrar la clave. Una vez identificado el algoritmo y extraida la clave, el descifrado es mecanico. Las herramientas como FindCrypt aceleran la deteccion de algoritmos con constantes conocidas, pero RC4 y XOR requieren reconocimiento manual de patrones.

En el articulo final de la serie, ponemos todo en practica con ejercicios de crackmes y muestras reales para consolidar lo aprendido.

Preguntas frecuentes

Artículos relacionados

Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.