Skip to content

Instantly share code, notes, and snippets.

@rmi1974
Last active February 2, 2025 02:12
Show Gist options
  • Save rmi1974/51244c06dbe1a84e052c09c5e142358a to your computer and use it in GitHub Desktop.
Save rmi1974/51244c06dbe1a84e052c09c5e142358a to your computer and use it in GitHub Desktop.
Using libfaketime to manipulate the system time for applications #faketime #wine #debug #commandlinefu

Using libfaketime to manipulate the system time for applications

See libfaketime on github for upstream project site general overview.

Build in multilib environment

#!/usr/bin/env bash

set -Eeuo pipefail

LIBFAKETIME_SOURCE_PATH=$PWD/libfaketime
LIBFAKETIME_INSTALL32_PREFIX=$PWD/install-x86
LIBFAKETIME_INSTALL64_PREFIX=$PWD/install-x86_64

[[ -d $LIBFAKETIME_SOURCE_PATH ]] || git clone https://github.com/wolfcw/libfaketime.git
make -C $LIBFAKETIME_SOURCE_PATH PREFIX=$LIBFAKETIME_INSTALL64_PREFIX distclean install | tee build64.log
CFLAGS="-m32" LDFLAGS="-m32" make -C $LIBFAKETIME_SOURCE_PATH PREFIX=$LIBFAKETIME_INSTALL32_PREFIX distclean install | tee build32.log

# generate scripts for shell environment
echo "export LD_PRELOAD=$LIBFAKETIME_INSTALL32_PREFIX/lib/faketime/libfaketime.so.1" > libfaketime32.env
echo "export LD_PRELOAD=$LIBFAKETIME_INSTALL64_PREFIX/lib/faketime/libfaketime.so.1" > libfaketime64.env

Usage in Wine to fake system time for Windows applications

64-bit application in 64-bit WINEPREFIX:

$ date
Sat Oct 19 19:11:58 CEST 2019

$ (source libfaketime64.env ; FAKETIME="-1y" wine64 "c:/windows/system32/cmd.exe" /c date /t)
Current Date is 10/19/2018

32-bit application in 64-bit WINEPREFIX:

$ date
Sat Oct 19 19:11:58 CEST 2019

$ (source libfaketime32.env ; FAKETIME="-1y" wine "c:/windows/syswow64/cmd.exe" /c date /t)
Current Date is 10/19/2018

NOTE: Since Wine 7.2, libfaketime doesn't work anymore for 32-bit processes due to missing 64-bit time_t support. See my comment


Links

@random-cdda-modder
Copy link

Thank you for this piece of cmd-fu. The 64-bit example works.

32-bit application example gives error:

LD_PRELOAD="$LIBFAKETIME_INSTALL32_PREFIX/lib/faketime/libfaketime.so.1" FAKETIME="-1y" wine "c:/windows/syswow64/cmd.exe" /c date /t
ERROR: ld.so: object '$LIBFAKETIME_INSTALL32_PREFIX/lib/faketime/libfaketime.so.1' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored.
Current Date is 12/2/2024

Trying to use the 64-bit lib with the 32-bit command also errors but with wrong ELF class: ELFCLASS64 instead.

Wineprefix is default, 64-bit, and freshly generated just for this gist.
Using wine64 instead of wine in 32-bit example does not change anything, as I would expect.
Trying to use wine instead of wine64 in 64-bit example also complains about ELFCLASS64, as I would expect.
No issues with building.
Inspecting with file command claims that wine64 and system32/cmd.exe are 64-bit executables, and same for 32-bit versions.
Installed wine version is 9.20

What could be the cause?

@rmi1974
Copy link
Author

rmi1974 commented Dec 23, 2024

Hi @random-cdda-modder

Sorry for the late reply. I was busy with lots of other (non software) projects.
Since I have every Wine version from 1.3.x onward still building and running on my Fedora 40 machine, I've traced the 32-bit breakage back to Wine 7.2.

Specifically to this change between Wine 7.1 and 7.2 from Feb 2, 2022:

https://gitlab.winehq.org/wine/wine/-/commit/2211ca9fa57640b4c19c0a6aa57fda94328c53c5 ("configure: Enable 64-bit time_t on Linux.")

There is actually a bug report about the missing 64-bit time_t support in the libfaketime project:

wolfcw/libfaketime#418

One guy was claiming to work on it but no updates since one year. :-(

So you are left with two options:

  • run the apps you need 32-bit libfaketime working with Wine 7.1 but no later (I guess not an option)
  • create a custom Wine build with 64-bit time_t disabled:
diff --git a/configure.ac b/configure.ac
index 6596f653fb1..febf94fab5a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -362,7 +362,7 @@ dnl **** Check for header files ****
 AC_SYS_LARGEFILE()
 m4_ifdef([AC_SYS_YEAR2038],
          [AS_IF(false,[AC_SYS_YEAR2038()])], dnl bypass misguided autoconf error on wow64 builds
-         [test "$ac_cv_sys_file_offset_bits" = 64 && AC_DEFINE(_TIME_BITS,64,[Define to 64 to enable 64-bit time_t])])
+         [test "$ac_cv_sys_file_offset_bits" = 64 && true])
 
 AC_CHECK_HEADERS(\
        CL/cl.h \

Don't forget to regenerate configure scripts with autoreconf -f when building wine (to have the change from configure.ac picked up).

This way you can still do libfaketime hacks with 32-bit processes on most recent Wine 10.0.


Apart from that (the root cause), the other errors from your command line output:

ERROR: ld.so: object '$LIBFAKETIME_INSTALL32_PREFIX/lib/faketime/libfaketime.so.1' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored.

Those are benign and can be ignored because wine always starts as 64-bit process nowadays, even if 32-bit has been requested.

Regards

@random-cdda-modder
Copy link

Thank you, bisecting the root cause all the way to 2022 is really going above and beyond on a bug report on a gist first published in the previous decade!

After reviewing your reply and the recent libfaketime author reply ( wolfcw/libfaketime#418 (comment) ), I believe the path of least resistance for me is to wait for https://gitlab.winehq.org/wine/wine/-/releases/wine-9.0#wow64 to be enabled by default which should allow using 64bit wine to run the 32bit executable.

At this time, this support requires also building your own wine, like your workaround, but I would recommend others who end up here to attempt wow64 support first since it sounds promising. So, the third option which would be:

  1. have a 64bit wine with wow64 support. Wine has a guide on how to enable this support manually if not yet enabled by default: https://gitlab.winehq.org/wine/wine/-/wikis/Building-Wine#shared-wow64
  2. $ (source libfaketime64.env ; FAKETIME="-1y" wine64 "c:/windows/syswow64/cmd.exe" /c date /t)
  3. after the above works replace the 32bit cmd.exe and its arguments in the above command with your application

@rmi1974
Copy link
Author

rmi1974 commented Jan 24, 2025

Hi,

just to clear things up. You are referring to the new experimental WoW64 mode.
Wine has Wow64 implemented since like 15 years which required a multilib host with 32-bit and 64-bit dependencies.
With the new experimental WoW64 mode, the 32-bit native host (and build) dependencies are no longer needed.
The 32-bit executables run in a 64-bit process.

Since I always build Wine on my own (I can still build all Wine versions down to Wine 1.3.x on the same Fedora 41 machine), I have those experimental wow64 builds as well, along with the traditional Wow64 32/64-bit multilib.

The new WoW64 is the way and follows what Windows natively does.
Output from my "new" wow64 mode build, showing it works:

$ source libfaketime64.env

$ wine --version
wine-10.0-127-g1f23d893483

$ FAKETIME="-1y" wine "c:/windows/syswow64/cmd.exe" /c date /t
0174:err:environ:init_peb starting L"C:\\windows\\syswow64\\cmd.exe" in experimental wow64 mode
Current Date is 1/25/2024

Not sure when they are provided as alternative/default to distros as well from WineHQ (https://gitlab.winehq.org/wine/wine/-/wikis/Download).
There are several third-party projects which provide own "custom" builds of various Wine flavours, including experimental WoW64 mode enabled ones. Example:

https://github.com/Kron4ek/Wine-Builds

Note, I don't use it/nor can comment on it, just listed as example.

Regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment