Strings en Windows: cómo extraer texto de archivos binarios paso a paso

  • Combina strings.exe, PowerShell y WSL/GNU strings para cubrir ASCII y Unicode.
  • Refuerza con FLOSS, PEStudio, ExifTool y certutil para cadenas dinámicas y metadatos.
  • Usa Select-String con -Encoding, -AllMatches, -Context y -Raw para filtrar bien.

Strings

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.

sigcheck
Artículo relacionado:
sigcheck: Verifica la integridad de tus archivos en Windows