O journal Update Sequence Number do NTFS é o primeiro artefacto a que recorro em qualquer host Windows onde precise de saber o que tocou no disco e quando. Está activado por predefinição em todos os volumes NTFS que o Windows expede desde o Vista, quase ninguém o desactiva, e quase ninguém o lê antes de algo correr mal. É essa assimetria que o torna útil.
Cada criação, eliminação, mudança de nome, truncamento, alternância de atributo e fecho de ficheiro no volume acrescenta um registo a $UsnJrnl:$J. Os registos são pequenos (algumas dezenas de bytes cada) e o ficheiro é um buffer circular de tamanho fixo, pelo que uma máquina activa retém grosso modo os últimos milhões de operações. Num desktop com a alocação predefinida de 32 MB são alguns dias. Num servidor de ficheiros dimensionado para 1 GB são semanas.
Onde o journal realmente vive
O journal não é um ficheiro normal. É um fluxo de dados alternativo chamado $J, anexado ao ficheiro de metadados \$Extend\$UsnJrnl na raiz do volume. Dois detalhes que apanham quem nunca o fez:
- Um arrastar-e-largar no Explorador, ou um
xcopy, ou umrobocopy, vai copiar silenciosamente o fluxo predefinido vazio e ficará com um ficheiro de zero bytes. Use uma ferramenta que perceba ADS: FTK Imager, X-Ways,icatdo The Sleuth Kit, RawCopy.exe, PowerForensics. O artigo complementar sobre extrair$Jde uma imagem de disco percorre cada uma. - Existe um fluxo irmão chamado
$Maxno mesmo ficheiro de metadados. Contém apenas metadados de tamanho/configuração. Se extrair$Maxpor engano, não obtém nada útil. Escolha sempre$J.
O próprio ficheiro é esparso. O NTFS reserva o tamanho máximo configurado em disco mas mantém a região inicial não utilizada a zeros. Quando se extrai $J de uma imagem, os primeiros muitos megabytes costumam ser apenas zeros antes do primeiro registo real. Qualquer parser razoável (usnrs, o USN-Journal-Parser do PoorBillionaire, MFTECmd, o parser WebAssembly desta página) salta automaticamente os zeros iniciais.
Estrutura do registo (USN_RECORD_V2)
Cada registo é uma struct USN_RECORD_V2. A Microsoft documenta o layout em winioctl.h; segue o resumo campo a campo:
| Campo | Bytes | Significado |
|---|---|---|
| RecordLength | 4 | Tamanho total do registo, incluindo nome do ficheiro |
| Major / Minor version | 2 + 2 | Sempre 2.0 no que vai encontrar na prática |
| FileReferenceNumber | 8 | Entrada MFT + sequência do ficheiro |
| ParentFileReferenceNumber | 8 | Entrada MFT + sequência do directório pai |
| USN | 8 | Posição deste registo no journal |
| Timestamp | 8 | FILETIME do Windows (ticks de 100 ns desde 1601-01-01) |
| Reason | 4 | Bitmask que descreve o que mudou |
| SourceInfo | 4 | Pistas (ex.: DATA_MANAGEMENT para alterações iniciadas pelo SO) |
| SecurityId | 4 | Índice em $Secure:$SII |
| FileAttributes | 4 | Atributos NTFS padrão |
| FilenameLength / Offset | 2 + 2 | Posição do nome UTF-16 no registo |
| Filename | n | UTF-16 LE, sem terminador nulo |
A bitmask Reason é o campo que justifica o seu peso. É aditiva, não exclusiva: um único registo pode trazer FileCreate | DataExtend | Close juntos. Um ciclo de vida típico de ficheiro é FileCreate | DataExtend → DataExtend | Close → BasicInfoChange | Close → FileDelete | Close. Reconstituir essa sequência a posteriori é como se conta o que realmente aconteceu ao ficheiro. O artigo sobre códigos de razão é a referência de campo para cada bit.
Dois campos que o leitor recente costuma subestimar:
FileReferenceNumberé a sua chave de junção. Agrupe os registos por ela e tem toda a história do ficheiro através de mudanças de nome, alterações de atributos e eliminação. Note que os 16 bits superiores são um número de sequência: um ficheiro eliminado e um novo ficheiro alocados à mesma entrada MFT partilham a entrada mas diferem na sequência.ParentFileReferenceNumberé a única informação de caminho do registo. O nome do ficheiro é apenas a folha. Precisa de um$MFTparseado para percorrer a cadeia parental até um caminho completo. Adquira ambos, sempre.
Por que ganha o seu lugar em DFIR
Duas razões que aparecem em quase todos os trabalhos.
Primeira, o journal sobrevive à eliminação. Mesmo depois de um ficheiro desaparecer do namespace e da sua entrada MFT ser reutilizada para outra coisa, o registo da sua criação, crescimento, mudança de nome e eliminação continua em $J até o buffer circular passar por cima. O mesmo se aplica a ficheiros esvaziados da reciclagem: os ficheiros $I da reciclagem são limpos, mas o journal lembra-se. Numa caça do tipo «este ficheiro alguma vez existiu», o journal aguenta mais que a entrada MFT e que os metadados da reciclagem na maior parte das vezes.
Segunda, é barato e auto-descritivo. Um $J de 100 MB normalmente contém cinco a dez milhões de registos cobrindo dias a semanas. Cada registo carrega o seu próprio timestamp, razão, referência do ficheiro e do pai. Pode passá-lo por um parser em segundos e pivotar sobre qualquer campo. Não existe outro artefacto Windows a este preço.
O que não lhe vai dizer é quem. Não há utilizador, processo nem linha de comandos em registo algum. Para atribuir um actor, correlacione por timestamp com o evento 4663 de Security.evtx (acesso a objecto, exige SACLs que quase de certeza não configurou), o evento 11 do Sysmon (criação de ficheiro), ou as árvores de processos do evento 1 do Sysmon. O journal responde ao quê e ao quando. Outros registos respondem ao quem.
Onde se encaixa na pilha de artefactos
O modelo mental que uso, ordenado de «estado actual» a «história histórica»:
$MFT— o índice de estado actual. Cada ficheiro e directório no volume, incluindo algumas entradas recentemente eliminadas. Quatro timestamps por atributo, sem histórico.$UsnJrnl:$J— histórico por operação, dias a semanas. O que está a ler aqui.$LogFile— o log de transacções de recuperação após crash do NTFS. Minutos a horas de imagens brutas antes/depois. O artigo USN journal vs MFT vs LogFile detalha quando recorrer a cada um.
Junte o journal a Prefetch, AmCache, Shimcache, ficheiros LNK e jump lists e consegue habitualmente reconstituir, ao minuto, o que correu, o que foi aberto e o que tocou no disco.
O que vem a seguir
Se nunca abriu um journal, a forma mais rápida de criar intuição é tirar um de uma máquina de teste e carregá-lo no parser no topo desta página juntamente com o $MFT correspondente. Filtre por FileCreate e leia o ficheiro pela ordem em que o Windows o escreveu. Os artigos seguintes desta série aprofundam as flags de razão, o procedimento de extracção, e os padrões que o journal expõe para ransomware, exfiltração, timestomping e recuperação de ficheiros eliminados.
Leituras adicionais
- Microsoft Learn — Change Journals e a referência USN_RECORD_V2.
- O usnrs da Airbus CERT — o parser
USN_RECORD_V2open-source mais limpo que conheço, e o que dá vida ao módulo WebAssembly deste site. - Brian Carrier, File System Forensic Analysis — o tratamento ao nível de livro dos internals do NTFS que ainda não foi substituído.