You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于kauth内核扩展的文件拷贝检测POC开发技术问询

嘿,这个场景我之前在做macOS内核安全工具的时候碰过,刚好可以给你捋捋思路!你要的是基于kauth的fileop scope回调,只抓已经被填充数据的目标文件,不用管源文件——这个需求完全可行,核心是要把文件的创建/打开事件和后续的写入行为关联起来,而不是孤立地处理单个认证操作。

具体实现思路

首先得明确kauth fileop里的几个关键事件节点,然后把它们串起来:

  • 第一步:跟踪待检测的目标文件
    当触发KAUTH_FILEOP_CREATE(新建文件)或者KAUTH_FILEOP_OPEN(带写入权限打开已有文件)的时候,先判断是不是普通文件(排除目录、设备文件这些),然后把这个文件的inode号、挂载点、路径记录下来,存在一个内核态的哈希表里,初始的写入字节数设为0。

  • 第二步:累计目标文件的写入量
    监听KAUTH_FILEOP_WRITE回调,每次这个文件有写入操作时,就把写入的字节数累加到之前记录的条目里。这里要注意加锁,内核态操作线程安全是必须的。

  • 第三步:在文件关闭时判定是否符合条件
    当触发KAUTH_FILEOP_CLOSE回调时,去哈希表里找对应的文件记录:如果累计写入的字节数大于0,说明这个文件确实被填充了数据,就是你要找的目标文件,这时候就可以触发你的后续分析逻辑(比如记录文件信息、上报到用户态等),最后把这条记录从哈希表里删掉,避免内存泄漏。

要避开的几个坑
  • vnode重用问题:内核会复用vnode对象,所以别只靠vnode指针作为唯一标识,最好结合文件的inode号和挂载点来做键,这样能避免误把复用的vnode当成同一个文件。
  • 性能开销:哈希表的操作要尽量轻量,别在回调里做耗时的事(比如同步写日志到磁盘),不然会拖慢系统。可以把需要分析的数据攒起来,异步传到用户态处理。
  • 覆盖文件的情况:有些拷贝是覆盖已有文件,这时候触发的是KAUTH_FILEOP_OPEN而不是CREATE,所以两个事件都要监听,并且检查打开的权限是写入模式。
简单的伪代码示例(内核态C)
// 定义跟踪文件的结构体
typedef struct {
    uint64_t ino;          // 文件inode号
    vfs_mount_t mp;        // 挂载点
    off_t total_written;   // 累计写入字节数
    char path[MAXPATHLEN]; // 文件路径
} TrackedFile;

// 内核态锁和哈希表
static lck_mtx_t *tracker_lock;
static hash_table_t *file_tracker;

// CREATE回调处理
static int kauth_fileop_create(kauth_cred_t cred, void *idata, kauth_action_t action, 
                               uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
    vnode_t vn = (vnode_t)arg0;
    char *file_path = (char *)arg1;

    // 只跟踪普通文件
    if (vn->v_type != VREG) return KAUTH_RESULT_DEFER;

    lck_mtx_lock(tracker_lock);
    // 创建跟踪条目
    TrackedFile *tf = malloc(sizeof(TrackedFile));
    tf->ino = vn->v_data->vn_ino;
    tf->mp = vn->v_mount;
    tf->total_written = 0;
    strlcpy(tf->path, file_path, MAXPATHLEN);
    // 用inode+挂载点作为键插入哈希表
    hash_table_insert(file_tracker, (uintptr_t)(tf->ino ^ (uintptr_t)tf->mp), tf);
    lck_mtx_unlock(tracker_lock);

    return KAUTH_RESULT_DEFER;
}

// WRITE回调处理
static int kauth_fileop_write(kauth_cred_t cred, void *idata, kauth_action_t action, 
                              uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
    vnode_t vn = (vnode_t)arg0;
    size_t write_len = (size_t)arg2;

    lck_mtx_lock(tracker_lock);
    // 查找对应的跟踪条目
    uintptr_t key = (uintptr_t)(vn->v_data->vn_ino ^ (uintptr_t)vn->v_mount);
    TrackedFile *tf = hash_table_lookup(file_tracker, key);
    if (tf) {
        tf->total_written += write_len;
    }
    lck_mtx_unlock(tracker_lock);

    return KAUTH_RESULT_DEFER;
}

// CLOSE回调处理
static int kauth_fileop_close(kauth_cred_t cred, void *idata, kauth_action_t action, 
                              uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) {
    vnode_t vn = (vnode_t)arg0;

    lck_mtx_lock(tracker_lock);
    uintptr_t key = (uintptr_t)(vn->v_data->vn_ino ^ (uintptr_t)vn->v_mount);
    TrackedFile *tf = hash_table_lookup(file_tracker, key);
    if (tf && tf->total_written > 0) {
        // 这里触发你的后续分析逻辑
        printf("Detected filled target file: %s | Written bytes: %lld\n", tf->path, tf->total_written);
    }
    // 清理资源
    if (tf) {
        free(tf);
        hash_table_remove(file_tracker, key);
    }
    lck_mtx_unlock(tracker_lock);

    return KAUTH_RESULT_DEFER;
}

这样一套逻辑下来,就能精准抓到那些被写入数据的目标文件,完全符合你不需要关注源文件的需求。

内容的提问来源于stack exchange,提问作者Zohar81

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:33:15