在 Debian(或者说 Linux 下 glibc)环境中,“重写 readdir”通常指拦截 / 替换 readdir() / readdir_r() / readdir64() 系列函数,用于:
下面按常见可行方案从简单到复杂说明。
readdir 是 glibc 提供的用户态函数,可以通过动态库优先加载来覆盖它。
#define _GNU_SOURCE
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
// 原始函数指针
static struct dirent *(*real_readdir)(DIR *) = NULL;
struct dirent *readdir(DIR *dirp) {
if (!real_readdir) {
real_readdir = dlsym(RTLD_NEXT, "readdir");
}
struct dirent *entry;
while ((entry = real_readdir(dirp)) != NULL) {
// 隐藏名为 secret 的文件
if (strcmp(entry->d_name, "secret") == 0)
continue;
return entry;
}
return NULL;
}
gcc -shared -fPIC -o readdir_hook.so hook.c -ldl
LD_PRELOAD=./readdir_hook.so ls
✅ 优点:简单、无需 root
❌ 缺点:只影响用户态程序,内核 API 不受影响
Debian 很多程序使用 readdir64:
struct dirent64 *readdir64(DIR *dirp);
示例:
static struct dirent64 *(*real_readdir64)(DIR *) = NULL;
struct dirent64 *readdir64(DIR *dirp) {
if (!real_readdir64)
real_readdir64 = dlsym(RTLD_NEXT, "readdir64");
struct dirent64 *e;
while ((e = real_readdir64(dirp)))
if (strcmp(e->d_name, "secret")) return e;
return NULL;
}
⚠️ 注意:
readdir_r 已废弃(glibc 2.34+)__readdir_chk 等 fortified 版本Debian 使用符号版本控制:
__asm__(".symver readdir,readdir@GLIBC_2.2.5");
适用于:
如果你指的是系统调用级:
readdir 最终调用:
getdents64(2)
拦截方式:
eBPF 示例方向:
SEC("lsm/path_listxattr")
如果你想“完全重写目录行为”:
struct fuse_operations {
.readdir = my_readdir,
};
✅ 稳定、安全
❌ 需要挂载点
| 需求 | 推荐方案 |
|---|---|
| 隐藏文件 | LD_PRELOAD |
| 审计 | eBPF |
| 虚拟目录 | FUSE |
| 系统级 | 内核模块 / LSM |
如果你能说明:
我可以给你可直接编译的完整示例。