Libfakestat
A trick on timestamp acquisition for Unix/Linux programs.
Install / Use
/learn @cctv18/LibfakestatREADME
libfakestat
一款用于劫持 Linux/Unix 应用程序获取时间戳的小工具。
原理
通过注入 Linux/Unix 应用程序,劫持应用程序获取创建时间(btime/crtime)、访问时间(atime)、修改时间(mtime)、变更时间(ctime)的获取函数,使程序查询文件时间戳时强行返回我们自行设置的时间戳,在不对文件系统实际时间戳进行底层修改操作的情况下完成安全、简便的时间戳伪装。
用法
- 编译:拉取源码仓库后进入
src目录,运行make指令即可进行编译,若需要直接安装至系统可运行make install;同时本项目也提供了利用 GitHub Action 进行云编译的工作流脚本。 - 注入程序:通过
FAKESTAT变量指定需要伪造的文件时间戳(格式为YYYY-MM-DD hh:mm:ss),并通过LD_PRELOAD=/your/lib/path/libfakestat.so指令加载so。 - 使用例:
FAKESTAT="2025-05-25 11:45:14" LD_PRELOAD=./libfakestat.so stat ./* - 输出效果:
文件:./libfakestat.c
大小:8008 块:16 IO 块大小:4096 普通文件
设备:252,0 Inode: 1221834 硬链接:1
权限:(0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-05-25 11:45:14.000000000 +0800
修改时间:2025-05-25 11:45:14.000000000 +0800
变更时间:2025-05-25 11:45:14.000000000 +0800
创建时间:2025-05-25 11:45:14.000000000 +0800
文件:./libfakestat.so
大小:16808 块:40 IO 块大小:4096 普通文件
设备:252,0 Inode: 1224875 硬链接:1
权限:(0775/-rwxrwxr-x) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-05-25 11:45:14.000000000 +0800
修改时间:2025-05-25 11:45:14.000000000 +0800
变更时间:2025-05-25 11:45:14.000000000 +0800
创建时间:2025-05-25 11:45:14.000000000 +0800
- 也可只指定日期,此时时、分、秒将自动被设置为
00:00:00。如下所示:
FAKESTAT="1919-08-10" LD_PRELOAD=./libfakestat.so stat ./* - 输出效果:
文件:./libfakestat.c
大小:8008 块:16 IO 块大小:4096 普通文件
设备:252,0 Inode: 1221834 硬链接:1
权限:(0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:1919-08-10 00:00:00.000000000 +0900
修改时间:1919-08-10 00:00:00.000000000 +0900
变更时间:1919-08-10 00:00:00.000000000 +0900
创建时间:1919-08-10 00:00:00.000000000 +0900
文件:./libfakestat.so
大小:16808 块:40 IO 块大小:4096 普通文件
设备:252,0 Inode: 1224875 硬链接:1
权限:(0775/-rwxrwxr-x) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:1919-08-10 00:00:00.000000000 +0900
修改时间:1919-08-10 00:00:00.000000000 +0900
变更时间:1919-08-10 00:00:00.000000000 +0900
创建时间:1919-08-10 00:00:00.000000000 +0900
- 同时,
libfakestat可以与libfaketime合用,使用例如下:
FAKETIME="@2024-05-26 12:34:56" FAKESTAT="2025-05-25 11:45:14" LD_PRELOAD="./libfakestat.so ./libfaketime.so" bash build.sh
注:若不手动指定FAKESTAT,则时间默认为1970-01-01 00:00:00。
- 作用/排除路径控制:分别通过
WORKPATH和NWORKPATH两个变量来控制,多个路径用空格分隔,路径可以使用通配符,且NWORKPATH优先级高于WORKPATH。 - 示例:
- 作用路径包含所有文件名/路径中含有.c和cc的文件而排除包含.orig的文件:
WORKPATH="cc *.c" NWORKPATH="*.orig" FAKESTAT="2025-10-18 14:30:00" LD_PRELOAD=./libfakestat.so stat ./*- 输出效果:
文件:./cc-wrapper
大小:184 块:8 IO 块大小:4096 普通文件
设备:252,0 Inode: 1225039 硬链接:1
权限:(0775/-rwxrwxr-x) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-18 14:30:00.000000000 +0800
修改时间:2025-10-18 14:30:00.000000000 +0800
变更时间:2025-10-18 14:30:00.000000000 +0800
创建时间:2025-10-18 14:30:00.000000000 +0800
文件:./libfakestat.c
大小:11111 块:24 IO 块大小:4096 普通文件
设备:252,0 Inode: 1225177 硬链接:1
权限:(0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-18 14:30:00.000000000 +0800
修改时间:2025-10-18 14:30:00.000000000 +0800
变更时间:2025-10-18 14:30:00.000000000 +0800
创建时间:2025-10-18 14:30:00.000000000 +0800
文件:./libfakestat.so
大小:21632 块:48 IO 块大小:4096 普通文件
设备:252,0 Inode: 1221725 硬链接:1
权限:(0775/-rwxrwxr-x) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-27 21:30:33.609675763 +0800
修改时间:2025-10-27 21:28:17.766599153 +0800
变更时间:2025-10-27 21:28:17.766626147 +0800
创建时间:2025-10-27 21:28:17.750293156 +0800
文件:./libfaketimeMT.so
大小:60072 块:120 IO 块大小:4096 普通文件
设备:252,0 Inode: 1224885 硬链接:1
权限:(0777/-rwxrwxrwx) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-25 05:21:59.710428660 +0800
修改时间:2022-08-14 02:58:42.000000000 +0800
变更时间:2025-10-25 05:21:48.797568367 +0800
创建时间:2025-10-21 04:34:03.843839056 +0800
文件:./orig_libfakestat.c
大小:11123 块:24 IO 块大小:4096 普通文件
设备:252,0 Inode: 1179720 硬链接:1
权限:(0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-18 14:30:00.000000000 +0800
修改时间:2025-10-18 14:30:00.000000000 +0800
变更时间:2025-10-18 14:30:00.000000000 +0800
创建时间:2025-10-18 14:30:00.000000000 +0800
文件:./orig_libfakestat.c.orig
大小:8008 块:16 IO 块大小:4096 普通文件
设备:252,0 Inode: 1221834 硬链接:1
权限:(0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-25 05:19:34.007313634 +0800
修改时间:2025-10-21 04:43:44.945544570 +0800
变更时间:2025-10-27 21:14:07.702856664 +0800
创建时间:2025-10-21 04:43:44.940544646 +0800
文件:./test.sh
大小:683 块:8 IO 块大小:4096 普通文件
设备:252,0 Inode: 1225041 硬链接:1
权限:(0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
访问时间:2025-10-25 05:26:42.812867964 +0800
修改时间:2025-10-25 05:26:39.190888740 +0800
变更时间:2025-10-25 05:26:39.191912867 +0800
创建时间:2025-10-25 05:26:39.188912905 +0800
背景
设计这个程序的初衷是我在研究 GitHub Action 中编译内核时 ccache 莫名其妙掉速的问题时,通过ccache日志发现:
GitHub Action 中 ccache 不知道为什么,刚创建缓存时拉取缓存可以直接模式命中,而过了一段时间之后就会出现大量ctime/mtime miss,导致 ccache 强制将缓存命中模式降级为预处理模式,导致在有同样 ccache 缓存的情况下,二次编译速度明显下降(从约6min降低到约11-12min),怀疑这可能和 GitHub Action 的环境/时间设置有关。
在以上情况下,我搜索了大量解决 ccache 缓存命中问题的方法,但最终证明无一奏效。于是我只能从根本入手,尝试解决ctime/mtime miss,即源码文件时间不匹配问题。在这期间,我接触到了wolfcw/libfaketime这个项目,这个小工具可以劫持任意程序获取的系统时间。但经过测试,它并不能劫持程序创建/修改文件的时间,因此还是无法完全解决 ccache 掉速的问题。于是我突发奇想,能不能仿照libfaketime的思路,设计一个类似的伪装文件时间戳的工具?于是就有了现在这个项目。
这个项目目前还只是一个很简易、粗糙的实现,应用场景也仍然在开发,难免存在各种bug与不足之处,欢迎大家提出更多功能改进建议。
