Hello Reader!

This weeks script is a continuation of the week twenty three script that’s parsing the LNK file header.  It’s a short one this week, but we’re working on the ShowCommand portion of the header at file offset 60.  The Microsoft documentation describes this portion as:

“A 32-bit unsigned integer that specifies the expected window state of an application launched by the link.”

Now the values for this are different if you look at the Microsoft documentation versus the documentation written up by Joachim Metz.  For this part of the code I went with the official Microsoft docs, but it’s a trivial matter to modify the code to use the information from Joachim.  The overall difference is the number of identifiers this value represents.

The first part of the code is the function that parses the four bytes of data.  It compares the value with three possible outcomes.  The second part of the code replaces line 53 of the original week 23 script, which just prints out the return value from the function.

Like I said it’s a short one this week!

https://github.com/CdtDelta/YOP


Hello reader!

Today we come to part three of our Windows LNK File Header parsing script, which began with the YOP – Week 23 script.

For this weeks snippet, we’re looking at a function to parse out the attributes of the target file that the lnk file points to, and again we’ll be making use of the bitstring module to parse out the individual bit values for this section.  Now the attribute itself is four bytes in length, starting at file offset 24.

First up is the function, lnk_attrib, which creates a dictionary that refers to the different values depending on which bit flag is set.  Then, in the second part of the function, we parse out the bit values, and if we see a “1”, we print out that the corresponding bit value is set.

The second part is where we pull in the byte values, and then pull out the individual bit values of those bytes.

Finally in the third part, we pass the bit values to the lnk_attrib function, and print the results.

Overall not too different from last weeks script, we’re just looking at a different dictionary.

Until next week!

https://github.com/CdtDelta/YOP


Hello Reader!

This week we’re going to continue working on our LNK File Parser script.  We have two things we’ll be adding this week to how we are parsing the header portion of a LNK file.  If you look at last weeks post, there were some sections that we were just printing out the data to make sure it was there.

First, we need to add some additional modules to our script.  First is the UUID module so we can parse out the Link CLSID correctly.  Second is the BitArray module, which we’ll need to parse out the Link Flags and the File Attributes.

Now this week we introduce a new function, called lnk_flags, which handles the Link Flags.  What I’m doing here is taking this four byte value, and we parse out the individual bits.  Each bit refers to a flag that’s been set.  So I’m looking at which flag is set to a one, and we print out what the corresponding bit refers to.

The second item to mention is we take the 16 byte LinkCLSID value, and then pass it to the UUID module to get the correct output.

And finally we just updated our print statements to show the correct output.

Next week we’ll look at another function I created to parse out some other header data.

Until then!

https://github.com/CdtDelta/YOP


Hello Reader!

Unfortunately this weeks post will be short.  I haven’t had a lot of time to work on my code this week.  There have been some “real life” issues that have been tying up my free time.

But what I have been working on is starting to parse out the header for Windows Shortcut (LNK) files.  However it’s still a work in progress, so I’ve put up what I’ve been able to do so far.  There are some areas that I still need to work on so the data appears correctly.  I’m hoping to work on that part this week.

So until next week!

https://github.com/CdtDelta/YOP


Hello Reader!

So my original thought for this week’s script was to start parsing Windows LNK files.  I needed some time with the Prefetch script to put together a Windows 8 image to finish testing it with (I have a VM somewhere just need to find it…which shows you how much I’ve used it).  I got some of the basics started on my script when my friend David Nides tweeted:

And I figured, what the heck, I’ll give it a shot….

Unfortunately I had some other “life events” going on (nothing bad, just a deadline to meet), so it limited the work I’ve done so far to just parsing out the header information.  And even that isn’t 100% complete.  So consider this script the raw data output from the header of a Windows ESE DB, but hey it gets you started!

As part of my regular strategy on parsing these file types, I start by just reading in the header portion of the file.  Then I pass it to the main function that will break everything out.  However from reading through Joachim Metz’s documentation that he did (which as always is excellent and thorough), I decided to break out some other pieces of the puzzle in to other functions.

The first one is the Backup Information (JET_BKINFO), which I will admit is not complete yet:

def edb_backup_parse(bkup_data):
    bkup_pos = struct.unpack("<Q", bkup_data[0:8])
    bkup_create_datetime = struct.unpack("<Q", bkup_data[8:16])
    bkup_gen_lwr_no = struct.unpack("<L", bkup_data[16:20])
    bkup_gen_upr_no = struct.unpack("<L", bkup_data[20:24])
    return bkup_pos[0], bkup_create_datetime[0], bkup_gen_lwr_no[0], bkup_gen_upr_no[0]

This is phase one of this function, I need to break down the data further (for example parse out the date/time data that’s there), but it’s enough to tell that there’s data there at least.

Next up is my Log Time (JET_LOGTIME and JET_BKLOGTIME) function:

def log_time(time_data):
    log_sec = struct.unpack("<B", time_data[0])
    log_min = struct.unpack("<B", time_data[1])
    log_hour = struct.unpack("<B", time_data[2])
    log_day = struct.unpack("<B", time_data[3])
    log_mon = struct.unpack("<B", time_data[4])
    log_year = struct.unpack("<B", time_data[5])
    return log_sec[0], log_min[0], log_hour[0], log_day[0], log_mon[0], (log_year[0] + 1900)

This just takes care of the time stamps for the log time data structures.

Finally is the last function, Database Time

def db_time(time_data):
    db_hours = struct.unpack("<H", time_data[0:2])
    db_min = struct.unpack("<H", time_data[2:4])
    db_sec = struct.unpack("<H", time_data[4:6])
    return db_hours[0], db_min[0], db_sec[0]

This one is definitely not complete, or at least my test data has the format wrong.  But the placeholder is here for me to get it working.

I plan on moving forward on this, and I’ve added to the list of things to get parsed out as this year goes on.  So keep an eye out for updates to this script before the year is out!

Until next week!

https://github.com/CdtDelta/YOP


Hello Reader!

This week I was working on updates to the Prefetch File script I began last week.  I’m starting to work on parsing out the file information data for the prefetch file.  It’s not complete, but there’s enough for now to post for this week.

First lets talk about the changes.  The prefetch_format function is first:

def prefetch_format(format_type):
    if format_type == "0x11":
        return "Windows XP"
    elif format_type == "0x17":
        return "Windows 7"
    elif format_type == "0x1a":
        return "Windows 8"
    return

Last week I was just printing out what OS the format was in.  This time around we’re going to use the data from the function to figure out what type of file we’re dealing with.  The parse it out accordingly.

The second change was when we read in the prefetch file to process it:

with open(args.prefetch_file, 'rb') as prefetch:
    prefetch_file = prefetch.read()
    prefetch_header = prefetch_file[:84]
    windows_os = prefetch_header_parse(prefetch_header)
    if windows_os == "Windows XP":
        file_info = prefetch_file[84:152]
        winxp_file_info(file_info)
    elif windows_os == "Windows 7":
        file_info = prefetch_file[84:240]
        win7_file_info(file_info)
    elif windows_os == "Windows 8":
        file_info = prefetch_file[84:308]
        win8_file_info(file_info)

So here’s where we are taking the return value from the prefetch_format function, and then figuring out which os function to pass it to.  This leads us to two new functions of code:

def winxp_file_info(file_info):
    metrics_offset = struct.unpack("<L", file_info[0:4])
    no_metrics = struct.unpack("<L", file_info[4:8])
    trace_chains = struct.unpack("<L", file_info[8:12])
    no_trace_chains = struct.unpack("<L", file_info[12:16])
    filename_str_offset = struct.unpack("<L", file_info[16:20])
    filename_str_size = struct.unpack("<L", file_info[20:24])
    volume_info = struct.unpack("<L", file_info[24:28])
    no_volumes = struct.unpack("<L", file_info[28:32])
    volume_info_size = struct.unpack("<L", file_info[32:36])
    last_run_time = struct.unpack("<Q", file_info[36:44])
    run_count = struct.unpack("<L", file_info[60:64])
    print "Metrics Array Offset: {}".format(hex(metrics_offset[0]))
    print "No. of Metrics: {}".format(no_metrics[0])
    print "Trace Chains Offset: {}".format(trace_chains[0])
    print "No. of Trace Chains: {}".format(no_trace_chains[0])
    print "Filename String Offset: {}".format(filename_str_offset[0])
    print "Filename String Size: {}".format(filename_str_size[0])
    print "Volume Info: {}".format(volume_info[0])
    print "No. of Volumes: {}".format(no_volumes[0])
    print "Volume Info Size: {}".format(volume_info_size[0])
    print "Last Run Time: {}".format(last_run_time[0])
    print "Run Count: {}".format(run_count[0])
    return

def win7_file_info(file_info):
    metrics_offset = struct.unpack("<L", file_info[0:4])
    no_metrics = struct.unpack("<L", file_info[4:8])
    trace_chains = struct.unpack("<L", file_info[8:12])
    no_trace_chains = struct.unpack("<L", file_info[12:16])
    filename_str_offset = struct.unpack("<L", file_info[16:20])
    filename_str_size = struct.unpack("<L", file_info[20:24])
    volume_info = struct.unpack("<L", file_info[24:28])
    no_volumes = struct.unpack("<L", file_info[28:32])
    volume_info_size = struct.unpack("<L", file_info[32:36])
    last_run_time = struct.unpack("<Q", file_info[44:52])
    run_count = struct.unpack("<L", file_info[68:72])
    print "Metrics Array Offset: {}".format(hex(metrics_offset[0]))
    print "No. of Metrics: {}".format(no_metrics[0])
    print "Trace Chains Offset: {}".format(trace_chains[0])
    print "No. of Trace Chains: {}".format(no_trace_chains[0])
    print "Filename String Offset: {}".format(filename_str_offset[0])
    print "Filename String Size: {}".format(filename_str_size[0])
    print "Volume Info: {}".format(volume_info[0])
    print "No. of Volumes: {}".format(no_volumes[0])
    print "Volume Info Size: {}".format(volume_info_size[0])
    print "Last Run Time: {}".format(last_run_time[0])
    print "Run Count: {}".format(run_count[0])
    return

So basically what I’m doing in these two functions is parsing out the file info data from the prefetch file of either Windows XP or Windows 7.  I’m still working on the Windows 8 functions, since that has a bit more data.

I also stumbled across the python Construct module which is what plaso uses to parse out this same information with log2timeline.  I’ve been playing around with rewriting some of this data with that module as well.  I may have that show up in future YOP entries.

Until next week!

https://github.com/CdtDelta/YOP


Hello Reader!

This week I’m going back to parsing Windows artifacts.  The first one I’ve decided to tackle are Prefetch files.  For those of you who are not familiar with Prefetch files, you can check out this link for more information.

So far all this script does is parse thee header information of the Prefetch files, which is only 84 bytes long.  I’ve started working on parsing the rest of the data, but it’s not ready yet.  The format of the script is simple:

yop-week20.py -f <prefetch file>

And that’s it.  The script reads in the first 84 bytes of the file, and then passes it to a function to parse out the individual information.

Now there are some parts of the code I still need to tweak.  First is the ability to output to a CSV file.  I’ve been playing around with the Python CSV module, so look for the ability to output to that format in later scripts.  The second part I need to fix is prefetch_header_file_name variable.  Since the contents of this can vary in size, I need to figure out how to determine the end of the file name (I’m sure someone will contact me online within 5 minutes of posting this :)  ).

The Prefetch file has one part that’s unique, in that depending on the version of Windows, the data after the header portion can vary.  I’m choosing to handle it by using a different function depending on the version of Windows I need to work with.  This function will take care of that:

def prefetch_format(format_type):
    if format_type == "0x11":
        print "Windows XP/2003"
    elif format_type == "0x17":
        print "Windows Vista/7"
    elif format_type == "0x1a":
        print "Windows 8.1"
    return

Right now this is just printing out the version of Windows.  However the current version I’m working on now will parse out the file version based on which version of Windows we’re dealing with.  That should show up in a later YOP.

Until next week!

https://github.com/CdtDelta/YOP




Follow

Get every new post delivered to your Inbox.