Skip to content

cctv18/libfakestat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

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,则时间默认为1970-01-01 00:00:00
  • 使用例:
    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
  • 文件读取劫持
  • 可以劫持指定文件大小/内容/哈希校验/时间戳等读取,劫持到某个指定的目标文件,且不影响可执行文件自身运行(即读取被劫持文件会被指向至劫持目标,但执行被劫持文件执行的是其自身),支持完整/部分/相对路径匹配及通配符匹配。
  • 指令用法:定义环境变量HIJACK_TARGET——被劫持目标,HIJACK_FAKE——重定向目标;若有特殊场景,需要使被劫持目标读取到重定向目标的真实时间戳(绕过全局定义的统一虚假时间戳),则可以额外定义环境变量HIJACK_PRIO_TIMESTAMP="1"
  • 使用例:
  • 单组映射劫持:
  • HIJACK_TARGET="$(pwd)/clang" HIJACK_FAKE="/home/ubuntu/bin/clang" LD_PRELOAD="./libfakestat.so stat ./clang
  • 多组映射劫持:
  • HIJACK_TARGET_1="$(pwd)/clang" HIJACK_FAKE_1="/home/ubuntu/bin/clang" HIJACK_TARGET_2="$(pwd)/ld.lld" HIJACK_FAKE_2="/home/ubuntu/bin/ld.lld" LD_PRELOAD="./libfakestat.so stat ./clang
  • 多组映射劫持以_n的形式对HIJACK_TARGETHIJACK_FAKE进行分组,最高支持1024组,且编号越小的映射规则优先级越高。
  • 文件劫持读写区分控制:默认对被劫持文件的写入操作只写入被劫持文件自身(保护重定向目标文件不被改写),只有在开启 HIJACK_ALLOW_WRITE=1 时才允许写入重定向目标文件。
  • 文件劫持进程黑白名单控制:通过 HIJACK_BLACKLISTHIJACK_WHITELIST两个变量定义,支持多个进程名定义(用 || 分隔),支持部分/全部/相对路径/通配符定义;在只定义白名单时,只有白名单内的进程被放行;在只定义黑名单时,只有黑名单内的进程被劫持;同时定义时,白名单优先级高于黑名单。
  • 示例:
- export HIJACK_BLACKLIST="ccache||clang*||/usr/bin/ld.lld"
- export HIJACK_WHITELIST="sh"
  • libfaketime合用
  • 使用例如下:
    FAKETIME="@2024-05-26 12:34:56" FAKESTAT="2025-05-25 11:45:14" LD_PRELOAD="./libfakestat.so ./libfaketime.so" bash build.sh
  • 作用/排除路径控制
  • 分别通过WORKPATHNWORKPATH两个变量来控制,多个路径用空格分隔,路径可以使用通配符,且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与不足之处,欢迎大家提出更多功能改进建议。

About

A trick on timestamp acquisition for Unix/Linux programs.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors