TL;DR. O primeiro u32 = tamanho do cabeçalho (tipicamente 0x30–0x36). Nesse offset, cada entrada começa com o magic de 4 bytes 10ts, seguido de um cabeçalho de 12 bytes e um corpo de tamanho variável: caminho UTF-16LE (com prefixo de tamanho, sem terminador nulo), mtime FILETIME e um blob de dados final. O flag de execução foi removido no Windows 10.
Toda versão do Windows desde o XP entregou um layout de ShimCache diferente. A variante Windows 10 / 11 é a que os investigadores mais veem hoje, e também a mais clemente de analisar — uma vez que você conhece as regras. Este post percorre o formato de ponta a ponta.
O blob a analisar
Você começa com o valor binário em:
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache\AppCompatCache
Se você extraiu esse valor da hive SYSTEM (veja onde o ShimCache fica armazenado), o que você tem é um único blob, tipicamente de dezenas a centenas de kilobytes. O blob contém um cabeçalho pequeno seguido por uma sequência de entradas, cada uma começando com um valor magic conhecido.
O cabeçalho
Os primeiros quatro bytes little-endian do blob dão o offset da primeira entrada. No Windows 10 / 11 isso é tipicamente 0x30, 0x34, 0x35 ou 0x36, dependendo do build. Algumas hives colocam 0x80 aqui — sinal de um layout Windows 8.x que usa a mesma assinatura de entrada 10ts / 00ts.
Um parser defensivo não codifica fixo o tamanho do cabeçalho; lê o primeiro u32 e valida que o byte naquele offset é o início de uma entrada reconhecida. Se nem 10ts nem 00ts aparecerem no offset declarado, varra para a frente em busca de 10ts e retome a partir daí — isso lida com hives ligeiramente fora da especificação que sistemas reais às vezes produzem.
Uma entrada Windows 10 / 11, byte a byte
Cada entrada moderna começa com a assinatura de quatro bytes 10ts (0x31 0x30 0x74 0x73). O layout completo, em ordem, é:
| Offset | Tamanho | Campo |
|---|---|---|
| 0x00 | 4 | Magic — "10ts" |
| 0x04 | 4 | Sequência / desconhecido (frequentemente ignorado pelos parsers) |
| 0x08 | 4 | Tamanho dos dados da entrada — bytes após este campo |
| 0x0C | 2 | Tamanho do caminho em bytes (UTF-16LE) |
| 0x0E | N | Bytes do caminho (UTF-16LE, sem terminador) |
| 0x0E + N | 8 | Última modificação — FILETIME (100 ns desde 1601-01-01 UTC) |
| 0x16 + N | 4 | Tamanho dos dados finais |
| 0x1A + N | M | Dados finais (geralmente vazios ou pequenos) |
O tamanho total da entrada é portanto 0x0C + entry_data_size. A próxima entrada começa imediatamente depois.
Duas notas práticas:
- O caminho é UTF-16LE e não é terminado por nulo. Use o campo de tamanho do caminho; não leia até encontrar um null.
- O
FILETIMEé o mtime$STANDARD_INFORMATIONdo arquivo, não o momento em que o programa rodou. O post sobre prova de execução explica por que isso importa.
O que foi removido no Windows 10
Versões anteriores do Windows empacotavam um flag Executed dentro de cada entrada. No Windows 10 e 11, ele foi removido inteiramente. Não há forma, no cache, de saber se um binário realmente rodou — você precisa de Prefetch, AmCache ou logs de eventos para isso.
Na prática
Um parser robusto:
- Valida o magic de quatro bytes no offset anunciado pelo cabeçalho.
- Itera entradas lendo o campo de tamanho dos dados e avançando.
- Decodifica o caminho como UTF-16LE.
- Converte o
FILETIMEno formato de carimbo que seu tooling a jusante prefere (Unix ms é conveniente). - Expõe o rótulo do formato do SO (Windows 10/11 vs 8.x vs 8.0) para filtragem a jusante.
Se você quer uma referência funcionando, o Shimcache Parser open source implementa exatamente o algoritmo acima em Rust e o entrega ao seu navegador como WebAssembly — sem servidor, sem upload.
Parsers de referência
- AppCompatCacheParser de Eric Zimmerman — a implementação C# padrão-ouro que cobre cada variante do Windows.
- ShimCacheParser da Mandiant — a prova de conceito Python original, útil como referência cruzada de formato.
- Velociraptor
Windows.Registry.AppCompatCache— artefato VQL para coleta ao vivo. - Windows 10/11 AppCompatCache deep dive (Ø Security) — a descrição pública mais completa do layout moderno.