How compatible are KSYSTEM_TIME and FILETIME on Windows?

I’ve been using information from KUSER_SHARED_DATA (useful overview) in various contexts in the past. Some of the first members are of type KSYSTEM_TIME and the way they’re laid out is required due to keep ISRs non-blocking according to this source.

For reference (from wdm.h):

typedef struct _KSYSTEM_TIME {
    ULONG LowPart;
    LONG High1Time;
    LONG High2Time;
} KSYSTEM_TIME, *PKSYSTEM_TIME;

As we can see this is practically equivalent to a LARGE_INTEGER/LONGLONG apart from the second “high” member (for the above mentioned reason).

Alas, FILETIME is (from winbase.h):

typedef struct _FILETIME {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME;

… and therefore all unsigned and for all intents and purposes equivalent to a ULARGE_INTEGER/ULONGLONG.

Now it makes sense that KSYSTEM_TIME can be negative as for the time zone offset (KUSER_SHARED_DATA::TimeZoneBias) but the value range is of course “halved” for the signed version and so it limits compatibility between the structs.

But it begs the question: is it alright to coerce the fields of KSYSTEM_TIME — if known to be a time rather than a time delta — into a FILETIME?

PS: the SYSTEMTIME used by FileTimeToSystemTime/SystemTimeToFileTime corresponds more (conceptually, not 1:1) to TIME_FIELDS struct and is not what the above question is about.

  • 1

    If you disassemble GetSystemTime() or GetSystemTimeAsFileTime() on x64 you will see they read the value into a single 64-bit register, so it should be safe (though not contractually guaranteed) to do so.

    – 

  • @Luke By “not contractually guaranteed” you basically mean I am depending on implementation-defined behavior (as I already do pretty much when using KUSER_SHARED_DATA and the native API), right? Thanks, this helps a lot. I think this is a perfectly acceptable answer (at least to me it would be). I verified it in IDA for GetSystemTimeAsFileTime() and you are of course right.

    – 




Leave a Comment