A brief history of time stamps
IntroductionThere are various methods of recording dates and times on computers and computing devices and as a forensic investigator it is useful to understand the main formats and also to have an understanding of why dates are stored in the way that they are. For those of us who like to delve a little deeper into file formats some familiarity with how these dates ‘look’ in a hex dump can help when reverse engineering a new file format.
During this short discourse I will be presenting screenshots taken using software developed by Sanderson Forensics – RevEnge. RevEnge supports the decoding and display of all of the date formats discussed.
Why the plethora of formats?In order to understand why we have so many date formats it is useful to understand what we are trying to achieve when encoding a date and what the trade off between different methods are.
The encoding used by early date formats was driven by the need to conserve space on disk and as such most dates were encoded using 4 bytes or 32 bits of storage space. This has required certain compromises in the accuracy and or the range of dates that can be encoded, such as the granularity of early MS-DOS dates being restricted to an accuracy of 2 seconds.
A further consideration when designing a date format is the use to which that particular format is to put. For instance if a date is to be used in calculations then it is easier to add (for example) 1 year to a date that has the years recorded in a set number of bits (such as the MS-DOS date) than it is to add a year to say a UNIX date where account would need to be taken of the number of seconds in a given year (see leap years and leap seconds). Some date formats lend themselves to addition and subtraction better than others, i.e. the OLE automation time stores the date as a floating point number with the number of days since 30/12/1899 being the whole number part and the fractional part being the number of seconds since midnight.
The different formats64 bit FileTime
This is the ‘standard’ windows API file time structure and is stored as a 64 bit integer value representing the number of 100 nano second intervals since 01/01/1601[i]. This format is most commonly seen in NTFS MFT entries (there can be up to 20 in one MFT). When looking at Raw hex dates in this format can be recognised by a 64 bit run of data ending (or starting in the case of BigEndian data) with the hex values 01CB, to 01C7.
FileTime data types can be identified in RevEnge by right clicking on the data interpreters window and selecting “FileTime 64 bit” then moving the cursor through the data until a valid date is displayed in the data interpreters window. As there are many possible valid dates some of which (say 10/03/2099 might not be reasonable) RevEnge can be configured to highlight a reasonable valid date (say anything between 1/1/1990 and todays date) in red.
In the screenshot above the date is highlight in green with the first byte highlighted in the red square. As I am sure all readers are aware Microsoft use the LittleEndian storage format for integers (most significant bit first) so the above number would be written in hex 01C7AAC24034F21C, it is the numbers at the right of the date as shown in the hex which “tick over” faster, i.e. the numbers on the right represent the nano-seconds and the numbers on the left the years – hence the use of 01C7 (C701 in the hex above) to visually identify this as a possible date. The pattern of four similar strings also makes me think date especially as I know I am looking at an MFT entry where I would expect to see one or more dates (there are 8 obviously visible above).
Filetime (or file time formatted)
Is a file time as above but represented by two 32 bit integers which when taken together are decoded as above. Typically these formatted FileTimes are seen in email headers and the two halves are separated by a colon or period, an example of such a time stamp taken from an email is:
The visual identifier for this date is again 01CB-01C7 but in this case the identifier is in the second half of the 32 bit integer pairs, although somewhat obviously if the date is within an email it would normally be prefixed by a textual description.
This is similar to the formatted FileTime above but the two 32 bit values are swapped
An example of a HTML file time is shown below
ANSI SQL time
Two 32 bit integers, the first stores the number of days since 17 November 1858[ii], the second integer stores the number of 100 microsecond intervals since midnight
A 64-bit integer value that specifies the number of milliseconds since January 1, 1970
OLE automation date
An 8 byte double precision floating point value. The integral portion is the number of days since 30/12/1899[iii], the fractional part records the fraction of the day (i.e. 0.5 is 12 hours i.e. noon, 0.25 is 6 hours i.e. 6am etc.)
The 32 bit date and time format used in the MSDOS and Windows FAT directory entry. Each portion of the time stamp (year, month etc.) is encoded within specific bits of the 32bit time stamp. The epoch for a DOS date is 1980 so this must be added to the date from bits 25-31. This format has a granularity of 2 seconds and the data is stored as follows:
MSDOS word swapped
This is a date format sometimes seen in tape archives and is the same as the above format with the upper and lower 16 bit words swapped.
Sometimes referred to as C date and time and referenced by the type time_t by programmers, it is stored as a 32 bit integer and records the number of seconds since 1/1/1970[iv].
Unix time 48 bit
The date and time is stored as a 6 byte integer recording the number of milliseconds since 1/1/1970. Seen on Android devices.
As for Unix time but recording the number of seconds since 1/1/1980[v]
The example below shows the same 4 bytes decoded as both a Unix time and an AOL time, as expect the two dates are exactly 10 years apart.
Seconds Since (RevEnge configurable)
A generic form of Unix time added to RevEnge whereby the user can specify the epoch essentially it is the same as Unix or AOL time but the user chooses which date the clock starts counting from. This could conceivably be useful when an investigator is presented with a string of bytes which he/she knows to be a date and has other information informing him of what date the bytes should represent (I determined the GPS time referred to be in just this manner).
Unix decimal 10 byte
The 10 digit decimal representation of the number stored as a 32 bit Unix time, i.e. the date is recorded as a human readable string and is quite common in web based applications. The example below is from FaceBook chat.
Unix decimal 13 byte
As above using 13 digits and using the additional three digits to record the time as millisecond increments from 1/1/1970
Unix times can often be recognised as 10 or 13 digits numbers start with 11 or 12. They are also often prefixed by a textual reference which gives a clue, i.e. in the case of FaceBook the rather obvious string “ClientTime”
Another utility that can be used to decode dates and times is Craig Wilsons excellent DCode program, shown below:
As for Unix time but recording the number of seconds since 6/1/1980[vi]
Again as for Unix time but recording the number of minutes since 1/1/1970
Used in the Macintosh operating systems and records the number of seconds since 1st January 1904[vii] GMT. In HFS this is local time, in HFS+ this is GMT.
Are stored as nibble swapped data using 7 bytes as follows
Decodes as 10/03/2007 10:44:03
The time zone byte represents the number of 15 minute intervals between local time and GMT
Decimal (Nokia S40) format dates
As above but the year can be stored as either a 2 byte little-endian or big-endian integer, there is no time zone information.
Binary Coded Decimal dates
Are stored as Binary Coded Decimal data using 6 bytes as follows
Decodes as 01/03/2007 10:44:03
ISO 8601 dates
A textual date format recording the date as YYYY-MM-DD hh:mm:ss
BitDate (seen on LG and Samsung phones)A rather arbitrary name applied by me before I was aware of the devices on which this date format could be seen.
The date is stored as a 32 bit integer and the different components of the date are specified by different bits within the integer, in a similar manner to a DOS FAT date and time, however there are no seconds recorded by the format.
i.e. the lowest 12 bits specify the year, the next 4 bits the month, then 5 bits each for the day & hour and then the last 6 bits for the minute.
A PDF version of this paper can be downloaded here
RevEnge, software by Sanderson Forensics can decode all of the above date/time formats in a hex dump (or image) and display all of the possible dates that decode under the cursor. You can also search hex for a date that falls in a date range, or even search for dates in any format that fall within a date range.
[i] Chosen because in the Gregorian calendar leap years are every 4 years, years that are divisible by 100 are not leap years unless they are also divisible by 400. 1600 was therefore a leap century and the next was 2000, 1601was the base date in the current (when Windows was devised) 400 year period
[ii] 17/11/1858 is the start of the Modified Julian Day system (used extensively by astronomers) 17/11/1858 is Julian day number 2,400,000.
[iii] Internal date used by Excel, supposedly simplified calculations but erroneously assumes 1900 to be a leap year
[iv] 1234567890 seconds from the Unix epoch was on 23rd February 2009 at 23:31:30 UTC
[v] I have not been able to determine the significance of this date, perhaps it is because Sweden changed the of succession to the throne
[vi] Seen on Motorola V3m mobile phones . GPS originally recorded time as a week number and an offset within the week, week zero was 6/1/1980 and there were 1024 weeks before the GPS system wraps and starts again (it was postulated that GPS navigation might be interrupted on 21st August 1999 – but this did not occur).
[vii] Chosen because 1904 was the first leap year of the 20th Century