Analisando Arquivos LNK do Windows para Artefatos
Quando Usar
- Ao reconstruir o histórico de acesso a arquivos por usuários a partir de arquivos de atalho do Windows
- Para rastrear arquivos acessados, compartilhamentos de rede e mídias removíveis
- Durante investigações para provar que um usuário abriu documentos específicos
- Ao correlacionar acesso a arquivos com outros artefatos de timeline
- Para identificar caminhos acessados em sistemas remotos ou dispositivos USB
Pré-requisitos
- Acesso a arquivos LNK de uma imagem forense (Pastas Recent, Desktop, Quick Launch)
- LECmd (Eric Zimmerman), python-lnk ou LnkParser para análise
- Compreensão da estrutura do arquivo LNK (formato Shell Link Binary)
- Conhecimento dos locais dos arquivos LNK em sistemas Windows
- Estação de trabalho forense com ferramentas de análise instaladas
Fluxo de Trabalho
Etapa 1: Coletar Arquivos LNK da Imagem Forense
# Montar a imagem forense
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
mkdir -p /cases/case-2024-001/lnk/{recent,desktop,startup,custom}
# Copiar arquivos LNK de Itens Recentes (fonte primária)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/*.lnk \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# Copiar destinos automáticos (Jump Lists)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/*.automaticDestinations-ms \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# Copiar destinos personalizados (itens fixados do Jump List)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/CustomDestinations/*.customDestinations-ms \
/cases/case-2024-001/lnk/custom/ 2>/dev/null
# Copiar atalhos da Área de Trabalho
cp /mnt/evidence/Users/*/Desktop/*.lnk /cases/case-2024-001/lnk/desktop/ 2>/dev/null
# Copiar atalhos da pasta Inicializar (persistência)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Start\ Menu/Programs/Startup/*.lnk \
/cases/case-2024-001/lnk/startup/ 2>/dev/null
cp "/mnt/evidence/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup"/*.lnk \
/cases/case-2024-001/lnk/startup/ 2>/dev/null
# Encontrar todos os arquivos LNK no sistema
find /mnt/evidence/ -name "*.lnk" -type f 2>/dev/null > /cases/case-2024-001/lnk/all_lnk_locations.txt
# Contar e gerar hashes
ls /cases/case-2024-001/lnk/recent/ | wc -l
sha256sum /cases/case-2024-001/lnk/recent/*.lnk > /cases/case-2024-001/lnk/lnk_hashes.txt 2>/dev/null
Etapa 2: Analisar Arquivos LNK com LECmd
# Usando Eric Zimmerman's LECmd (Windows ou via Mono)
# Processar todos os arquivos LNK em um diretório
LECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf lnk_analysis.csv
# Processar um único arquivo LNK com saída detalhada
LECmd.exe -f "C:\cases\lnk\recent\document.pdf.lnk"
# Processar arquivos Jump List
JLECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf jumplist_analysis.csv
# A saída inclui:
# - Caminho do arquivo fonte
# - Caminho de destino (arquivo que foi acessado)
# - Carimbos de criação, modificação e acesso do destino
# - Carimbos de criação e modificação do LNK
# - Diretório de trabalho
# - Argumentos da linha de comando
# - Número serial e rótulo do volume
# - Tipo de unidade (Fixo, Removível, Rede)
# - ID da máquina (nome NetBIOS)
# - Endereço MAC (do banco de dados do rastreador)
# - Tamanho do arquivo de destino
Etapa 3: Analisar Arquivos LNK com Python
pip install LnkParse3
python3 << 'PYEOF'
import LnkParse3
import os, json, csv
from datetime import datetime
lnk_dir = '/cases/case-2024-001/lnk/recent/'
results = []
for filename in sorted(os.listdir(lnk_dir)):
if not filename.lower().endswith('.lnk'):
continue
filepath = os.path.join(lnk_dir, filename)
try:
with open(filepath, 'rb') as f:
lnk = LnkParse3.lnk_file(f)
info = lnk.get_json()
parsed = {
'lnk_file': filename,
'target_path': '',
'working_dir': '',
'arguments': '',
'target_created': '',
'target_modified': '',
'target_accessed': '',
'file_size': '',
'drive_type': '',
'volume_serial': '',
'volume_label': '',
'machine_id': '',
'mac_address': '',
}
# Extrair carimbos do cabeçalho
header = info.get('header', {})
parsed['target_created'] = str(header.get('creation_time', ''))
parsed['target_modified'] = str(header.get('modified_time', ''))
parsed['target_accessed'] = str(header.get('accessed_time', ''))
parsed['file_size'] = str(header.get('file_size', ''))
# Extrair informações do link
link_info = info.get('link_info', {})
if link_info:
local_path = link_info.get('local_base_path', '')
network_path = link_info.get('common_network_relative_link', {}).get('net_name', '')
parsed['target_path'] = local_path or network_path
vol_info = link_info.get('volume_id', {})
if vol_info:
parsed['drive_type'] = str(vol_info.get('drive_type', ''))
parsed['volume_serial'] = str(vol_info.get('drive_serial_number', ''))
parsed['volume_label'] = str(vol_info.get('volume_label', ''))
# Extrair dados de string
string_data = info.get('string_data', {})
parsed['working_dir'] = str(string_data.get('working_dir', ''))
parsed['arguments'] = str(string_data.get('command_line_arguments', ''))
# Extrair dados do rastreador (ID da máquina e MAC)
extra = info.get('extra', {})
tracker = extra.get('DISTRIBUTED_LINK_TRACKER_BLOCK', {})
if tracker:
parsed['machine_id'] = str(tracker.get('machine_id', ''))
parsed['mac_address'] = str(tracker.get('mac_address', ''))
results.append(parsed)
# Imprimir resumo
print(f"\n{filename}")
print(f" Destino: {parsed['target_path']}")
print(f" Modificado: {parsed['target_modified']}")
print(f" Unidade: {parsed['drive_type']} (Serial: {parsed['volume_serial']})")
if parsed['machine_id']:
print(f" Máquina: {parsed['machine_id']}")
except Exception as e:
print(f" Erro ao analisar {filename}: {e}")
# Escrever resultados em CSV
with open('/cases/case-2024-001/analysis/lnk_analysis.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=results[0].keys() if results else [])
writer.writeheader()
writer.writerows(results)
print(f"\n\nTotal de arquivos LNK analisados: {len(results)}")
PYEOF
Etapa 4: Analisar para Valor Investigativo
# Identificar arquivos acessados de mídia removível
python3 << 'PYEOF'
import csv
with open('/cases/case-2024-001/analysis/lnk_analysis.csv') as f:
reader = csv.DictReader(f)
print("=== ARQUIVOS ACESSADOS DE MÍDIA REMOVÍVEL ===\n")
removable = []
network = []
for row in reader:
if 'DRIVE_REMOVABLE' in row.get('drive_type', '').upper() or \
'removable' in row.get('drive_type', '').lower():
removable.append(row)
print(f" {row['target_modified']} | {row['target_path']} | Vol: {row['volume_serial']}")
if 'network' in row.get('drive_type', '').lower() or \
row.get('target_path', '').startswith('\\\\'):
network.append(row)
print(f"\n=== ARQUIVOS ACESSADOS DE COMPARTILHAMENTOS DE REDE ===\n")
for row in network:
print(f" {row['target_modified']} | {row['target_path']}")
print(f"\nArquivos de mídia removível: {len(removable)}")
print(f"Arquivos de compartilhamentos de rede: {len(network)}")
# Verificar máquinas únicas (dados do rastreador)
machines = set()
for row in [*removable, *network]:
if row.get('machine_id'):
machines.add(row['machine_id'])
if machines:
print(f"\nIDs de máquinas encontradas: {machines}")
PYEOF
# Verificar arquivos LNK da pasta Inicializar para persistência
echo "=== ATALHOS DA PASTA INICIALIZAR (PERSISTÊNCIA) ===" > /cases/case-2024-001/analysis/startup_persistence.txt
for lnk in /cases/case-2024-001/lnk/startup/*.lnk; do
python3 -c "
import LnkParse3
with open('$lnk', 'rb') as f:
lnk = LnkParse3.lnk_file(f)
info = lnk.get_json()
target = info.get('link_info', {}).get('local_base_path', 'Desconhecido')
args = info.get('string_data', {}).get('command_line_arguments', '')
print(f' $(basename $lnk): {target} {args}')
" >> /cases/case-2024-001/analysis/startup_persistence.txt 2>/dev/null
done
Conceitos-chave
| Conceito | Descrição |
|---|---|
| Shell Link (.lnk) | Formato de arquivo de atalho do Windows contendo caminho de destino, carimbos e metadados |
| Carimbos de destino | Horários de criação, modificação e acesso do arquivo apontado pelo atalho |
| Número serial do volume | Identificador único do volume da unidade onde o arquivo de destino reside |
| ID da máquina | Nome NetBIOS embutido pelo serviço Distributed Link Tracking |
| Endereço MAC | MAC do adaptador de rede da máquina que criou o arquivo LNK |
| Jump Lists | Listas de arquivos recentes e fixados por aplicativo (contêm dados LNK embutidos) |
| Destinos automáticos | Entradas de Jump List gerenciadas pelo sistema para arquivos abertos recentemente |
| Destinos personalizados | Itens de Jump List fixados pelo usuário que persistem até serem removidos manualmente |
Ferramentas e Sistemas
| Ferramenta | Finalidade |
|---|---|
| LECmd | Analisador de arquivos LNK de linha de comando de Eric Zimmerman com saída CSV/JSON |
| JLECmd | Analisador de Jump Lists de Eric Zimmerman |
| LnkParse3 | Biblioteca Python para análise programática de arquivos LNK |
| lnk_parser | Ferramenta alternativa de análise de LNK em Python |
| Autopsy | Plataforma forense com módulo de análise de arquivos LNK |
| KAPE | Coleta automatizada de artefatos LNK e Jump List |
| Plaso | Ferramenta de timeline com analisador de LNK para criação de super-timeline |
| LNK Explorer | Ferramenta GUI para exame interativo de arquivos LNK |
Cenários Comuns
Cenário 1: Exfiltração de Dados via Unidade USB Analise arquivos LNK da pasta Recent para destinos em unidades removíveis, correlacione números seriais de volume com entradas de registro USBSTOR, monte uma lista de arquivos acessados de dispositivos USB, estabeleça quais documentos foram abertos da unidade removível, correlacione com carimbos de cópia de arquivos.
Cenário 2: Persistência de Malware via Atalhos na Inicialização Examine arquivos LNK da pasta Inicializar para destinos maliciosos, verifique o caminho de destino e argumentos para comandos codificados ou executáveis suspeitos, confirme se o arquivo de destino existe e examine-o, correlacione o carimbo de criação com o momento inicial de comprometimento.
Cenário 3: Investigação de Acesso a Compartilhamentos de Rede Filtre arquivos LNK com caminhos de rede (destinos UNC), identifique quais compartilhamentos de rede foram acessados e quando, correlacione IDs de máquina com sistemas corporativos conhecidos, verifique se servidores de arquivos sensíveis foram acessados fora das funções normais, construa uma timeline de acesso para investigação de conformidade.
Cenário 4: Timeline de Acesso a Documentos para Procedimentos Legais Extraia todos os arquivos LNK da pasta Recent, construa uma lista cronológica de documentos acessados pelo usuário, identifique arquivos específicos relevantes para o caso, apresente carimbos de destino mostrando quando os arquivos foram abertos, correlacione com timelines de e-mail e comunicação.
Formato de Saída
Resumo da Análise de Arquivos LNK:
Perfil do Usuário: usuário_suspeito
Total de Arquivos LNK: 234 (Recent: 198, Desktop: 23, Inicializar: 5, Outros: 8)
Estatísticas de Acesso a Arquivos:
Unidade local (C:): 156 arquivos
Mídia removível: 23 arquivos (3 seriais de volume únicos)
Compartilhamentos de rede: 15 arquivos (\\server01, \\fileserver)
Outras unidades: 4 arquivos
IDs de Máquina Encontrados: DESKTOP-ABC123, LAPTOP-XYZ789
Endereços MAC: AA:BB:CC:DD:EE:FF, 11:22:33:44:55:66
Acesso a Mídia Removível:
Volume Serial 1234-ABCD:
2024-01-15 14:32 - E:\Confidencial\relatorio_financeiro.xlsx
2024-01-15 14:45 - E:\Confidencial\base_clientes.csv
2024-01-15 15:00 - E:\Projetos\codigo_fonte.zip
Persistência na Inicialização:
updater.lnk -> C:\ProgramData\svc\updater.exe (SUSPEITO)
OneDrive.lnk -> C:\Users\...\OneDrive.exe (Legítimo)
Timeline: /cases/case-2024-001/analysis/lnk_analysis.csv