Python Digital Forensics Cookbook
上QQ阅读APP看书,第一时间看更新

How it works...

First, we import the required libraries to handle argument parsing, parsing dates, and the html_dashboard script we created in the previous recipe:

from __future__ import print_function
import argparse
from datetime import datetime
import os
import sys
import html_dashboard

This recipe's command-line handler takes two positional arguments, INPUT_DIR and OUTPUT_DIR, which represent the path to the directory containing acquisition logs and the desired output path, respectively. After creating the output directory, if necessary, and validating that the input directory exists, we call the main() method and pass these two variables to it:

if __name__ == "__main__":
# Command-line Argument Parser
parser = argparse.ArgumentParser(
description=__description__,
epilog="Developed by {} on {}".format(
", ".join(__authors__), __date__)
)
parser.add_argument("INPUT_DIR", help="Input Directory of Logs")
parser.add_argument("OUTPUT_DIR", help="Desired Output Path")
args = parser.parse_args()

if os.path.exists(args.INPUT_DIR) and os.path.isdir(args.INPUT_DIR):
main(args.INPUT_DIR, args.OUTPUT_DIR)
else:
print("[-] Supplied input directory {} does not exist or is not "
"a file".format(args.INPUT_DIR))
sys.exit(1)

In the main() function, we use the os.listdir() function to get a directory listing of the input directory and identify only those files with a .txt file extension. This is important, as FTK Imager creates acquisition logs with the .txt extension. This helps us avoid some files that should not be processed by the extension alone. We will, however, take it one step further. After we create a list of the possible FTK logs, we create a placeholder list, ftk_data, to store the processed acquisition data. Next, we iterate through each potential log and set up a dictionary with the desired keys we will extract. To further eliminate false positives, we call the validate_ftk() method, which returns either a True or False Boolean value depending on the results of its inspection. Let's take a quick look at how it works:

def main(in_dir, out_dir):
ftk_logs = [x for x in os.listdir(in_dir)
if x.lower().endswith(".txt")]
print("[+] Processing {} potential FTK Imager Logs found in {} "
"directory".format(len(ftk_logs), in_dir))
ftk_data = []
for log in ftk_logs:
log_data = {"e_numb": "", "custodian": "", "type": "",
"date": "", "size": ""}
log_name = os.path.join(in_dir, log)
if validate_ftk(log_name):

Thankfully, each FTK Imager log contains the words "Created by AccessData" on the first line. We can rely on this to be the case to verify that the log is likely a valid FTK Imager log. With the input log_file path, we open the file object and read the first line using the readline() method. With the first line extracted, we check whether the phrase is present and return True if it is or False otherwise:

def validate_ftk(log_file):
with open(log_file) as log:
first_line = log.readline()
if "Created By AccessData" not in first_line:
return False
else:
return True

Back in the main() method, after having validated the FTK Imager log, we open the file, set a few variables to None, and begin iterating through each line in the file. Based on the dependable layout of these logs, we can use specific keywords to identify whether the current line is one we are interested in. For example, if the line contains the phrase "Evidence Number:", we can be sure that this line contains the evidence number value. And in fact, we split the phrase and take the value to the right of the colon and associate it with the dictionary e_numb key. This type of logic can be applied to most of the desired values, with a few exceptions.

For the acquisition time, we must use the datetime.strptime() method to convert the string into an actual datetime object. We must do this to store it in the format that the HTML dashboard is expecting. We use the strftime() method on the datetime object and associate it with the date key in the dictionary:

            with open(log_name) as log_file:
bps, sec_count = (None, None)
for line in log_file:
if "Evidence Number:" in line:
log_data["e_numb"] = line.split(
"Number:")[1].strip()
elif "Notes:" in line:
log_data["custodian"] = line.split(
"Notes:")[1].strip()
elif "Image Type:" in line:
log_data["type"] = line.split("Type:")[1].strip()
elif "Acquisition started:" in line:
acq = line.split("started:")[1].strip()
date = datetime.strptime(
acq, "%a %b %d %H:%M:%S %Y")
log_data["date"] = date.strftime(
"%M/%d/%Y %H:%M:%S")

The bytes per sector and sector count are handled a little differently from the rest. Due to the fact that the HTML dashboard script is expecting to receive the data size (in GB), we need to extract these values and calculate the acquired media size. To do this, once identified, we convert each value into an integer and assign it to the two local variables that were originally None. Once we finish iterating through all lines, we check whether these variables are no longer None, and if they are not, we send them to the calculate_size() method. This method performs the necessary calculation and stores the media size within the dictionary:

def calculate_size(bytes, sectors):
return (bytes * sectors) / (1024**3)

Once the file has been processed, the dictionary with the extracted acquisition data is appended to the ftk_data list. After all the logs have been processed, we call the html_dashboard.process_data() method and supply it with the acquisition data and output directory. The process_data() function is, of course, the exact same as the previous recipe. Therefore, you know that this acquisition data replaces the sample acquisition data of the previous recipe and populates the HTML dashboard with real data:

                    elif "Bytes per Sector:" in line:
bps = int(line.split("Sector:")[1].strip())
elif "Sector Count:" in line:
sec_count = int(
line.split("Count:")[1].strip().replace(
",", "")
)
if bps is not None and sec_count is not None:
log_data["size"] = calculate_size(bps, sec_count)

ftk_data.append(
[log_data["e_numb"], log_data["custodian"],
log_data["type"], log_data["date"], log_data["size"]]
)

print("[+] Creating HTML dashboard based acquisition logs "
"in {}".format(out_dir))
html_dashboard.process_data(ftk_data, out_dir)

When we run this tool, we can see the acquisition log information, as shown in the following two screenshots: