
Si alguna vez has abierto un ejecutable y te ha parecido un galimatías, no estás solo; sin embargo, entre ese mar de bytes se esconden cadenas de texto legibles que revelan rutas, DLLs, errores y pistas forenses. Sacarlas a la luz con las herramientas adecuadas en Windows te permite entender de qué va un binario sin desensamblar ni depurar.
En este recorrido vas a aprender a usar strings.exe (Sysinternals), PowerShell (Select-String, Get-Content) y también el comando GNU strings desde WSL, además de FLOSS y utilidades como PEStudio, ExifTool o certutil. Verás cómo localizar texto en ASCII y Unicode/UTF-16LE, rascar cadenas generadas en tiempo de ejecución, detectar XML incrustado, revisar flujos alternativos NTFS y apoyarte en metadatos, firmas y hashes para contextualizar lo que encuentres. Apóyate en ExifTool para metadatos generales y en la guía para eliminar metadatos de documentos Office cuando necesites limpiar información sensible.
Qué son las cadenas en un binario PE y por qué importan
Una cadena no es más que una secuencia de bytes interpretada con una codificación (ASCII, UTF-8, UTF-16/Unicode). En Windows, los ejecutables PE suelen contener nombres de funciones importadas, mensajes, rutas, manifiestos XML, URLs de OCSP/CRL y advertencias del stub DOS como «This program cannot be run in DOS mode». Ese texto delata dependencias, funcionalidad y hasta señales anti-depuración (p. ej., IsDebuggerPresent, LoadLibrary, GetProcAddress).
Al leer cadenas, separa el grano de la paja. Te interesan dominios, rutas, nombres de DLL, claves de registro, opciones de línea de comandos y cualquier rastro que sugiera comportamiento. Que veas referencias a VeriSign/Microsoft no garantiza una firma válida, pero sí es una pista para comprobar autenticidad con herramientas del sistema.
El básico en Windows: Sysinternals strings.exe y FLOSS
La forma más directa de comenzar en Windows es strings.exe (de Sysinternals). Recorre el archivo y vuelca las secuencias de texto legibles que detecta, algo perfecto para una primera criba. Un uso mínimo sería:
strings.exe binario.exe > cadenas.txt
En la salida verás de todo: manifiestos XML, DLLs importadas, mensajes de error, rutas internas y textos de interfaz. Si sospechas que el binario está empaquetado u ofuscado, complementa con FLOSS (FLARE/FireEye), que intenta recuperar cadenas que se construyen en tiempo de ejecución y que strings.exe no detecta de forma estática.
Apóyate en visores estáticos como PEStudio (indicadores, importaciones, recursos, firmas, entropía) y en ExifTool para metadatos generales. Cruzar resultados reduce falsos positivos y te ayuda a priorizar qué investigar a continuación sin gastar horas.
PowerShell para buscar y filtrar texto: Select-String al detalle
PowerShell trae un «grep» nativo: Select-String. Trabaja sobre líneas y usa expresiones regulares para localizar patrones en archivos o en la salida de otros comandos. Por defecto muestra archivo, número de línea y el contenido donde aparece la coincidencia, y puede devolver varias coincidencias por línea, hacer matching sensible a mayúsculas o devolver solo booleanos.
Conceptos clave de uso con archivos: -Path para seleccionar rutas (acepta comodines), -Pattern para el texto o regex a buscar, -AllMatches para encontrar todas las apariciones en cada línea, -CaseSensitive si necesitas distinción de mayúsculas/minúsculas y -Encoding para definir la codificación esperada (UTF-8, Unicode/UTF-16, OEM, etc.).
También es útil -Context para mostrar líneas antes/después, -Include/-Exclude para filtrar por patrones de nombre, -NotMatch para invertir la búsqueda, -List para devolver solo la primera coincidencia por archivo, -Quiet para salida booleana y -Raw para que la salida sea solo el texto coincidente en lugar de objetos enriquecidos.
Algunas recetas prácticas, que cubren casos típicos con codificación y múltiples archivos:
# Buscar "Microsoft" distinguiendo mayúsculas/minúsculas en todos los .txt del directorio actual
Select-String -Path .\*.txt -Pattern 'Microsoft' -CaseSensitive
# Encontrar TODAS las apariciones (no solo la primera por línea)
Select-String -Path .\log.txt -Pattern 'ERROR' -AllMatches
# Mostrar 2 líneas antes y 3 después de una coincidencia
Select-String -Path .\registro.txt -Pattern 'FATAL' -Context 2,3
# Solo decir si existe el patrón (True/False)
Select-String -Path .\*.conf -Pattern '^Port\s+22$' -Quiet
# Forzar lectura como UTF-16 (Unicode LE), típico en cadenas de binarios Windows
Select-String -Path .\dump_strings.txt -Pattern '<\?xml' -Encoding Unicode
Dos matices importantes cuando canalizas objetos: con -InputObject se trata la colección completa como una sola cadena combinada, mientras que si encadenas por pipeline se procesa elemento a elemento. Además, los objetos FileInfo se leen como ruta (contenido del archivo), no como su ToString(); y si quieres la representación de texto formateada de objetos complejos, Out-String es tu amigo antes de Select-String.
Leer binarios como bytes en PowerShell y entender ADS de NTFS
A veces no basta con buscar, necesitas cargar el binario como bytes para operar a bajo nivel. PowerShell lo facilita con Get-Content y el parámetro -AsByteStream (mejor junto a -Raw) para obtener un ] sobre el que filtrar, medir o trocear:
$bytes = Get-Content -Path .\binario.exe -AsByteStream -Raw
$bytes.Length
Si el sospechoso es un archivo de texto enorme, escoge entre lectura línea a línea o cruda con -Raw. Y cuando solo te interesa el final de un fichero que va creciendo (logs), tira de -Tail o -TotalCount para limitar IO y acelerar la triage.
En NTFS, no olvides los Alternate Data Streams (ADS): datos que viajan en streams paralelos asociados a un fichero. Puedes listarlos y leerlos así:
# Ver streams disponibles
Get-Item -Path .\sospechoso.txt -Stream *
# Leer el stream primario y uno alternativo
Get-Content -Path .\sospechoso.txt -Stream ':$DATA'
Get-Content -Path .\sospechoso.txt -Stream 'Oculto'
Cuando la ruta contenga caracteres especiales usa -LiteralPath para evitar interpretaciones de comodines. Filtrar con -Include/-Exclude o -Filter te ahorra escribir bucles innecesarios y te permite procesar lotes enteros de forma consistente.
WSL/GNU strings: gran aliado para cribar rápido
Si trabajas con WSL o Linux, el comando strings es un clásico. Para obtener un vistazo rápido de cadenas útiles, combina longitud mínima, offsets y codificaciones, y luego filtra con grep:
# Básico
strings ejemplo.bin
# Ignorar morralla: cadenas de 10 o más
strings -n 10 ejemplo.bin
# Mostrar desplazamiento (hex) de cada cadena
strings -t x ejemplo.bin
# Forzar codificación UTF-16LE (Windows)
strings -e S ejemplo.bin
# Encadenar con head para una vista rápida
strings archivo1.bin archivo2.bin | head -n 100
Estos trucos son oro para encontrar URLs, extensiones, patrones de configuración, nombres de recursos y demás indicadores. Si el binario está muy ofuscado, verás pocas cadenas; ahí toca pasar a herramientas que reconstruyen texto en ejecución o a análisis dinámico.
Localizar y extraer XML incrustado en ejecutables
Muchos EXE llevan fragmentos XML como manifiestos o configuraciones en claro (ASCII/Unicode). Para cazarlos desde PowerShell, busca el arranque de documento o etiquetas características y, si procede, parsea el bloque como XML:
# 1) Volcar posibles cadenas (UTF-16) a un archivo intermedio si hace falta
strings.exe binario.exe > dump_strings.txt
# 2) Buscar el inicio de XML (en Unicode, usa -Encoding Unicode)
$xmlLines = Select-String -Path .\dump_strings.txt -Pattern '<\?xml' -Encoding Unicode
# 3) O leer directamente el EXE como texto Unicode y capturar el bloque
$text = Get-Content -Path .\binario.exe -Encoding Unicode -Raw
$match = ::Match($text, '<\?xml*?</+>')
if ($match.Success) {
$xml = $match.Value
$xml.DocumentElement | Format-List -Property *
}
Cuando el bloque esté codificado, verás Base64 o hexadecimal rodeando tags. Con certutil es muy cómodo decodificar:
# Base64 a binario
certutil -decode in.txt out.bin
# Hex a binario
certutil -decodehex in.hex out.bin
Si necesitas validar firma o ver la cadena de certificados, Get-AuthenticodeSignature en PowerShell y certutil -asn/-dump te dan el contexto que strings por sí sola no muestra. Así encajas si ese XML es un manifiesto, una policy o configuración que el binario consume.
Firmas y metadatos: lo que cuentan los certificados
Las cadenas suelen incluir nombres de CA (VeriSign, Thawte), rutas de OCSP/CRL o identificadores. Eso invita a comprobar si el binario está firmado digitalmente y si la verificación es válida; puedes apoyarte en herramientas especializadas como sigcheck para análisis de firmas y reputación. En Windows, revisa propiedades del archivo o lanza:
# Firma del ejecutable
Get-AuthenticodeSignature .\binario.exe | Format-List
# Volcado ASN.1 de un DER/P7
certutil -asn firma.der
# Hash rápido para inventario/IOC
certutil -hashfile .\binario.exe SHA256
Que existan referencias a certificados no implica confianza: hay certificados caducados o revocados que seguirán dejando rastro en recursos. Esa discrepancia, sumada a cadenas sospechosas, es un indicador más a tener en la triage.
Cuando strings no basta: empaquetado, ofuscación y entropía
Si la salida es pobre, puede que el ejecutable esté empaquetado (UPX, variantes) o con datos comprimidos/cifrados. Observa la entropía de secciones PE (alta = compresión/cifrado) y prueba con FLOSS para cadenas dinámicas. PEStudio facilita ver entropía, importaciones, recursos y banderas en un par de clics.
UPX se detecta y desempaqueta con facilidad, pero hay ofuscaciones caseras a base de XOR y descifrado en runtime. En esos casos, las cadenas aparecerán en memoria durante la ejecución, no en el binario estático, así que piensa en hooking, tracing de API o ejecutar en sandbox si necesitas llegar más lejos.
Flujo de trabajo de triage estático que ahorra tiempo
Un orden que rara vez falla: 1) Identifica tipo y arquitectura (cabeceras, «file», xxd). 2) Calcula hashes (MD5/SHA-1/SHA-256) para inventario e IOCs. 3) Extrae cadenas con strings.exe y GNU strings, filtra por longitud y busca patrones. 4) Pruébalo con FLOSS si sospechas generación en runtime. 5) Mira metadatos y firma con PEStudio/ExifTool/PowerShell. 6) Usa certutil para decodificar blobs y volcar ASN.1. 7) Revisa ADS de NTFS por si hay datos alternativos. 8) Señales de ofuscación y entropía para decidir si pasas a dinámico.
Si analizas malware o quieres más contexto PE, herramientas como pev/peframe aportan: hashes tradicionales, ssdeep (fuzzy hashing), imphash (basado en IAT), packers, mutex y funciones criptográficas. Además, utilidades como pescan (entropía, timestamps) o pepack para firmas de empaquetadores te ayudan a clasificar rápido.
Leer y escribir binarios de forma programática: C++, Python y ASP.NET
Además de rascar cadenas, conviene saber cómo tratar binarios a bajo nivel en código. En C++, la clase fstream en modo ios::binary permite lectura/escritura directa y posicionamiento con seekg/seekp (en bytes). Ojo con usar objetos autocontenidos (p. ej., arrays char en structs) y con alineación/endianness si vas a mover archivos entre plataformas o compiladores.
// Guardar un registro binario
struct Persona { char nombre; int edad; char telefono; };
Persona p{ "Baltasar", 33, "988387028" };
std::ofstream f("datos.bin", std::ios::binary);
if (f.is_open()) f.write(reinterpret_cast<const char*>(&p), sizeof(Persona));
En Python, para extraer números estructurados de un binario, piensa en struct.unpack tras abrir con ‘rb’. Si lo que buscas es localizar patrones de texto, puedes leer todo como bytes y buscar secuencias delimitadas (p. ej., entre marcadores claros), o convertir un bloque a string con la codificación correcta y filtrar con regex.
with open('archivo.bin', 'rb') as f:
data = f.read()
# Buscar secuencia UTF-16LE de '<?xml'
needle = '<?xml'.encode('utf-16le')
pos = data.find(needle)
if pos != -1:
# Extrae una ventana y decodifica con cuidado
snippet = data.decode('utf-16le', errors='ignore')
Si desarrollas en web con .NET y necesitas devolver un binario al navegador, recuerda establecer el ContentType adecuado y escribir el archivo al stream HTTP. Un patrón típico en ASP.NET (VB) es usar Response.ContentType = «application/pdf» y Response.WriteFile con la ruta física, terminando con Response.End para evitar que se mezcle otra salida.
Select-String: parámetros y trucos que marcan la diferencia
Aunque es sencillo de usar, Select-String tiene opciones menos conocidas que conviene dominar. -Culture (en PS 7+) permite ajustar comparaciones teniendo en cuenta la referencia cultural o bien forzar «Ordinal» para comparaciones binarias rápidas, lo que combinado con -SimpleMatch evita interpretación regex y acelera búsquedas literales.
La codificación por defecto en PowerShell moderno es UTF-8 sin BOM, pero puedes especificar -Encoding explícitamente: ASCII, OEM, Unicode (UTF-16 LE), UTF8/UTF8BOM/UTF8NoBOM, UTF32 y hasta páginas de códigos numéricas (p. ej., -Encoding 1252). Es clave cuando analizas volcado de cadenas Unicode o archivos con BOM ausente.
Si solo necesitas la primera coincidencia por archivo para construir una lista de afectados, tira de -List. Para excluir lo que sí coincide (p. ej., líneas que NO contengan «Get» ni «Set»), usa -NotMatch con varios patrones. Y cuando quieras únicamente el texto coincidente estilo grep/findstr, -Raw simplifica la salida.
# Excluir líneas que contengan Get o Set
Select-String -Path .\Command.txt -Pattern 'Get','Set' -NotMatch
# Mostrar solo el fragmento que coincide (modo "crudo")
Select-String -Path .\*.log -Pattern '0x+' -Raw
Recuerda que la salida normal es un objeto MatchInfo con propiedades útiles (Path, LineNumber, Line, Matches). Puedes encadenar a Get-Member para inspeccionarlas y después formatear como te convenga con Select-Object, Export-CSV o Format-List según tu objetivo.
Casos reales: Unicode, offsets y patrones útiles
Mucho binario Windows guarda texto en UTF-16LE. Si strings.exe te da un volc volcado básico, considera re-analizar con foco en Unicode y buscar secuencias útiles: «http», «\\\\» para rutas, «.exe», «api», o etiquetas XML. Luego filtra con Select-String forzando -Encoding Unicode para no perder coincidencias.
# Volcado con GNU strings (WSL) en UTF-16LE y luego filtrado
strings -e S binario.exe | grep -E '(http|\\\\|\.exe|<\?xml)'
Si quieres saber dónde vive cada cadena dentro del archivo para correlacionar con secciones PE, usa «strings -t x» y cruza offsets con un visor PE. Puede ayudarte a decidir si un texto está en .rdata, .text o en recursos, lo cual cambia la interpretación del hallazgo.
Seguridad y sandbox: precauciones mínimas
Cuando trabajes con muestras potencialmente maliciosas, establece una política mínima: utiliza máquinas virtuales, no ejecutes el binario en el host principal, verifica integridad con hashes y compara en servicios reputacionales si el caso lo permite, y en casos de documentos sospechosos revisa cómo identificar un PDF malicioso en Windows. Si decides ejecutar, hazlo en sandbox aislada y con monitorización de red/archivo/registro para capturar cadenas que aparecen solo en runtime.
Como parte de tu disciplina, guarda los resultados (hashes, cadenas relevantes, metadatos, firma) y etiqueta cada artefacto con fecha y contexto. Ese orden te permitirá volver atrás y reproducir análisis, además de comparar familias y variantes con fuzzy hashing (ssdeep) e imphash.
Trabajando con este enfoque y las utilidades que hemos visto, podrás extraer en minutos todo el texto valioso que un binario Windows deja a la vista: desde cadenas incrustadas en Unicode hasta XML escondido, pasando por rutas, endpoints y firmas. Conforme te acostumbres a combinar strings.exe, Select-String, FLOSS, certutil, PEStudio/ExifTool y WSL/GNU strings, ganarás velocidad y precisión, reducirás ruido y tendrás una base sólida para decidir si escalar a análisis dinámico, reversing o cierre de la investigación.