Navegadores, e-mail e sincronização em nuvem · Aula 2 de 6
Firefox: places.sqlite e dados de sessão
11 min de leitura
O Firefox mantém seu histórico em um esquema SQLite próprio, em arquivos JSON próprios e em um formato de sessão compactado, com registros de data e hora contados a partir de uma época diferente da do Chromium. Esta aula mostra onde fica um perfil do Firefox, quais tabelas respondem a "o que foi visitado, digitado e baixado, e quando" e como abrir os arquivos de sessão que registram as abas abertas e fechadas recentemente. A aula 4.3 aborda o cache e a navegação privativa.
Localizando o perfil
No Windows, cada perfil tem duas pastas com o mesmo nome: %APPDATA%\Mozilla\Firefox\Profiles\<random>.<name> (itinerante: os bancos de dados e arquivos JSON desta aula) e %LOCALAPPDATA%\Mozilla\Firefox\Profiles\<random>.<name> (local: o cache). O prefixo tem oito caracteres aleatórios; as versões atuais nomeiam o perfil criado para cada instalação como default-release, por exemplo, k3x9p2qa.default-release.
Dois arquivos em %APPDATA%\Mozilla\Firefox\ informam qual perfil estava em uso. profiles.ini lista todos os perfis em seções [ProfileN] (Name, IsRelative, Path) e, desde o Firefox 67, uma seção [Install<hash>] cuja linha Default= indica o perfil usado por uma instalação. installs.ini repete esse mapeamento, com uma seção por hash de instalação. Um perfil chamado default com Default=1 costuma ser um perfil legado quase vazio; portanto, siga a entrada [Install…] e, ainda assim, examine todas as pastas de perfil presentes.
No Linux, os perfis ficam em ~/.mozilla/firefox/, com o cache em ~/.cache/mozilla/firefox/. O pacote Snap usa ~/snap/firefox/common/.mozilla/firefox/ e o Flatpak, ~/.var/app/org.mozilla.firefox/.mozilla/firefox/. A partir do Firefox 147, novas instalações seguem a estrutura XDG em ~/.config/mozilla/firefox/. Procure todos os arquivos profiles.ini em vez de confiar em um único caminho.
A maioria dos bancos de dados do Firefox opera no modo de registro antecipado de escrita. Colete places.sqlite junto com places.sqlite-wal e places.sqlite-shm (faça o mesmo para cookies, histórico de formulários e favicons): visitas recentes podem existir apenas no WAL. Calcule os hashes do conjunto e depois trabalhe com cópias, pois abrir um banco de dados com o SQLite pode aplicar um checkpoint do WAL ao arquivo principal e alterar ambos.
places.sqlite
moz_places e moz_historyvisits
moz_places contém uma linha por URL: url, title, rev_host (o host invertido caractere por caractere, acrescido de um ponto final, de modo que transfer.example.com se torna moc.elpmaxe.refsnart.), visit_count, typed (1 se a URL já foi digitada), frecency (uma pontuação de classificação para sugestões da barra de endereços, não um horário), last_visit_date e guid. moz_historyvisits contém uma linha por visita: place_id (faz a junção com moz_places.id), visit_date, visit_type e from_visit (o id da visita que levou até aqui, 0 se não houver). Ambas as datas estão em PRTime: microssegundos desde 1970-01-01 UTC (aula 3.1).
| visit_type | Nome | Significado |
|---|---|---|
| 1 | LINK | Seguiu um link |
| 2 | TYPED | Digitou ou selecionou na barra de endereços |
| 3 | BOOKMARK | Abriu a partir de um favorito |
| 4 | EMBED | Conteúdo incorporado; as versões atuais mantêm esses registros na memória, por isso raramente estão no disco |
| 5 | REDIRECT_PERMANENT | Acessou por meio de um redirecionamento permanente, como HTTP 301 |
| 6 | REDIRECT_TEMPORARY | Acessou por meio de um redirecionamento temporário, como HTTP 302 |
| 7 | DOWNLOAD | URL obtida como download |
| 8 | FRAMED_LINK | Seguiu um link dentro de um frame |
| 9 | RELOAD | Recarregou a página |
Seguir from_visit de trás para frente reconstrói uma cadeia de navegação. O Firefox expira automaticamente o histórico antigo, portanto a ausência de uma visita não prova que ela não ocorreu.
Favoritos, texto digitado e origens
moz_bookmarks armazena favoritos (type 1), pastas (2) e separadores (3), com fk apontando para moz_places.id, parent, title e dateAdded e lastModified em PRTime. moz_inputhistory registra o que o usuário digitou na barra de endereços e qual resultado escolheu em seguida: input (o texto digitado), place_id (a página selecionada) e use_count, uma pontuação que diminui com o tempo. Não tem registro de data e hora, portanto determine sua data por meio das visitas correspondentes. moz_origins mantém uma linha por combinação de esquema e host (prefix, host, frecency), referenciada por moz_places.origin_id.
Downloads
Desde o Firefox 26, os downloads são registrados em places.sqlite; perfis mais antigos usavam um arquivo downloads.sqlite separado. Um download adiciona uma visita do tipo 7 para a URL de origem e duas anotações de página em moz_annos, vinculadas ao place_id dessa URL e nomeadas por meio de moz_anno_attributes.name:
downloads/destinationFileURI:contentcontém o local de salvamento como uma URI, comofile:///C:/Users/jsilva/Downloads/Q1_payroll.zip.downloads/metaData:contentcontém JSON comstate(1 concluído, 2 falhou, 3 cancelado; outros valores indicam downloads pausados ou bloqueados),endTimeem milissegundos desde 1970 UTC,fileSize(presente quando o download foi bem-sucedido) edeleted.
As linhas de moz_annos também contêm dateAdded e lastModified em PRTime. Corrobore com o sistema de arquivos: a entrada $MFT do arquivo e seu fluxo Zone.Identifier (aula 1.4).
Outros arquivos do perfil
favicons.sqlite: ícones (moz_icons) vinculados às URLs de páginas (moz_pages_w_icons), um vestígio que corrobora que uma página foi carregada ou adicionada aos favoritos.formhistory.sqlite:moz_formhistoryarmazena valores digitados em campos de formulários web:fieldname,value,timesUsed,firstUsedelastUsed(PRTime). Caixas de pesquisa também aparecem aqui, frequentemente comfieldnameigual asearchbar-history.cookies.sqlite:moz_cookiescomhost,name,value,creationTimeelastAccessed(PRTime) eexpiry. Os valores não são criptografados. Versões mais antigas armazenamexpiryem segundos Unix e as versões atuais, em milissegundos; portanto, verifique a quantidade de dígitos.permissions.sqlite:moz_permsregistra permissões de sites (origin,type, comodesktop-notificationoucamera,permission,modificationTime).logins.json: credenciais salvas.hostname,formSubmitURLe os horários são legíveis;encryptedUsernameeencryptedPasswordsão criptografados com uma chave mantida emkey4.db(banco de dados de chaves NSS, em SQLite desde o Firefox 58), protegida pela Senha primária, se houver uma definida.extensions.json: complementos instalados comid,version,active,installDateeupdateDate(milissegundos) epath; os pacotes ficam emextensions\como arquivos.xpi.addons.jsonmantém em cache os metadados da loja de complementos. Procure complementos que o usuário não teria instalado conscientemente.
Dados de sessão
A pasta sessionstore-backups contém o estado da sessão:
recovery.jsonlz4: a sessão em andamento, regravada enquanto o Firefox está em execução (a cada 15 segundos por padrão).recovery.baklz4: a cópia anterior do arquivo de recuperação.previous.jsonlz4: a sessão anterior à última reinicialização.upgrade.jsonlz4-<buildID>: uma cópia feita quando o Firefox foi atualizado, nomeada com o ID de compilação de 14 dígitos.- No encerramento normal, o Firefox também grava
sessionstore.jsonlz4na raiz do perfil.
Os arquivos usam um contêiner LZ4 próprio da Mozilla: os bytes 0–7 são a assinatura mozLz40\0 (6D 6F 7A 4C 7A 34 30 00), os bytes 8–11 são o tamanho descompactado como um inteiro de 32 bits em little-endian, e o restante é um único bloco LZ4 bruto, não um frame LZ4; por isso, a ferramenta padrão de linha de comando lz4 o rejeita. Use uma ferramenta dedicada, como dejsonlz4 ou lz4json, ou Python: lz4.block.decompress(data[12:], uncompressed_size=int.from_bytes(data[8:12], 'little')). De forma equivalente, lz4.block.decompress(data[8:]), pois essa função lê por padrão um prefixo de tamanho de 4 bytes em little-endian.
O JSON revela windows[].tabs[], cada uma com entries[] (o histórico de voltar e avançar da aba: url, title, referenciador), um index que marca a entrada atual e lastAccessed; _closedTabs com closedAt; _closedWindows; e formdata, que contém texto digitado nos campos das páginas (campos de senha não são salvos). Os horários da sessão estão em milissegundos desde 1970 UTC. Comparar previous.jsonlz4 com recovery.jsonlz4 mostra o que mudou entre as sessões.
Firefox e Chromium lado a lado
| Arquivo do Firefox | Equivalente no Chromium | O que ele responde |
|---|---|---|
places.sqlite: moz_places, moz_historyvisits | History: urls, visits | Quais páginas, quando e como foram acessadas |
places.sqlite: moz_annos | History: downloads, downloads_url_chains | O que foi baixado, de onde e onde foi salvo |
places.sqlite: moz_inputhistory | Shortcuts: omni_box_shortcuts | O que o usuário digitou na barra de endereços |
places.sqlite: moz_bookmarks | Bookmarks (JSON) | Páginas salvas deliberadamente e quando |
formhistory.sqlite | Web Data: autofill | Valores digitados em formulários web |
cookies.sqlite | Network\Cookies (valores criptografados) | Sites visitados e sessões mantidas |
logins.json + key4.db | Login Data + chave de Local State | Credenciais salvas e seus sites |
sessionstore-backups\*.jsonlz4 | Sessions\Session_*, Tabs_* | Abas abertas e fechadas, dados de formulários das páginas |
extensions.json | Extensions\ + Preferences | Complementos instalados |
Exemplo resolvido: digitação seguida de download
Uma coleta de triagem contém places.sqlite e seu WAL. A pergunta: o usuário acessou deliberadamente um site de transferência de arquivos e quando um download foi concluído? Execute:
SELECT v.id, v.from_visit, strftime('%Y-%m-%dT%H:%M:%SZ', v.visit_date/1000000, 'unixepoch') AS visit_utc, v.visit_type, p.url FROM moz_historyvisits v JOIN moz_places p ON p.id = v.place_id ORDER BY v.visit_date;
| id | from_visit | visit_utc | visit_type | url |
|---|---|---|---|---|
| 1201 | 0 | 2026-05-19T08:41:37Z | 2 | https://transfer.example.com/ |
| 1202 | 1201 | 2026-05-19T08:42:18Z | 1 | https://transfer.example.com/d/7Hq2 |
| 1203 | 1202 | 2026-05-19T08:42:25Z | 7 | https://dl.transfer.example.com/7Hq2/Q1_payroll.zip |
O visit_date bruto da visita 1201 é 1.779.180.097.512.334. A divisão inteira por 1.000.000 resulta em 1.779.180.097 segundos, o que corresponde a 2026-05-19T08:41:37Z; a divisão trunca os 0,512334 s, como deve ocorrer em uma resposta em segundos inteiros. (datetime(visit_date/1000000,'unixepoch') fornece o mesmo instante sem o T e o Z.) A visita 1201 é TYPED, sem referenciador, e moz_inputhistory tem input = trans apontando para essa página, portanto o usuário digitou o início do endereço. A visita 1202 foi um link seguido a partir de 1201, e a visita 1203 foi um download iniciado a partir de 1202.
Para o registro da URL do ZIP (o destino da visita 1203), downloads/metaData contém {"state":1,"deleted":false,"endTime":1779180163904,"fileSize":48213977}. Aqui, endTime está em milissegundos: 1.779.180.163.904 ÷ 1.000 = 1.779.180.163,904 s, portanto o download foi concluído em 2026-05-19T08:42:43Z, 18 segundos após a visita do tipo 7.
Não misture as épocas dos navegadores. O Chromium armazena o mesmo instante como microssegundos desde 1601: (1.779.180.097 + 11.644.473.600) × 1.000.000 + 512.334 = 13.423.653.697.512.334, e a consulta do Chromium deve subtrair 11.644.473.600 após a divisão. Decodifique o valor do Firefox com a fórmula do Chromium e você obterá 1657-05-19T08:41:37Z; decodifique o valor do Chromium como PRTime e você obterá 2395-05-19T08:41:37Z. Ambas as unidades são microssegundos, portanto apenas a época as distingue; um valor de 16 dígitos em 2026 é PRTime e um valor de 17 dígitos é horário do Chromium.
Ferramentas
O DB Browser for SQLite executa consultas como a apresentada acima. O Plaso tem plugins SQLite para Firefox, como firefox_history e firefox_cookies; compare a saída deles com uma consulta manual, pois os esquemas mudam entre versões. O Hindsight analisa apenas navegadores baseados no Chromium e não lê perfis do Firefox.
Foco no exame: Prepare-se para converter valores PRTime para ISO 8601 UTC, ler códigosvisit_type(especialmente 2 TYPED e 7 DOWNLOAD) e recuperar o caminho de salvamento e o horário de conclusão de um download a partir demoz_annos, lembrando queendTimeestá em milissegundos. Você também pode precisar localizar o perfil ativo a partir deprofiles.iniouinstalls.ini, ou reconhecer o cabeçalhomozLz40\0e seu comprimento de 12 bytes.
Pontos principais
- O perfil itinerante contém os bancos de dados e o perfil local contém o cache;
profiles.inieinstalls.iniidentificam o perfil usado por cada instalação. - Faça a junção de
moz_historyvisits.place_idcommoz_places.id; PRTime são microssegundos desde 1970 UTC, e o horário do Chromium são microssegundos desde 1601. - Desde o Firefox 26, os downloads são uma visita do tipo 7 mais as anotações
downloads/destinationFileURIedownloads/metaData, comendTimeem milissegundos. - O histórico de formulários, os valores dos cookies e os dados de formulários da sessão são armazenados sem criptografia; as senhas salvas precisam de
key4.db. - Os arquivos de sessão são um cabeçalho
mozLz40\0de 12 bytes mais um bloco LZ4 e revelam abas abertas, abas fechadas e dados digitados em formulários. - Sempre colete os arquivos
-wale-shme analise cópias.