Evidence Acquisition: Imaging, Hashing & Read-Only Mounting
- Explain why you analyze a bit-for-bit copy, never the original, and what chain of custody means
- Image a whole device or partition to a file with dd, choosing block size and watching progress
- Prove an image is a faithful copy by hashing the source and image with sha256sum and comparing
- Mount an image strictly read-only via a loopback device so analysis can never alter the evidence
Why you never touch the original
Frame acquisition as preserving a crime scene: analyze a copy so the evidence stays pristine.
Before you run a single forensic tool, you have a problem older than computers: the act of examining evidence can destroy it. Mount a disk the wrong way, open a file, let an antivirus scan kick off — and you've changed timestamps, replayed a journal, or overwritten a deleted file you needed. Once the original is altered, you can never get the pristine state back, and in any serious investigation your findings become worthless.
The discipline that solves this is evidence acquisition: you make a perfect, verifiable copy of the storage first, lock the original away untouched, and do all your poking and prodding on the copy. If you wreck the copy, you make another from the sealed original. The original is the ground truth you protect at all costs.
Think of a physical crime scene. The detective doesn't rearrange the furniture to look for clues — they photograph everything exactly as found, bag and tag each item with a label and a signature, and analyze in the lab. The sealed evidence bag, and the unbroken record of who held it when, is what lets the evidence stand up later. A forensic disk image is that photograph; the hash is the tamper-evident seal; the chain of custody is the signed log of every hand the evidence passed through.
The acquisition order
Learn the fixed sequence — image, hash, verify, mount read-only — and why order matters.
Acquisition is a checklist run in order, and the order is not negotiable. Skip a step or swap two and you lose the property that makes the result trustworthy. The sequence is:
- 1. Image — make a bit-for-bit copy of the source to an image file (
ddand friends). - 2. Hash the source — compute a cryptographic hash of the original device so you have a fingerprint of exactly what you copied.
- 3. Hash the image and compare — the image's hash must equal the source's hash. Equal hashes prove the copy is faithful.
- 4. Mount read-only — attach the image through a loopback device with writes disabled, so every later tool physically cannot change it.
- 5. Hash again afterward — re-hash the image when you're done analyzing. Same hash = you can prove your analysis altered nothing.
The rule beneath all of it: handle the original as few times as possible, and only ever to read it. Once the verified image exists, the original goes back in the evidence locker and you never touch it again.
Check yourself
In forensic acquisition, when should you compute a cryptographic hash of the evidence image — before analysis, after analysis, or both?
- 1. Image — make a bit-for-bit copy of the source to an image file (
Image it: dd
Copy a whole device or partition to an image file with dd, byte for byte.
ddcopies raw bytes from an input (if=) to an output (of=) and does no interpretation — it doesn't know or care whether the bytes are a filesystem, deleted files, or empty space. That ignorance is exactly what you want: a forensic image must capture everything, including unallocated space and slack where deleted data still lives. Pointif=at the device (/dev/sdb, the whole disk) or a partition (/dev/sdb1), andof=at an image file on separate storage.The one parameter worth tuning is block size (
bs=).ddreads and writes one block at a time; the default 512 bytes is slow because it does a syscall per tiny block. A larger block likebs=4Mmoves the same data in far fewer, larger chunks — much faster — without changing a single byte of the result.sudo dd if=/dev/sdb of=/evidence/case42.img bs=4M status=progress conv=noerror,sync8321499136 bytes (8.3 GB, 7.7 GiB) copied, 92 s, 90.4 MB/s 1985+0 records in 1985+0 records out 8327790592 bytes (8.3 GB, 7.8 GiB) copied, 92.1 s, 90.4 MB/s
- if=/dev/sdb
- Input file — the SOURCE. /dev/sdb is the whole device; use /dev/sdb1 to image just one partition.
- of=/evidence/case42.img
- Output file — the image. Always write to SEPARATE storage, never back onto the source.
- bs=4M
- Block size: read/write in 4 MiB chunks. Bigger blocks = far fewer syscalls = much faster; the bytes copied are identical.
- status=progress
- Print a live throughput/progress line to stderr — without it dd is silent until done, and a multi-hour image looks hung.
- conv=noerror,sync
- On a read error, don't abort (noerror) and pad the bad block with zeros to keep byte offsets aligned (sync). Critical for failing disks.
ddread the entire/dev/sdbdevice and wrote it tocase42.img— an exact, mountable replica of the disk. Therecords in/records outlines should match (here1985+0both ways), confirming nothing was dropped. Withconv=noerror,sync, a disk with a few bad sectors still produces a complete image; the unreadable blocks become zeros instead of stopping the copy and leaving you with a partial, useless image.Check yourself
Why image the whole device (/dev/sdb) and copy unallocated space too, instead of just tar-ing up the visible files?
Prove it's faithful: sha256sum
Hash the source and the image and compare — equal hashes prove a perfect copy.
An image you can't prove is faithful is just an unlabeled copy. A cryptographic hash turns any amount of data into a short fixed-length fingerprint with one essential property: change a single bit of the input and the output changes completely and unpredictably. So if the hash of the source device equals the hash of the image, the two are byte-for-byte identical — and if anyone alters the image later by even one bit, its hash will no longer match, exposing the tampering.
Hash the source device and the image, then compare the two fingerprints. Equal means a verified, faithful acquisition.
Example — not runnable on your lab box
sudo sha256sum /dev/sdb /evidence/case42.img9f2c4e0b7a1d83c5e6f0b2a9d4c71e8f3b6a0c2d5e8f1a4b7c0d3e6f9a2b5c8d /dev/sdb 9f2c4e0b7a1d83c5e6f0b2a9d4c71e8f3b6a0c2d5e8f1a4b7c0d3e6f9a2b5c8d /evidence/case42.img
- /dev/sdb
- Hash the raw source device — the fingerprint of exactly what you copied.
- /evidence/case42.img
- Hash the image you produced. List both on one line and the two hashes sit together for easy comparison.
The two SHA-256 hashes are identical, character for character. That single fact certifies the acquisition: case42.imgis a perfect replica of/dev/sdb, with no bytes added, dropped, or altered. Record this hash in your case notes now — it's the reference value you'll compare against again when analysis is finished. From here on, you work only on the image; the original disk goes back in the locker.Check yourself
You hash the source disk and the image and the two SHA-256 values match exactly. What does that prove?
Mount it read-only: losetup + mount -o ro
Attach the image through a loopback device and mount it so analysis can never write to it.
Now you want to browse the image's filesystem with normal tools — but a normal
mountmakes it writable, and the moment a filesystem is mounted read-write the kernel may write to it: updating access times, and worse, replaying the journal. Your job is to mount it so that physically nothing can change.An image is a file, not a block device, so first you wrap it in a loopback device with
losetup— that exposes/evidence/case42.imgas a fake disk like/dev/loop0(with-Pit even exposes its partitions as/dev/loop0p1, etc.). Then youmountthat loop device with the write-protection flags:ro(read-only), and for journaled filesystemsnoload/norecoveryso the kernel does not replay the journal.Example — not runnable on your lab box
sudo losetup -fP --show /evidence/case42.img/dev/loop0
- -f
- Find the first FREE loop device automatically instead of you guessing /dev/loopN.
- -P
- Scan the image's partition table and expose each partition as /dev/loop0p1, /dev/loop0p2, …
- --show
- Print the loop device name that was allocated (here /dev/loop0) so you know what to mount.
The image file is now backed by the block device `/dev/loop0` — Linux treats it as a disk. If case42.imgwas a whole-device image with partitions, you'd now also have/dev/loop0p1,/dev/loop0p2, and so on, and you'd mount the partition you care about rather than the whole device. Note:losetupby itself does not write to the image — it just maps it.Example — not runnable on your lab box
sudo mount -o ro,noload,noexec,nodev /dev/loop0 /mnt/evidence- -o ro
- Mount READ-ONLY — the kernel rejects every write to this filesystem.
- noload
- Do NOT replay the ext3/ext4 journal on mount (norecovery is the equivalent for xfs). This is what stops the kernel writing to your evidence.
- noexec
- Disallow executing binaries from the image — don't accidentally run the attacker's malware while browsing it.
- nodev
- Ignore any device nodes on the image — a planted device file can't be used to reach real hardware.
No output means success. The evidence filesystem is now visible under /mnt/evidence, and it is read-only at the kernel level — not by politeness, but enforced.noloadis the subtle hero here: a journaled filesystem that wasn't cleanly unmounted has a dirty journal, and a normal mount would replay it, writing to the disk to finish interrupted transactions.noloadtells the kernel to skip that replay, so mounting changes nothing.mount | grep loop0/dev/loop0 on /mnt/evidence type ext4 (ro,noexec,nodev,relatime)
Always verify the mount is actually read-only — don't assume. The (ro,...)in the options is the confirmation:rois present, so writes are blocked. If you ever seerwhere, stop and remount; something is exposing the evidence to modification. The real test is the next step: try to write and watch it fail.Check yourself
Why add noload (or norecovery) when read-only mounting a seized ext4/xfs image, on top of ro?
Try it in your live terminal
Run the full image → hash → loopback → read-only → verify → clean-up workflow yourself.
You have a real root shell. We'll rehearse the entire acquisition workflow on a small, throwaway file-backed image — no real disk involved, fully reversible. You'll create an 8 MiB image, put a filesystem on it, hash it, attach it as a loopback device, mount it strictly read-only, prove the read-only protection by watching a write fail, then tear it all down. This is the same sequence of moves you'd run on a real case; only the source (a tiny file instead of
/dev/sdb) is different.Run the blocks in order.
dd if=/dev/zero of=/tmp/et.img bs=1M count=8 status=progressCreate an 8 MiB image file full of zeros — our stand-in for a seized disk. if=/dev/zerois an endless source of zero bytes;bs=1M count=8writes eight 1-MiB blocks. On a real case this would beif=/dev/sdbreading an actual device.mkfs.ext4 -q /tmp/et.imgFormat the image with an ext4 filesystem so there's something real to mount. -qkeeps it quiet. dd doesn't care what's inside the image — we add a filesystem only so the read-only mount step has structure to attach.sha256sum /tmp/et.imgFingerprint the image BEFORE we mount and explore it. Copy this hash somewhere — you'll re-run sha256sum at the end and the value must be unchanged, proving the read-only mount altered nothing. sudo losetup -fP --show /tmp/et.imgWrap the image file in a loopback block device and print its name (e.g. /dev/loop0). -f picks a free loop device; -P would expose partitions if it had any. Note the device name it prints — you'll need it to detach later. Example — not runnable on your lab box
sudo mount -o ro,loop /tmp/et.img /mnt 2>/dev/null || { sudo mkdir -p /mnt/ev && sudo mount -o ro,loop /tmp/et.img /mnt/ev; }Mount the image READ-ONLY. -o ro,looplets mount set up the loop device and apply read-only in one step. The||fallback creates /mnt/ev and mounts there if /mnt is busy — so this works whatever the sandbox layout is. Note which mountpoint succeeded (/mnt or /mnt/ev).mount | grep -E '/mnt(/ev)? 'Verify the mount really is read-only: the options must contain ro. Don't trust that you typed it correctly — confirm the kernel applied it. This is the verification step you always perform on real evidence.Example — not runnable on your lab box
sudo touch /mnt/proof 2>&1 || sudo touch /mnt/ev/proof 2>&1PROVE it's read-only by trying to write. You should get 'Read-only file system' — the kernel physically refusing the write. A failed write here is the success condition: it means analysis tools genuinely cannot alter the evidence. Example — not runnable on your lab box
sudo umount /mnt 2>/dev/null || sudo umount /mnt/ev; sudo losetup -d $(losetup -j /tmp/et.img -O NAME --noheadings); rm -f /tmp/et.img; echo cleanedTear down in reverse order: unmount the filesystem, detach the loop device (losetup -j finds which loop device backs our image, -d detaches it), then delete the throwaway image. Self-contained and reversible — the sandbox is back exactly as it started. On a real case you'd keep the image and its hash, not delete them.
- Never analyze the original. Make a verified bit-for-bit copy, lock the original away, and do all work on the image — provability, not any single tool, is the foundation of DFIR.
dd(or forensicdc3dd/ddrescue) images a whole device or partition raw, capturing unallocated space and deleted data a file copy would miss; tunebs=for speed, useconv=noerror,syncfor failing disks.sha256sumthe source AND the image and compare — matching hashes prove a faithful copy and seal it tamper-evident. Hash again after analysis to prove nothing changed. MD5 is broken; don't seal new evidence with it.- Mount evidence through a loopback (
losetup) withmount -o ro,noload(ornorecovery) so the kernel can't write or replay a dirty journal — then VERIFY read-only by checking the mount options and watching a write fail. - The write-blocking mindset: assume any access can write unless something actively prevents it. Put the read-only protection (software or hardware) in place BEFORE you connect the evidence.
| Step | Command | Guarantees / watch for |
|---|---|---|
| Image the source | dd if=/dev/sdb of=img bs=4M status=progress | Exact raw copy incl. deleted/unallocated data; never swap if=/of= |
| Hash source + image | sha256sum /dev/sdb img | Equal hashes = faithful copy; use SHA-256, not broken MD5 |
| Wrap as loop device | losetup -fP --show img | Exposes the image file as /dev/loopN (and partitions with -P) |
| Mount read-only | mount -o ro,noload loop /mnt | Kernel-enforced no writes; noload stops journal replay |
| Verify read-only | mount | grep loop ; failed touch | Options show ro; a write must fail ('Read-only file system') |
| Re-hash when done | sha256sum img | Same value as before = your analysis altered nothing |
