How it works...

We import a number of libraries to assist with argument parsing, handling evidence containers and filesystems, and creating tabular console data.

from __future__ import print_function
import argparse
import os
import pytsk3
import pyewf
import sys
from tabulate import tabulate

This recipe's command-line handler takes two positional arguments, EVIDENCE_FILE and TYPE, which represent the path to the evidence file and the type of evidence file. Additionally, if the user is experiencing difficulties with the evidence file, they can use the optional p switch to manually supply the partition. This switch should not be necessary for the most part but has been added as a precaution. After performing input validation checks, we pass the three arguments to the main() function.

if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=__description__,
epilog="Developed by {} on {}".format(
", ".join(__authors__), __date__)
)
parser.add_argument("EVIDENCE_FILE", help="Evidence file path")
parser.add_argument("TYPE", help="Type of Evidence",
choices=("raw", "ewf"))
parser.add_argument("-p", help="Partition Type",
choices=("DOS", "GPT", "MAC", "SUN"))
args = parser.parse_args()

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

The main() function is substantially similar, at least initially, to the previous recipe. We must first create the pyewf handle and then use the EWFImgInfo class to create, as shown previously in the pytsk3 handle. If you would like to learn more about the EWFImgInfo class, refer to the Opening Acquisitions recipe. However, note that we have added an additional line calling the e01_metadata() function to print E01 metadata to the console. Let's explore that function now.

def main(image, img_type, part_type):
print("[+] Opening {}".format(image))
if img_type == "ewf":
try:
filenames = pyewf.glob(image)
except IOError:
print("[-] Invalid EWF format: {}".format(e))
sys.exit(2)

ewf_handle = pyewf.handle()
ewf_handle.open(filenames)
e01_metadata(ewf_handle)

# Open PYTSK3 handle on EWF Image
img_info = EWFImgInfo(ewf_handle)
else:
img_info = pytsk3.Img_Info(image)

The e01_metadata() function primarily relies on the get_header_values() and get_hash_values() methods to acquire E01-specific metadata. The get_header_values() method returns a dictionary of key-value pairs for various types of acquisition and media metadata. We use a loop to iterate through this dictionary and print the key-value pairs to the console.

Similarly, we use a loop with the hashes dictionary to print stored acquisition hashes of the image to the console. Lastly, we call an attribute and a few functions to print acquisition size metadata.

def e01_metadata(e01_image):
print(" EWF Acquisition Metadata")
print("-" * 20)
headers = e01_image.get_header_values()
hashes = e01_image.get_hash_values()
for k in headers:
print("{}: {}".format(k, headers[k]))
for h in hashes:
print("Acquisition {}: {}".format(h, hashes[h]))
print("Bytes per Sector: {}".format(e01_image.bytes_per_sector))
print("Number of Sectors: {}".format(
e01_image.get_number_of_sectors()))
print("Total Size: {}".format(e01_image.get_media_size()))

With that covered, we can now return to the main() function. Recall that in the first recipe of this chapter, we did not create support for physical acquisitions (which was totally on purpose). Now, however, we add that support in using the Volume_Info() function. While pytsk3 can be daunting at first, appreciate the consistency in naming conventions used in the major functions we have introduced so far: Img_Info, FS_Info, and Volume_Info. These three functions are vital in order to access the contents of the evidence container. In this recipe, we will not be using the FS_Info() function as the purpose here is to only print out the partition table.

We attempt to access the volume info in a try-except block. First, we check if the p switch was supplied by the user and, if so, assign the attribute for that partition type to a variable. Then we supply that, along with the pytsk3 handle, in the Volume_Info method. Otherwise, if no partition was specified, we call the Volume_Info method and supply it with just the pytsk3 handle object. If we receive an IOError attempting to do this, we catch the exception as e and print it to the console before exiting. If we are able to access the volume info, we pass this onto the part_metadata() function to print the partition data to the console.

    try:
if part_type is not None:
attr_id = getattr(pytsk3, "TSK_VS_TYPE_" + part_type)
volume = pytsk3.Volume_Info(img_info, attr_id)
else:
volume = pytsk3.Volume_Info(img_info)
except IOError:
_, e, _ = sys.exc_info()
print("[-] Unable to read partition table: {}".format(e))
sys.exit(3)
part_metadata(volume)

The part_metadata() function is relatively light on logic. We create a nested list structure, as seen in the previous recipe, with the first element representing the eventual table header. Next, we iterate through the volume object and append the partition address, type, offset, and length to the table list. Once we have iterated through the partitions, we use tabulate to print a table of this data to the console using firstrow as the table header.

def part_metadata(vol):
table = [["Index", "Type", "Offset Start (Sectors)",
"Length (Sectors)"]]
for part in vol:
table.append([part.addr, part.desc.decode("utf-8"), part.start,
part.len])
print(" Partition Metadata")
print("-" * 20)
print(tabulate(table, headers="firstrow"))

When running this code, we can review information about the acquisition and partition information in the console, if present:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.47.221