温馨提示×

如何重写debian readdir

小樊
43
2026-10-07 06:43:04
栏目: 智能运维

在 Debian(或者说 Linux 下 glibc)环境中,“重写 readdir”通常指拦截 / 替换 readdir() / readdir_r() / readdir64() 系列函数,用于:

  • 隐藏或过滤目录项
  • 审计目录访问
  • 实现虚拟文件系统行为
  • 做沙箱 / 容器 / FUSE 之外的轻量 hook

下面按常见可行方案从简单到复杂说明。


一、使用 LD_PRELOAD 重写 readdir(最常用)

1. 原理

readdir 是 glibc 提供的用户态函数,可以通过动态库优先加载来覆盖它。

2. 示例代码(readdir hook)

#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;
}

3. 编译与使用

gcc -shared -fPIC -o readdir_hook.so hook.c -ldl
LD_PRELOAD=./readdir_hook.so ls

✅ 优点:简单、无需 root
❌ 缺点:只影响用户态程序,内核 API 不受影响


二、同时重写 readdir64 / readdir_r(兼容问题)

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 版本

三、使用 glibc 符号版本(更“正规”)

Debian 使用符号版本控制:

__asm__(".symver readdir,readdir@GLIBC_2.2.5");

适用于:

  • 静态分析
  • 特定 glibc 版本兼容

四、内核态方案(真正的“重写”)

如果你指的是系统调用级:

1. getdents / getdents64

readdir 最终调用:

getdents64(2)

拦截方式:

  • LSM(SELinux / AppArmor)
  • eBPF(lsm / tracepoint)
  • 内核模块(不推荐)

eBPF 示例方向:

SEC("lsm/path_listxattr")

五、FUSE(完全不同的“目录”)

如果你想“完全重写目录行为”:

struct fuse_operations {
    .readdir = my_readdir,
};

✅ 稳定、安全
❌ 需要挂载点


六、选择建议

需求 推荐方案
隐藏文件 LD_PRELOAD
审计 eBPF
虚拟目录 FUSE
系统级 内核模块 / LSM

如果你能说明:

  • 是 用户态还是内核态
  • 想 隐藏 / 修改 / 记录 什么
  • Debian 版本 & glibc 版本

我可以给你可直接编译的完整示例。

0 踩