Principianteanalisis estaticostringshashestriajePEStudioherramientas

Analisis Estatico Basico: Strings, Hashes y Metadatos

Fundamentos del analisis estatico de malware. Extraccion de strings con strings y FLOSS, hashes criptograficos y fuzzy hashing con ssdeep, metadatos con PEStudio y Detect It Easy. Primer triaje de muestras sospechosas.

MalwareIntel Research··10 min lectura
Serie: Análisis de Binarios — Parte 8

El primer contacto con una muestra sospechosa

Antes de abrir un desensamblador o ejecutar un binario en sandbox, el analisis estatico basico responde preguntas fundamentales en minutos: que tipo de archivo es, para que plataforma fue compilado, que strings contiene, si esta empaquetado, y si alguien ya lo ha analizado.

Este primer triaje no requiere conocimientos avanzados de reverse engineering. Con un punado de herramientas gratuitas y un flujo de trabajo sistematico, cualquier analista SOC puede extraer indicadores utiles de una muestra sospechosa.

Paso 1: Identificacion del archivo

Nunca confiar en la extension del archivo. Un .pdf puede ser un .exe renombrado, y un .docx puede ser un archivo con macros maliciosas.

# Identificar el tipo real del archivo
file sample.suspicious
# sample.suspicious: PE32+ executable (GUI) x86-64, for MS Windows

# Verificar el magic number manualmente
xxd sample.suspicious | head -2
# 00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000  MZ..............

El magic number "MZ" (0x4D5A) confirma que es un PE de Windows. Otros magic numbers comunes:

MagicHexFormato
MZ4D 5APE (Windows)
.ELF7F 45 4C 46ELF (Linux)
Mach-O 64CF FA ED FEMach-O (macOS, little-endian)
PK50 4BZIP (incluye .docx, .xlsx, .apk, .jar)
%PDF25 50 44 46PDF
.docD0 CF 11 E0OLE (Office antiguo)

Paso 2: Hashes criptograficos

Los hashes son la huella digital del binario. Permiten buscar si la muestra ya ha sido analizada por la comunidad.

# Generar hashes
md5sum sample.exe
sha1sum sample.exe
sha256sum sample.exe

# O con Python
python3 -c "
import hashlib
data = open('sample.exe', 'rb').read()
print('MD5:   ', hashlib.md5(data).hexdigest())
print('SHA1:  ', hashlib.sha1(data).hexdigest())
print('SHA256:', hashlib.sha256(data).hexdigest())
print('Tamano:', len(data), 'bytes')
"

Donde buscar los hashes:

ServicioURLQue ofrece
VirusTotalvirustotal.comDetecciones de 70+ AVs, relaciones
MalwareBazaarbazaar.abuse.chBase de datos de muestras con tags
Hybrid Analysishybrid-analysis.comReportes de sandbox
ANY.RUNany.runAnalisis interactivo en sandbox
Joe Sandboxjoesandbox.comAnalisis automatizado detallado

Importante: SHA256 es el hash estandar para identificacion de malware. MD5 y SHA1 tienen colisiones conocidas y se usan como complemento, no como identificador principal.

Paso 3: Fuzzy Hashing con ssdeep

Los hashes criptograficos cambian completamente con cualquier modificacion del archivo. ssdeep genera hashes que permiten medir la similitud entre archivos:

# Generar hash ssdeep
ssdeep sample.exe
# 384:Gm4eLNqRaR2q/b2V0HoS7kBn:Gm4eLNq/qb2V0HoS7c, "sample.exe"

# Comparar dos archivos
ssdeep -d sample1.exe sample2.exe
# sample1.exe matches sample2.exe (87)

# Comparar contra base de datos
ssdeep -r /malware/samples/ > hashes.txt
ssdeep -m hashes.txt new_sample.exe

Un match de 80% o mas indica que los binarios son variantes de la misma familia. ssdeep es especialmente util para:

  • Identificar variantes de malware que usan custom packers (cada empaquetado produce hash SHA256 diferente pero ssdeep similar).
  • Agrupar muestras de la misma campana.
  • Detectar actualizaciones incrementales de malware.

Import Hash (ImpHash)

El ImpHash es un hash MD5 de la lista de imports del PE (DLLs y funciones en orden). Binarios compilados con el mismo codigo fuente y linker producen el mismo ImpHash aunque el binario sea diferente:

import pefile

pe = pefile.PE("sample.exe")
print("ImpHash:", pe.get_imphash())

El ImpHash es un excelente indicador para agrupar muestras de la misma familia cuando el codigo fuente no ha cambiado.

Paso 4: Extraccion de strings

Los strings son la fuente de informacion mas accesible en un binario. URLs, IPs, rutas de archivos, mensajes, nombres de APIs y comandos pueden aparecer en texto claro.

strings (herramienta basica)

# Strings ASCII (minimo 6 caracteres)
strings -n 6 sample.exe

# Strings Unicode (UTF-16LE, comun en Windows)
strings -e l sample.exe

# Ambos, guardando en archivo
strings -a sample.exe > strings_ascii.txt
strings -e l sample.exe >> strings_unicode.txt

# Buscar patrones especificos
strings sample.exe | grep -iE "http|https|ftp|\.exe|\.dll|\.bat"
strings sample.exe | grep -iE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"
strings sample.exe | grep -iE "HKEY|CurrentVersion|Run"

FLOSS (FLARE Obfuscated String Solver)

FLOSS de Mandiant va mas alla de strings: emula las funciones de descifrado del malware para extraer strings ofuscadas:

# Analisis completo
floss sample.exe

# Solo strings decodificadas (las interesantes)
floss sample.exe --no-static-strings

# Con longitud minima
floss sample.exe -n 8

# Output JSON para procesamiento
floss sample.exe -o json > floss_output.json

FLOSS clasifica los strings en tres categorias:

  1. Static strings: Visibles con strings normal.
  2. Decoded strings: Extraidas emulando funciones de descifrado.
  3. Stack strings: Construidas caracter a caracter en el stack.

Que buscar en los strings

CategoriaPatronEjemplo
URLshttp://, https://http://evil.com/gate.php
IPsFormato IPv4192.168.1.100, 45.33.32.156
DominiosPatron FQDNc2server.evil.com
RutasC:, %TEMP%, %APPDATA%C:\Users\Public\payload.exe
RegistroHKEY, CurrentVersionHKCU\Software\Microsoft...
Comandoscmd, powershell, wmiccmd.exe /c whoami
DLLs.dllws2_32.dll, advapi32.dll
APIsNombres de funcionesCreateRemoteThread
MutexIdentificadores unicosGlobal\MutexName123
User-AgentMozilla, User-AgentMozilla/5.0 (Windows NT...
Credencialespassword, login, adminadmin:password123

Paso 5: Detect It Easy (DIE)

DIE identifica el compilador, linker y packer utilizado analizando patrones de bytes y heuristicas en el binario:

diec sample.exe

# Salida tipica:
# PE32
#   Compiler: Microsoft Visual C/C++(2019)[EXE32]
#   Linker: Microsoft Linker(14.29)
#   Tool: Visual Studio(2019 version 16.11)

# O para un binario empaquetado:
# PE32
#   Packer: UPX(3.96)[NRV2E]

Informacion que revela DIE:

  • Compilador: MSVC, MinGW/GCC, Borland/Delphi, Go, Rust.
  • Packer: UPX, ASPack, Themida, VMProtect, MPRESS.
  • Installer: NSIS, Inno Setup, InstallShield.
  • .NET: Si es un assembly .NET (para decompilacion con dnSpy/ILSpy).

Paso 6: PEStudio (analisis integral)

PEStudio es la herramienta de referencia para un analisis estatico rapido de PE. En una sola vista muestra:

SeccionContenido
IndicatorsAnomalias detectadas automaticamente
VirustotalResultado de busqueda del hash
StringsStrings clasificadas por relevancia
LibrariesDLLs importadas
ImportsFunciones importadas con marcado de sospechosas
ExportsFunciones exportadas (si es DLL)
ResourcesRecursos embebidos con entropia
SectionsSecciones con entropia y permisos
TLSTLS callbacks (codigo pre-entry point)
ManifestManifest XML (permisos solicitados)
VersionInformacion de version del archivo
CertificateFirma digital
DebugInformacion de debug y rutas PDB

Indicadores criticos que PEStudio resalta:

  • Imports clasificadas como sospechosas (rojo)
  • Secciones con entropia alta
  • Entry point fuera de .text
  • Timestamp anomalo
  • Presencia de TLS callbacks
  • Manifest solicitando elevacion de privilegios

Paso 7: Metadatos de compilacion

Compilador y version

El compilador deja huellas en el binario. Conocer el compilador ayuda a:

  • Entender la estructura del codigo.
  • Identificar funciones de runtime conocidas.
  • Elegir el decompilador mas adecuado.
CompiladorIndicadores
MSVCRich Header, CRT init code, secciones .CRT
MinGW/GCCSeccion .textbss, sin Rich Header
Delphi/BorlandSeccion CODE, strings Delphi en recursos
GoStrings runtime.main, gopclntab, buildid
RustStrings rust_begin_unwind, panic messages
.NETCLR header, seccion .text con IL code
AutoItString "AU3!" en recursos, AutoIt3 script
PyInstallerSeccion con overlay grande, archivos Python embebidos
NSISSecciones .ndata, .rsrc grande, strings NSIS

Informacion de version

Los recursos de version (VS_VERSION_INFO) pueden contener:

  • CompanyName, ProductName, FileDescription
  • OriginalFilename (revelador si difiere del nombre actual)
  • InternalName
  • FileVersion, ProductVersion

El malware a veces copia la informacion de version de ejecutables legitimos para parecer autentico. Si un archivo dice ser de "Microsoft Corporation" pero no tiene firma digital de Microsoft, es sospechoso.

Paso 8: Verificacion de firma digital

# Windows (PowerShell)
Get-AuthenticodeSignature sample.exe

# Linux (con osslsigncode)
osslsigncode verify sample.exe

# Python
import pefile
pe = pefile.PE("sample.exe")
# Verificar si tiene Security Directory (Data Directory index 4)
if len(pe.OPTIONAL_HEADER.DATA_DIRECTORY) > 4:
    sec_dir = pe.OPTIONAL_HEADER.DATA_DIRECTORY[4]
    if sec_dir.VirtualAddress > 0 and sec_dir.Size > 0:
        print("Tiene firma digital (verificar validez)")
    else:
        print("Sin firma digital")
EscenarioImplicacion
Sin firmaSospechoso si se presenta como software de empresa conocida
Firma valida de empresa desconocidaVerificar la empresa, podria ser certificado robado
Firma invalida o expiradaFirma removida, binario modificado post-firma
Firma de empresa conocida y validaPodria ser legitimo o usar certificado robado

Flujo completo de triaje

Aplicando todos los pasos en orden:

# 1. Tipo de archivo
file sample.suspicious

# 2. Hashes
sha256sum sample.suspicious

# 3. Buscar en VirusTotal (si la politica lo permite)
# vt hash search: sha256_del_archivo

# 4. Strings rapido
strings -n 6 sample.suspicious | head -50
strings -n 6 sample.suspicious | grep -iE "http|\.exe|cmd|HKEY"

# 5. FLOSS (si strings no revela mucho)
floss sample.suspicious --no-static-strings

# 6. Detectar compilador/packer
diec sample.suspicious

# 7. Entropia
python3 -c "
import pefile
pe = pefile.PE('sample.suspicious')
for s in pe.sections:
    name = s.Name.decode().rstrip(chr(0))
    print(name, round(s.get_entropy(), 2))
"

# 8. ssdeep para agrupar con muestras conocidas
ssdeep sample.suspicious

Tiempo estimado: 5 a 10 minutos para un triaje completo.

Automatizacion del triaje

import hashlib
import pefile
import sys
import os

def basic_triage(filepath):
    # Tamano
    size = os.path.getsize(filepath)

    # Hashes
    data = open(filepath, "rb").read()
    md5 = hashlib.md5(data).hexdigest()
    sha256 = hashlib.sha256(data).hexdigest()

    print("=== Basic Triage Report ===")
    print("File:", filepath)
    print("Size:", size, "bytes")
    print("MD5:", md5)
    print("SHA256:", sha256)
    print()

    # PE analysis
    try:
        pe = pefile.PE(filepath)
    except pefile.PEFormatError:
        print("No es un PE valido")
        return

    # Tipo
    is_dll = bool(pe.FILE_HEADER.Characteristics & 0x2000)
    is_exe = bool(pe.FILE_HEADER.Characteristics & 0x0002)
    arch = "x64" if pe.FILE_HEADER.Machine == 0x8664 else "x86"

    print("Tipo:", ("DLL" if is_dll else "EXE"), arch)
    print("ImpHash:", pe.get_imphash())
    print()

    # Secciones
    print("Secciones:")
    for s in pe.sections:
        name = s.Name.decode().rstrip("\x00")
        entropy = round(s.get_entropy(), 2)
        flag = ""
        if entropy > 7.0:
            flag = " [HIGH ENTROPY]"
        print("  " + name.ljust(12) + str(entropy) + flag)

    # Imports count
    import_count = 0
    if hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
        for entry in pe.DIRECTORY_ENTRY_IMPORT:
            import_count += len(entry.imports)
    print("\nImports:", import_count)

    if import_count < 10:
        print("[!] Pocas imports: probable resolucion dinamica o packing")

    # Timestamp
    import datetime
    ts = pe.FILE_HEADER.TimeDateStamp
    try:
        compile_date = datetime.datetime.utcfromtimestamp(ts)
        print("Compilado:", compile_date)
        if compile_date.year > 2030 or compile_date.year < 2000:
            print("[!] Timestamp sospechoso")
    except (ValueError, OSError):
        print("[!] Timestamp invalido:", hex(ts))

if __name__ == "__main__":
    basic_triage(sys.argv[1])

Conclusion

El analisis estatico basico es el punto de partida obligatorio para cualquier muestra sospechosa. En menos de 10 minutos, un analista puede determinar el tipo de archivo, verificar si es conocido por la comunidad, extraer indicadores (strings, hashes, IPs, URLs), detectar si esta empaquetado y obtener metadatos del compilador. Estas herramientas (strings, FLOSS, PEStudio, DIE, ssdeep) son gratuitas y no requieren ejecutar el binario, eliminando cualquier riesgo de infeccion durante el triaje inicial.

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.