Search notes:

Windows: set date in process (faketime for Windows)

This is the source code for a simple Windows tool that uses Detours to start a process and hook the WinAPI functions GetLocalTime and GetSystemTime in order to make the started process run under a given time.
Thus, this utility is a an approximation of the shell command faketime that is found in Linux distributions.
The process is started in a command line (cmd.exe or PowerShell) like so:
C:\Users\rene> setDate 2001-02-03 04:05:06 path-and-or-name-of.exe
For example, if path-and-or-name-of.exe is cmd.exe, the time or date is now changed to the given values:
C:\Users\rene> echo %TIME%
4:05:06.00
C:\Users\rene> echo %DATE%
2001-02-03

Compilation

I compiled the program with MinGW-w64 using this Makefile.

TODO

There are a number of other WinAPI functions that return a date or time that also should be hooked:
If this tool is used to start a process that in turn starts another (child-) process, the child process does not «inherit» the time. Therefore, the tool should probably also hook CreateProcess so that the started process injects the hooking DLL also into the child-process.

setDate.c

#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include "setDate.h"

int main(int argc, char* argv[]) {

   if (argc < 2) {
      printf("specify executable\n");
      return 1;
   }

   STARTUPINFO         si; ZeroMemory(&si, sizeof(si));
   PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi));

   si.cb = sizeof(si);
   si.dwFlags = STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_SHOW;


   char* dllPath = malloc(MAX_PATH);
   char* cp = dllPath + GetModuleFileName(NULL, dllPath, MAX_PATH);
   while (*--cp != '\\');
   memcpy (cp+1, "setDate.dll\x00", 12);

   char* lpCommandLine = GetCommandLine();

   lpCommandLine += strlen(argv[0]) + 2; // Skip program name plus 2 apostrophes in which it is enclosed.
   printf(lpCommandLine);
   printf("\n");

   while (*++lpCommandLine == ' ');

   SYSTEMTIME fake_SYSTEMTIME;

   *(lpCommandLine + 4) = 0; fake_SYSTEMTIME.wYear         = atoi(lpCommandLine); lpCommandLine += 5;
   *(lpCommandLine + 2) = 0; fake_SYSTEMTIME.wMonth        = atoi(lpCommandLine); lpCommandLine += 3;
   *(lpCommandLine + 2) = 0; fake_SYSTEMTIME.wDay          = atoi(lpCommandLine); lpCommandLine += 3;
   *(lpCommandLine + 2) = 0; fake_SYSTEMTIME.wHour         = atoi(lpCommandLine); lpCommandLine += 3;
   *(lpCommandLine + 2) = 0; fake_SYSTEMTIME.wMinute       = atoi(lpCommandLine); lpCommandLine += 3;
   *(lpCommandLine + 2) = 0; fake_SYSTEMTIME.wSecond       = atoi(lpCommandLine); lpCommandLine += 3;
                             fake_SYSTEMTIME.wDayOfWeek    = 0;  // Hah. How am I supposed to know?
                             fake_SYSTEMTIME.wMilliseconds = 0;  // Granularity of one second is enough for everyone...

   while (*lpCommandLine == ' ') lpCommandLine++;

   if (! DetourCreateProcessWithDllEx (
       0                           , // LPCTSTR                         appName
       lpCommandLine               , // LPTSTR                          lpCommandLine,
       0                           , // LPSECURITY_ATTRIBUTES           lpProcessAttributes,
       0                           , // LPSECURITY_ATTRIBUTES           lpThreadAttributes,
       0                           , // BOOL                            bInheritHandles,
       CREATE_DEFAULT_ERROR_MODE |
       CREATE_SUSPENDED            , // DWORD                           dwCreationFlags,
       0                           , // LPVOID                          lpEnvironment,
       0                           , // LPCTSTR                         lpCurrentDirectory,
      &si                          , // LPSTARTUPINFOW                  lpStartupInfo,
      &pi                          , // LPPROCESS_INFORMATION           lpProcessInformation,
       dllPath                     , // LPCSTR                          lpDllName
       0                             // PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW
   )) {

     printf("Failed.\n");
     exit(-1);

   }

   free(dllPath);

// https://github.com/microsoft/Detours/blob/master/samples/tracebld/tracebld.cpp
   if (!DetourCopyPayloadToProcess(
          pi.hProcess,
         &payload,
         &fake_SYSTEMTIME,
         sizeof(SYSTEMTIME))
      ) {

       printf("failed copy payload\n");
       return 1;
    }


    ResumeThread(pi.hThread);

    WaitForSingleObject(pi.hProcess, INFINITE);

    CloseHandle(&si);
    CloseHandle(&pi);

    return 0;
}
Github repository set-date-in-windows-process, path: /setDate.c

hooks.c

#include <windows.h>
#include "detours.h"
#include "setDate.h"

typedef void     (WINAPI  *GetSystemTime_func                 )(LPSYSTEMTIME  );
typedef void     (WINAPI  *GetLocalTime_func                  )(LPSYSTEMTIME  );

GetSystemTime_func GetSystemTime_real;
GetLocalTime_func  GetLocalTime_real ;

LPSYSTEMTIME       pFakeLocalTime = 0;
  SYSTEMTIME        fakeUniversalTime;

void WINAPI   GetSystemTime_hook (LPSYSTEMTIME t) {
   CopyMemory(t, &fakeUniversalTime, sizeof(SYSTEMTIME));
}

void WINAPI   GetLocalTime_hook  (LPSYSTEMTIME t) {
   CopyMemory(t, pFakeLocalTime, sizeof(SYSTEMTIME));
}


int attach(PVOID func, PVOID* real, PVOID hook) {

  *real = func;
  
   LONG dar;

   if ( (dar = DetourAttach(real, hook)) != NO_ERROR ) {
      return 0; 
   }

   return 1;
}


BOOL WINAPI DllMain(HINSTANCE i, DWORD dwReason, LPVOID l) {

   switch ( dwReason ) {

      case DLL_PROCESS_ATTACH: {

         for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
             ULONG cbData;
             PVOID pvData = DetourFindPayload(hMod, &payload, &cbData);
       
             if (pvData != NULL) {
                 pFakeLocalTime = (LPSYSTEMTIME) pvData;

                 TzSpecificLocalTimeToSystemTime(0, pFakeLocalTime , &fakeUniversalTime);
       
              //
              // MSDN: Do not cast a pointer to a FILETIME structure to either a
              // ULARGE_INTEGER* or __int64* value because it can cause alignment
              // faults on 64-bit Windows.
              //
              // fakeLargeIntger.LowPart  = fakeFiletime.dwLowDateTime;
              // fakeLargeIntger.HighPart = fakeFiletime.dwHighDateTime;
       
             }
         }


         if (DetourTransactionBegin() != NO_ERROR) {
            return FALSE; 
         }

         if (  DetourUpdateThread( GetCurrentThread()) != NO_ERROR ) {
            return FALSE; 
         }

         HMODULE kernelBase = GetModuleHandle("kernelbase.dll");
         GetSystemTime_func GetSystemTime_ = (GetSystemTime_func) GetProcAddress(kernelBase, "GetSystemTime");
         GetLocalTime_func  GetLocalTime_  = (GetLocalTime_func ) GetProcAddress(kernelBase, "GetLocalTime" );

         attach((PVOID) GetSystemTime_                , (PVOID*) &GetSystemTime_real                 , (PVOID) GetSystemTime_hook                 );
         attach((PVOID) GetLocalTime_                 , (PVOID*) &GetLocalTime_real                  , (PVOID) GetLocalTime_hook                  );
         if ( DetourTransactionCommit() != NO_ERROR) {
            return FALSE; 
         }
         break;
      }
      case DLL_PROCESS_DETACH: {

         DetourTransactionBegin();
         DetourUpdateThread( GetCurrentThread() );
         
         DetourTransactionCommit(); 
      }
      break;
   }

   return TRUE;
}
Github repository set-date-in-windows-process, path: /hooks.c

setDate.h

const GUID payload = {
    0xcb190af8, 0x5dc7, 0x461d, {0xb9, 0x07, 0x87, 0x6a, 0x8d, 0x15, 0x61, 0x42}
};
Github repository set-date-in-windows-process, path: /setDate.h

Makefile

DETOURS_SRC=Detours/src

all: setDate.dll setDate.exe

setDate.dll:  hooks.o Detours.o disasm.o modules.o
	g++ -shared hooks.o Detours.o disasm.o modules.o -lntdll     -o setDate.dll

setDate.exe: setDate.o creatwth.o Detours.o disasm.o modules.o
	g++        setDate.o creatwth.o Detours.o disasm.o modules.o -o setDate.exe

hooks.o : hooks.c setDate.h
	gcc -I$(DETOURS_SRC) -std=c99 -c hooks.c

Detours.o : $(DETOURS_SRC)/Detours.cpp
	g++ -I$(DETOURS_SRC) -c $(DETOURS_SRC)/Detours.cpp

disasm.o : $(DETOURS_SRC)/disasm.cpp
	g++ -I$(DETOURS_SRC) -c $(DETOURS_SRC)/disasm.cpp

modules.o : $(DETOURS_SRC)/modules.cpp
	g++ -I$(DETOURS_SRC) -c $(DETOURS_SRC)/modules.cpp

creatwth.o : $(DETOURS_SRC)/creatwth.cpp
	g++ -I$(DETOURS_SRC) -c $(DETOURS_SRC)/creatwth.cpp

setDate.o: setDate.c setDate.h
	gcc -I$(DETOURS_SRC) -c setDate.c

# test-target.exe: test-target.o
# 	gcc target.o -o test-target.exe
Github repository set-date-in-windows-process, path: /Makefile

History

2021-11-30 Makefile: Add compiler option -std=c99 to compile hooks.c in order to be able to compile it with g++ 4.6.3

Links

The source code is hosted on github.

Index