Pular para conteúdo

Índices de diretórios ($I30)

O que é o $I30

Todo diretório NTFS mantém um índice dos arquivos que contém, chamado $I30. Um diretório pequeno o mantém em seu registro do $MFT ($INDEX_ROOT); um maior também tem registros INDX, geralmente de 4.096 bytes cada, em um fluxo $INDEX_ALLOCATION:$I30. Cada entrada de índice contém uma cópia do $FILE_NAME do arquivo: seu nome, a referência MFT, o diretório pai, quatro carimbos de data/hora e dois tamanhos, conforme a última vez que o NTFS atualizou a entrada.

Quando um arquivo é excluído ou renomeado para fora de um diretório, o NTFS remove sua entrada e desloca as entradas seguintes. Os bytes antigos permanecem no slack do registro INDX, além das entradas em uso, até que entradas posteriores os sobrescrevam. O slack de índice pode preservar o nome, os horários e o tamanho de um arquivo cujo registro do $MFT foi reutilizado e cujos registros do Diário USN já foram descartados pela rotação.

Melhor conclusão: um nome encontrado no slack de índice esteve, em algum momento, no índice deste diretório com os horários e tamanhos de $FILE_NAME indicados. Uma entrada de slack não informa quando foi removida, nem se foi excluída, renomeada ou deslocada por rebalanceamento.

Localização e coleta

C:\<directory>:$I30:$INDEX_ALLOCATION

O $I30 é metadado do NTFS: colete-o com uma ferramenta forense com acesso bruto ao disco que consiga exportar o fluxo $I30 de um diretório (os arquivos exportados costumam se chamar $I30). O Juntei também pode procurar registros INDX em uma imagem de disco ou em espaço não alocado. Colete também o $MFT e o $J do mesmo volume, para determinar o que eram as entradas de slack.

Cuidados para o analista

  • O slack de índice é parcial e desordenado. As entradas são sobrescritas à medida que o diretório muda; um nome ausente não prova nada.
  • Muitas entradas de slack são cópias de entradas ainda em uso, deixadas quando as entradas se deslocam. CopyOfEntryInUse as marca. O mesmo nome excluído também pode aparecer no slack várias vezes.
  • Os horários em uma entrada de índice são horários de $FILE_NAME conforme a última atualização da entrada. Eles podem diferir tanto dos horários de $STANDARD_INFORMATION quanto dos de $FILE_NAME do registro do $MFT do arquivo.
  • AllocatedSize e RealSize também refletem a última atualização da entrada e podem estar desatualizados.
  • O FileEntry (ou ParentEntry) de uma entrada de slack pode estar ausente quando bytes posteriores o sobrescreveram. Quando presente, o registro MFT que ele indica pode ter sido reutilizado desde então: compare o número de sequência.
  • parse-ntfs i30 lê registros INDX. O índice de um diretório pequeno existe apenas em seu registro do $MFT ($INDEX_ROOT); seus arquivos estão no $MFT.

Analisar com o Juntei

Usage: juntei parse-ntfs i30 <INPUT> [OPTIONS]

Input:
  -d, --directory <DIR>  Recursively find $I30 files (with $I30 in their name, or starting with an INDX record)
  -f, --file <FILE>      Parse one $I30 stream, or any file holding INDX records (a disk image, unallocated space)

Filtering:
      --slack-only  Only the entries found in slack
      --no-copies   Leave out the slack entries that copy an entry in use

Output:
  -o, --output <FILE>       Save every entry
  -t, --output-type <TYPE>  csv, json, or jsonl
juntei parse-ntfs i30 -f 'Users_$I30'
juntei parse-ntfs i30 -d evidence/ -o i30.csv
juntei parse-ntfs i30 -f 'Users_$I30' --slack-only --no-copies -t jsonl
juntei parse-ntfs i30 -f disk.raw -o carved-i30.csv

O resumo lista os registros INDX (e quantos foram gravados parcialmente), as entradas em uso e no slack, e os nomes das entradas de slack que não são cópias exatas de entradas em uso. Esses nomes são candidatos a arquivos excluídos ou renomeados, e não um veredito por si sós.

Campos de saída CSV

Campo Interpretação
SourcePath Arquivo de entrada; distingue hosts e diretórios.
RecordOffset, EntryOffset Deslocamentos em bytes do registro INDX e da entrada na entrada analisada. Essenciais para a validação e para registros encontrados em imagens de disco.
RecordVCN, RecordLSN A posição do registro no fluxo de índice e seu número de sequência do $LogFile.
FromSlack True para uma entrada encontrada além das entradas em uso.
CopyOfEntryInUse Entrada de slack com o mesmo nome, namespace, arquivo (quando conhecido), pai e horários de uma entrada em uso do mesmo índice de diretório. Geralmente é uma sobra do deslocamento de entradas, não um arquivo excluído.
Filename O nome no diretório.
Namespace win32, dos (nome curto 8.3), win32_and_dos ou posix.
FileEntry, FileSequence A referência MFT do arquivo. Vazio para uma entrada de slack cujo cabeçalho foi sobrescrito.
ParentEntry, ParentSequence A referência MFT do diretório. Vazio quando outros bytes a sobrescreveram.
CreatedUTC, ModifiedUTC, MFT-ModifiedUTC, AccessedUTC Horários de $FILE_NAME, com precisão de 100 ns, conforme a última atualização da entrada.
AllocatedSize, RealSize Tamanhos que o NTFS copiou para a entrada; veja os cuidados acima.
FileAttributes Nomes de atributos unidos por | (hidden|archive); is_directory para um subdiretório. Os bits que esta versão do Juntei não nomeia são mantidos em hexadecimal (0x00800000).
ReparseValue Tag de reparse ou tamanho dos atributos estendidos, a partir de $FILE_NAME.
Problems Danos no registro, como setores gravados parcialmente. Entradas de um registro danificado ainda merecem análise, com cuidado.

JSON/JSONL têm os mesmos campos em snake_case, com problems como lista e null para valores desconhecidos.

Como as entradas de slack são encontradas

O slack é varrido em cada limite de 8 bytes, onde as entradas começam, em busca de entradas inteiras, de atributos $FILE_NAME cujo cabeçalho de entrada foi sobrescrito e, no início do slack, de um $FILE_NAME cuja referência ao pai foi sobrescrita pelo final das entradas em uso. Um candidato precisa se parecer com o que o Windows grava: um nome UTF-16 válido sem caracteres de controle nem separadores de caminho, quatro horários entre 1980 e 2100, um namespace conhecido e flags de atributo conhecidas. Uma referência ao pai acima de 32 bits indica bytes que a sobrescreveram e é deixada vazia.

A matriz de sequência de atualização (update sequence array) de cada registro é aplicada. Um setor que não termina com o valor da sequência de atualização foi gravado parcialmente; o Juntei lê o registro como está e indica os setores em Problems.

Estratégia de investigação

  1. Comece pelos nomes no slack que não são cópias, listados no resumo, e depois filtre com --slack-only --no-copies.
  2. Procure o FileEntry no $MFT. O mesmo FileSequence significa o mesmo arquivo; um valor maior significa que o registro foi liberado desde então e, talvez, reutilizado.
  3. Pesquise o nome no Diário USN para saber quando ele foi excluído ou renomeado.
  4. Compare os horários de $FILE_NAME com os horários de $STANDARD_INFORMATION do $MFT para detectar timestomping.
  5. Correlacione com Prefetch, LNK, Jump Lists e logs de eventos para saber como o arquivo foi usado.

Mais detalhes