In a previous post I made a quick comparison between dd, dc3dd and dcfldd. In this post we go deeper on dcfldd: you will find the commands that I use most during an acquisition, with a short explanation for each one.
See also these posts:
dcfldd
Brief description from the man page:
Enhanced version of dd for forensics and security.
dcfldd was initially developed at the Department of Defense Computer Forensics Lab (DCFL). It works like dd, but it adds hashing on the fly, status output, split output, verification and multiple outputs. The default block size is 32 KiB, while dd uses 512 bytes. For this reason dcfldd is more efficient than dd when you use the default options.
Install dcfldd
On Debian and Ubuntu you can install dcfldd with apt:
sudo apt install dcfldd
Then check the version:
dcfldd --version
I tested all the commands in this post with dcfldd 1.9.1 on Ubuntu 24.04. The outputs come from a test with a source of 256 MB.
Before you start
First of all, find the device that you want to acquire:
lsblk
In the examples the source drive is /dev/sdb and the images go in the /evidence folder. Use the whole device (/dev/sdb) and not a partition (/dev/sdb1). In this way you acquire also the partition table and the unallocated space. If you can, connect the source drive through a write blocker.
1. Create an image and calculate the hash
sudo dcfldd if=/dev/sdb of=/evidence/image.dd hash=sha256
Command explanation:
if=/dev/sdbis the source driveof=/evidence/image.ddis the output filehash=sha256is the hashing algorithm. You can use md5, sha1, sha256, sha384 or sha512
dcfldd shows the progress and, at the end, the hash of the data that it read:
8192 blocks (256Mb) written.
Total (sha256): f4cfd07f8aa5ac68214ac1eb4d2c38684c7dc004ca1d8c0a56173b324108b86a
8192+0 records in
8192+0 records out
Without hash= dcfldd does not calculate any hash, so always add it.
2. Save the hash in a file with hashlog
By default dcfldd writes the hash on the screen. Use hashlog= to save it in a file, so you can attach it to your report:
sudo dcfldd if=/dev/sdb of=/evidence/image.dd hash=sha256 hashlog=/evidence/hash.txt
This is the content of hash.txt:
Total (sha256): f4cfd07f8aa5ac68214ac1eb4d2c38684c7dc004ca1d8c0a56173b324108b86a
You can also calculate more hashes at the same time. Write the algorithms in a list, separated by commas:
sudo dcfldd if=/dev/sdb of=/evidence/image.dd hash=md5,sha256 hashlog=/evidence/hash.txt
Now hash.txt contains both hashes:
Total (md5): 553bc4da76af195b0087cad874d864fd
Total (sha256): f4cfd07f8aa5ac68214ac1eb4d2c38684c7dc004ca1d8c0a56173b324108b86a
If you prefer one file for each algorithm, use md5log=, sha256log= and so on (the format is ALGORITHMlog=):
sudo dcfldd if=/dev/sdb of=/evidence/image.dd hash=md5,sha256 md5log=/evidence/image.md5 sha256log=/evidence/image.sha256
dcfldd reads the source only one time and calculates all the hashes while it copies the data. In this way you don’t need to run md5sum and sha256sum after the acquisition, and with big drives you save a lot of time.
3. Show the percentage
By default dcfldd shows only the number of blocks written. Add sizeprobe=if to see the percentage and the time remaining:
sudo dcfldd if=/dev/sdb of=/evidence/image.dd hash=sha256 sizeprobe=if
sizeprobe=if tells dcfldd to use the size of the input to calculate the percentage. The last lines of the output are similar to these:
[96% of 256Mb] 7936 blocks (248Mb) written. 00:00:00 remaining.
[100% of 256Mb] 8192 blocks (256Mb) written. 00:00:00 remaining.
4. Calculate a hash for each part of the drive (hashwindow)
With hashwindow= dcfldd calculates a hash for every part of the data, and then the total hash. In this example each part is 64 MiB:
sudo dcfldd if=/dev/sdb of=/evidence/image.dd hash=sha256 hashwindow=64M hashlog=/evidence/hashwindow.txt
This is the content of hashwindow.txt:
0 - 67108864: eb539ecf39a98c4116e9ac113c36bab49b892cc49f2e69e80b719c2e89b8709a
67108864 - 134217728: bcb04f9118aa4e7e5d3d41467eb1168b8d041a57a3f8667a9670ef189466b796
134217728 - 201326592: c68e6b4d7d7a4300015b078d6e25140becef370a06a47296d71032f6cc4d4ba5
201326592 - 268435456: 347c5fe8676ef082dc6032664a6a7a0daccbace9f5a4acc7a3cf2d385556598b
Total (sha256): f4cfd07f8aa5ac68214ac1eb4d2c38684c7dc004ca1d8c0a56173b324108b86a
Each line shows the start offset, the end offset (in bytes) and the hash of that part. The partial hashes are useful when you verify the image again: if the total hash does not match, you can find which part of the image changed. You will see an example in the next section.
5. Verify the image
After the acquisition, you can verify that the image matches the source drive. Use vf= with the path of the image:
sudo dcfldd if=/dev/sdb vf=/evidence/image.dd
If the image and the source are the same, the result is:
Total: Match
If they are different, the result is:
0 - 0: Mismatch
Total: Mismatch
Add hashwindow= to find where the difference is. For this test I changed one byte of the image at offset 150000000:
sudo dcfldd if=/dev/sdb vf=/evidence/image.dd hashwindow=64M
134217728 - 201326592: Mismatch
Total: Mismatch
Now we know that the difference is in the part between byte 134217728 and byte 201326592.
Note about verifylog: the man page says that verifylog= sends the result to a file. In my tests with dcfldd 1.9.1 the file was created but it was empty, and the result was still on the screen. For this reason I save the result with a redirect of stderr:
sudo dcfldd if=/dev/sdb vf=/evidence/image.dd status=off 2> /evidence/verify.txt
Please note also that dcfldd returns exit code 0 also when the result is Mismatch. If you use dcfldd in a script, check the text and not the exit code:
grep -q "Total: Match" /evidence/verify.txt && echo "Image verified" || echo "Image NOT verified"
6. Split the image
Sometimes you need smaller files, for example to copy the image to a FAT32 disk, where the maximum file size is 4 GB. Use split=:
sudo dcfldd if=/dev/sdb hash=sha256 hashlog=/evidence/hash.txt split=2G of=/evidence/image.dd
Please note that split= must be before of=. If you put it after of=, dcfldd creates only one file.
dcfldd adds a number to the name of each file. In my test, with a source of 256 MB and split=100M, the result is:
image.dd.000
image.dd.001
image.dd.002
The hash in hash.txt is the hash of all the data, not of each file. To check it, join the files and calculate the hash again:
cat /evidence/image.dd.* | sha256sum
f4cfd07f8aa5ac68214ac1eb4d2c38684c7dc004ca1d8c0a56173b324108b86a -
If you prefer the extensions .001, .002, .003 that many Windows tools use, add splitformat=WIN:
sudo dcfldd if=/dev/sdb hash=sha256 hashlog=/evidence/hash.txt split=2G splitformat=WIN of=/evidence/image.dd
7. Write two copies at the same time
You can use of= more than one time. dcfldd reads the source one time and writes all the copies. For example, one copy for the analysis and one copy for the archive:
sudo dcfldd if=/dev/sdb hash=sha256 hashlog=/evidence/hash.txt of=/evidence/image.dd of=/mnt/archive/image.dd
8. Drives with read errors
If the source drive has bad sectors, add conv=noerror,sync. With these options dcfldd continues after a read error and writes zeros in place of the data that it cannot read. Use errlog= to save the errors in a file:
sudo dcfldd if=/dev/sdb of=/evidence/image.dd bs=4096 conv=noerror,sync hash=sha256 hashconv=after hashlog=/evidence/hash.txt errlog=/evidence/errors.txt
With damaged drives, always add bs=4096 and hashconv=after. In my speed and reliability test, with the default block size (32 KiB) dcfldd created an image with the data at the wrong offset after a bad sector. Without hashconv=after, the hash in the log is not the hash of the image file. For drives in bad condition, ddrescue is a better choice.
Quick reference
| Option | What it does |
|---|---|
hash=sha256 | Calculates the hash while it copies the data (md5, sha1, sha256, sha384, sha512) |
hashlog=FILE | Saves the hashes in a file |
md5log=FILE, sha256log=FILE | Saves the hash of one algorithm in its own file |
hashwindow=64M | Calculates a hash for every 64 MiB of data |
sizeprobe=if | Shows the percentage and the time remaining |
vf=FILE | Verifies that FILE matches the source |
split=2G | Splits the output in files of 2 GiB (put it before of=) |
splitformat=WIN | Uses .001, .002, .003 as extensions |
of=FILE (more times) | Writes more copies at the same time |
conv=noerror,sync | Continues after read errors and writes zeros in place of the bad data |
hashconv=after | Calculates the hash on the data written in the image (use it with conv=noerror,sync) |
errlog=FILE | Saves the error messages in a file |
If you use other dcfldd options in your acquisitions, please share them in the comment box!
Leave a Reply