Photographs are not the only files carrying a hidden diary. A document records who wrote it and what software touched it; a browser remembers every page it has shown you. Both are read the same way this unit has worked from the start: find the standard library or small package that already knows the file's format, and ask it.
Document metadata
Office documents and PDFs carry their own hidden fields: an author name, the software used, and creation and modification timestamps, all stored separately from the visible text.
extract_pdf_metadata.py
# extract_pdf_metadata.py
from pypdf import PdfReader
reader = PdfReader("evidence_copy/report.pdf")
meta = reader.metadata
print(f"Author: {meta.author}")
print(f"Creator software: {meta.creator}")
print(f"Creation date: {meta.creation_date}")
Sample output
Author: Dennis
Creator software: Microsoft Word
Creation date: 2026-09-14 18:42:07
Three attributes, three lines of code, and in one documented case, those exact two fields, author and creator software, ended a search that had run for over thirty years.
Real incident: The BTK Killer, 2005: caught by a document's metadata
Dennis Rader had evaded identification as the "BTK" serial killer in Wichita, Kansas, for over three decades. In 2004 and 2005 he resumed taunting the media, and in February 2005 sent a floppy disk containing a Microsoft Word document to a television station. Forensic examiners recovered metadata embedded in the document, including a reference to "Dennis" as the author and the name of a church whose computer had been used. Those two fields, combined with other leads, led police directly to Rader, who was arrested that month.
What this teaches: the author and creator fields the code above reads are exactly the kind that broke a thirty-year case. A document carries identifying metadata its writer never sees on screen, which is why a forensic examination reads a document's metadata as carefully as its visible text.
Browser artefacts
Most browsers store history, downloads and bookmarks in a SQLite database, a single file Python's standard library reads directly, no third-party package needed.
extract_browser_history.py
# extract_browser_history.py
import sqlite3
import shutil
# work on a copy: the live database may be locked, and the original is evidence
shutil.copy("evidence_copy/History", "history_copy.sqlite")
conn = sqlite3.connect("history_copy.sqlite")
cursor = conn.cursor()
cursor.execute("""
SELECT url, title, last_visit_time, visit_count
FROM urls ORDER BY last_visit_time DESC LIMIT 20
""")
for url, title, last_visit, visits in cursor.fetchall():
print(f"{url} (visited {visits} times)")
conn.close()
Sample output, against a lab-built copy of a Chrome-shaped history file
https://example.com/ (visited 3 times)
https://cybercrime.gov.in/ (visited 1 times)
https://learn.epochzero.net/ (visited 12 times)
Copying the database before opening it is the order-of-volatility rule from the first article of this unit, in action: the original stays untouched as evidence, and all the work happens on a disposable copy. A live browser can hold its history file locked while running, which is a second, practical reason the copy comes first: opening the original directly might simply fail.
Caution: last_visit_time is not an ordinary timestamp yet
The query above prints last_visit_time as the raw number Chrome stores it as, not a readable date. That number is counted in a unit and a reference year neither Unix nor most other software uses. The next two articles explain exactly what it means and how to convert it correctly, which matters more than it might look: comparing it to an ordinary timestamp without converting first produces a timeline wrong by centuries.
Where other common evidence lives
An investigator saves hours by knowing where common artefacts sit before going looking. The table below is a starting map for a Windows system, the platform most forensic exercises use.
| Artefact | Typical location and what it tells you |
|---|---|
| Browser history | Chrome History SQLite file; sites visited and when |
| Recent files | Windows registry and Recent folder; files recently opened |
| Prefetch | C:\Windows\Prefetch; which programs ran and how often |
| Event logs | .evtx files; logins, service starts, failures |
| Recycle Bin | $Recycle.Bin; deleted files not yet purged |
| Registry hives | SYSTEM, SOFTWARE, NTUSER.DAT; configuration and user activity |
Python's sqlite3 reads several of these directly, exactly as it read the browser history above.
Try it yourself: Read your own browser history
Your own browser's history is a safe, real database to practise on. Find your Chrome or Chromium History file (on Linux, under ~/.config/google-chrome/Default/; on Windows, under %LOCALAPPDATA%\Google\Chrome\User Data\Default\), copy it, and run extract_browser_history.py against the copy. You will see your own recent browsing, and the microsecond timestamps the next article teaches you to convert.
Check your understanding
Question 1: Why does extract_browser_history.py copy the database before connecting to it, rather than connecting to the original directly?
Two reasons: the live database may be locked while the browser is running, so opening it directly could fail, and the original is evidence that must stay untouched. Working from a copy follows the order-of-volatility and preserve-the-original rules from earlier in this unit.
Question 2: In the BTK case, what kind of evidence led investigators to the suspect, and why was it invisible to someone just reading the document on screen?
Metadata embedded in a Microsoft Word document, specifically an author field referencing "Dennis" and the name of a church whose computer had produced the file. It was invisible because metadata is stored separately from the document's visible text, so nothing about reading the letter on screen would reveal it.
Question 3: Name two Windows artefacts other than browser history, and what each one can tell an investigator.
Any two of: Prefetch files, which show which programs ran and how often; event logs (.evtx files), which record logins, service starts and failures; the Recycle Bin, which can hold deleted files not yet purged; registry hives, which hold configuration and a record of user activity.
Key takeaway: Key takeaway
A document's author and creator fields, and a browser's history database, both carry evidence that never appears on screen. Read both from a copy, never the original, and treat any timestamp you find in them with suspicion until you know its actual reference, which is exactly what the next two articles cover.

