In this post, I will not tackle decoding hexadecimal time stamps to human readable form. Instead, I will focus on another issue: “it is recorded in seconds” from what starting point?
Epochs
Think of an epoch as a line in the sand, if you will, a starting point. Unix-like systems use ‘unixepoch’ time as their start point, which is 1970-01-01. Windows systems use “Windows Time”, or 1601-01-01 and Macs have for some time used Mac Absolute Time, or 2001-01-01. So, as you can see, time is a matter of perspective, but not limited to the operating system. Application programmers can choose any epoch they wish (Webkit Time, GPS Time, etc.) and it is not uncommon to find many different epochs in use on a single device. Experienced examiners readily recognize some time formats based on their length and starting values, but none can do the conversion to a human readable format without programming assistance.Converting time stamps
I recently was tasked with creating a super timeline of data from many different devices, mostly computers and mobile phones. Most of the data was stored in SQLite databases, but the automated tools in my arsenal did auto-process all of the databases of interest. I used a graphical SQLite Browser to study the databases and experiment with queries until I could export the evidentiary content, and I then used python to extract the data into a format from which I could synthesize the timeline. The chief problem was that I had several different time formats, meaning they used different epochs, and SQLite only understands unixepoch. While it is still possible to convert non-unixepoch time stamps in SQLite (i.e. adding or subtracting the difference between the foreign epoch and unixepoch), it is clunky and requires a little research and initial calculation to be successful.The Pythonic Way
I wanted a simple function that would take an epoch and a time stamp as arguments, and then return a human readable format for inclusion in the timeline. In that way, it could flex depending on the format of the data source.def convert_ts(epoch, ts):
'''(str, int) --> str
Takes a timestamp (ts) in seconds and returns a human readable format
based on a provided epoch. Times are UTC.
>>> convert_ts('1970-01-01', 0)
'1970-01-01 00:00:00'
>>> convert_ts('1970-01-01', 1493750183)
'2017-05-02 18:36:23'
>>> convert_ts('2001-01-01', 515442983)
'2017-05-02 18:36:23' '''
delta = datetime.datetime.strptime(epoch, "%Y-%m-%d")
conversion = delta + datetime.timedelta(seconds=ts)
return conversion.strftime("%Y-%m-%d %H:%M:%S")
Application of the function is quite simple, as you can see from the sample execution in the comments of the function. But I’ll quickly demonstrate how a dictionary and the function could be used to evaluate unknown time stamps.>>> epochs = {
... 'win': '1601-01-01',
... 'unx': '1970-01-01',
... 'mac': '2001-01-01'}
>>> for item in epochs:
... epoch = epochs.get(item)
... print(epoch, convert_ts(epoch, 1493750183))
unx 2017-05-02 18:36:23
win 1648-05-02 18:36:23
mac 2048-05-02 18:36:23
As you can see, the time stamp is evaluated by all three epochs in the dictionary and printed to the terminal. The examiner can look at the dates and consider them in the context of the data source and and determine that the datestamp is likely unixepoch if the other dates make no sense. The dictionary could grow to evaluate as many timestamps as required.The chief point here is that a time stamp has no meaning without the context of its epoch time. The python function is just a simple demonstration of a flexible way to change epochs and evaluate time stamps.