APatch kpm模块开发

转载至APatch kpm模块开发 | 拓森

什么是KernelPatch Module (KPM)

KPM是一个ELF文件,可以通过KernelPatch在内核空间中加载和运行

官方文档与代码案例

官方提供了3个案例:
1.hello world
2.inline-hook
3.syscallhook

Hello

//代码比较简单
//这里声明了模块名称, 版本, 作者协议, 描述等

KPM_NAME("kpm-hello-demo");


KPM_VERSION("1.0.0");


KPM_LICENSE("GPL v2");


KPM_AUTHOR("bmax121");


KPM_DESCRIPTION("KernelPatch Module Example");


static long hello_init(const char *args, const char *event, void *__user reserved)
{
    pr_info("kpm hello init, event: %s, args: %s\n", event, args);
    pr_info("kernelpatch version: %x\n", kpver);
    return 0;
}

static long hello_control0(const char *args, char *__user out_msg, int outlen)
{
    pr_info("kpm hello control0, args: %s\n", args);
    char echo[64] = "echo: ";
    strncat(echo, args, 48);
    compat_copy_to_user(out_msg, echo, sizeof(echo));
    return 0;
}

static long hello_control1(void *a1, void *a2, void *a3)
{
    pr_info("kpm hello control1, a1: %llx, a2: %llx, a3: %llx\n", a1, a2, a3);
    return 0;
}

static long hello_exit(void *__user reserved)
{
    pr_info("kpm hello exit\n");
    return 0;
}

//这里注册了几个函数: 
KPM_INIT(hello_init);      //初始化
KPM_CTL0(hello_control0);  //ctl0
KPM_CTL1(hello_control1);  //ctl1
KPM_EXIT(hello_exit);      //退出
JavaScript

inline hook

//同上
KPM_NAME("kpm-inline-hook-demo");
KPM_VERSION("1.0.0");
KPM_LICENSE("GPL v2");
KPM_AUTHOR("bmax121");
KPM_DESCRIPTION("KernelPatch Module Inline Hook Example");

int __noinline add(int a, int b)
{
    logkd("origin add called\n");
    int ret = a + b;
    return ret;
}

void before_add(hook_fargs2_t *args, void *udata)
{
    logkd("before add arg0: %d, arg1: %d\n", (int)args->arg0, (int)args->arg1);
}

void after_add(hook_fargs2_t *args, void *udata)
{
    logkd("after add arg0: %d, arg1: %d, ret: %d\n", (int)args->arg0, (int)args->arg1, (int)args->ret);
    args->ret = 100;   //修改返回值
}

static long inline_hook_demo_init(const char *args, const char *event, void *__user reserved)
{
    logkd("kpm inline-hook-demo init\n");

    int a = 20;
    int b = 10;

    int ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    hook_err_t err = hook_wrap2((void *)add, before_add, after_add, 0);
    logkd("hook err: %d\n", err);

    ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    return 0;
}

static long inline_hook_control0(const char *args, char *__user out_msg, int outlen)
{
    pr_info("kpm control, args: %s\n", args);
    return 0;
}

static long inline_hook_demo_exit(void *__user reserved)
{
    unhook((void *)add);

    int a = 20;
    int b = 10;

    int ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    logkd("kpm inline-hook-demo  exit\n");
}

KPM_INIT(inline_hook_demo_init);
KPM_CTL0(inline_hook_control0);
KPM_EXIT(inline_hook_demo_exit);
JavaScript
static long inline_hook_demo_init(const char *args, const char *event, void *__user reserved)
{
    logkd("kpm inline-hook-demo init\n");

    int a = 20;
    int b = 10;

    int ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    hook_err_t err = hook_wrap2((void *)add, before_add, after_add, 0);
    logkd("hook err: %d\n", err);

    ret = add(a, b);
    logkd("%d + %d = %d\n", a, b, ret);

    return 0;
}
JavaScript
定义一个测试函数:__noinline add
__noinline 避免被内联优化, 方便hook
执行hook
    hook_err_t err = hook_wrap2((void *)add, before_add, after_add, 0);
    //参数很好理解
    第一个是被hook的函数, 第二个是before hook, 第三个是after hook, 第四个是用户数据指针
   
JavaScript

syscall hook

const char *margs = 0;
enum hook_type hook_type = NONE;

enum pid_type
{
    PIDTYPE_PID,
    PIDTYPE_TGID,
    PIDTYPE_PGID,
    PIDTYPE_SID,
    PIDTYPE_MAX,
};
struct pid_namespace;

//函数指针
pid_t (*__task_pid_nr_ns)(struct task_struct *task, enum pid_type type, struct pid_namespace *ns) = 0;

void before_openat_0(hook_fargs4_t *args, void *udata)
{
    int dfd = (int)syscall_argn(args, 0);
    const char __user *filename = (typeof(filename))syscall_argn(args, 1);
    int flag = (int)syscall_argn(args, 2);
    umode_t mode = (int)syscall_argn(args, 3);

    char buf[1024];
    compat_strncpy_from_user(buf, filename, sizeof(buf));

    struct task_struct *task = current;
    pid_t pid = -1, tgid = -1;
    if (__task_pid_nr_ns) {
        pid = __task_pid_nr_ns(task, PIDTYPE_PID, 0);
        tgid = __task_pid_nr_ns(task, PIDTYPE_TGID, 0);
    }

    args->local.data0 = (uint64_t)task;

    pr_info("hook_chain_0 task: %llx, pid: %d, tgid: %d, openat dfd: %d, filename: %s, flag: %x, mode: %d\n", task, pid,
            tgid, dfd, buf, flag, mode);
}

uint64_t open_counts = 0;

void before_openat_1(hook_fargs4_t *args, void *udata)
{
    uint64_t *pcount = (uint64_t *)udata;
    (*pcount)++;
    pr_info("hook_chain_1 before openat task: %llx, count: %llx\n", args->local.data0, *pcount);
}

void after_openat_1(hook_fargs4_t *args, void *udata)
{
    pr_info("hook_chain_1 after openat task: %llx\n", args->local.data0);
}

static long syscall_hook_demo_init(const char *args, const char *event, void *__user reserved)
{
    margs = args;
    pr_info("kpm-syscall-hook-demo init ..., args: %s\n", margs);
    //赋值给函数指针
    __task_pid_nr_ns = (typeof(__task_pid_nr_ns))kallsyms_lookup_name("__task_pid_nr_ns");
    pr_info("kernel function __task_pid_nr_ns addr: %llx\n", __task_pid_nr_ns);

    if (!margs) {
        pr_warn("no args specified, skip hook\n");
        return 0;
    }

    hook_err_t err = HOOK_NO_ERR;

    if (!strcmp("function_pointer_hook", margs)) {
        pr_info("function pointer hook ...");
        hook_type = FUNCTION_POINTER_CHAIN;
        err = fp_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0);
        if (err) goto out;
        err = fp_hook_syscalln(__NR_openat, 4, before_openat_1, after_openat_1, &open_counts);
    } else if (!strcmp("inline_hook", margs)) {
        pr_info("inline hook ...");
        hook_type = INLINE_CHAIN;
        err = inline_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0);
    } else {
        pr_warn("unknown args: %s\n", margs);
        return 0;
    }

out:
    if (err) {
        pr_err("hook openat error: %d\n", err);
    } else {
        pr_info("hook openat success\n");
    }
    return 0;
}

static long syscall_hook_control0(const char *args, char *__user out_msg, int outlen)
{
    pr_info("syscall_hook control, args: %s\n", args);
    return 0;
}

static long syscall_hook_demo_exit(void *__user reserved)
{
    pr_info("kpm-syscall-hook-demo exit ...\n");

    if (hook_type == INLINE_CHAIN) {
        inline_unhook_syscall(__NR_openat, before_openat_0, 0);
    } else if (hook_type == FUNCTION_POINTER_CHAIN) {
        fp_unhook_syscall(__NR_openat, before_openat_0, 0);
        fp_unhook_syscall(__NR_openat, before_openat_1, after_openat_1);
    } else {
    }
    return 0;
}

KPM_INIT(syscall_hook_demo_init);
KPM_CTL0(syscall_hook_control0);
KPM_EXIT(syscall_hook_demo_exit);
JavaScript
初始化
static long syscall_hook_demo_init(const char *args, const char *event, void *__user reserved) {
    margs = args;
    
    // 获取内核函数地址复制给函数指针, 方便后面调用
    __task_pid_nr_ns = (typeof(__task_pid_nr_ns))kallsyms_lookup_name("__task_pid_nr_ns");
    
    if (!margs) {
        pr_warn("no args specified, skip hook\n");
        return 0;
    }

    hook_err_t err = HOOK_NO_ERR;
    
    // 根据参数选择hook类型
    if (!strcmp("function_pointer_hook", margs)) {
        // 函数指针方式hook
        hook_type = FUNCTION_POINTER_CHAIN;
        // 安装两个钩子形成链
        err = fp_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0);
        if (err) goto out;
        err = fp_hook_syscalln(__NR_openat, 4, before_openat_1, after_openat_1, &open_counts);
    }
    else if (!strcmp("inline_hook", margs)) {
        // 内联方式hook
        hook_type = INLINE_CHAIN;
        err = inline_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0);
    }
    
    out:
    return err ? -1 : 0;
}
JavaScript
如果参数是function_pointer_hook, 使用fp_hook_syscalln来hook系统函数, hook了openat
如果是inline_hook, 则使用inline_hook_syscalln来hook系统函数
void before_openat_0(hook_fargs4_t *args, void *udata)
{
    //获取openat四个参数
    int dfd = (int)syscall_argn(args, 0);    //fd
    const char __user *filename = (typeof(filename))syscall_argn(args, 1);  //filename
    int flag = (int)syscall_argn(args, 2);   //打开标志
    umode_t mode = (int)syscall_argn(args, 3);  //模式

    //从用户空间复制文件名
    char buf[1024];
    compat_strncpy_from_user(buf, filename, sizeof(buf));

    //获取当前进程
    struct task_struct *task = current;
    pid_t pid = -1, tgid = -1;
    //调用__task_pid_nr_ns函数指针获取pid和tgid(线程组id)
    if (__task_pid_nr_ns) {
        pid = __task_pid_nr_ns(task, PIDTYPE_PID, 0);
        tgid = __task_pid_nr_ns(task, PIDTYPE_TGID, 0);
    }

    //保存到local data中
    args->local.data0 = (uint64_t)task;

    pr_info("hook_chain_0 task: %llx, pid: %d, tgid: %d, openat dfd: %d, filename: %s, flag: %x, mode: %d\n", task, pid,
            tgid, dfd, buf, flag, mode);
}
JavaScript
通过syscall_argn来获取参数值
uint64_t open_counts = 0;

void before_openat_1(hook_fargs4_t *args, void *udata)
{
    //获取参数复制给pcount
    uint64_t *pcount = (uint64_t *)udata;
    (*pcount)++;   //累加
    pr_info("hook_chain_1 before openat task: %llx, count: %llx\n", args->local.data0, *pcount);  
}

void after_openat_1(hook_fargs4_t *args, void *udata)
{
    pr_info("hook_chain_1 after openat task: %llx\n", args->local.data0);   //这里打印出累加后的值
}
JavaScript

实际案例分析

模块作用:redirect /system/etc/hosts to /data/adb/hosts
KPM_NAME("hosts_redirect");
KPM_VERSION(MYKPM_VERSION);
KPM_LICENSE("GPL v2");
KPM_AUTHOR("lzghzr");
KPM_DESCRIPTION("redirect /system/etc/hosts to /data/adb/hosts/{n}");

#define IZERO (1UL << 0x10)
#define UZERO (1UL << 0x20)

struct open_flags;
struct file* (*do_filp_open)(int dfd, struct filename* pathname, const struct open_flags* op);

char* kfunc_def(d_path)(const struct path* path, char* buf, int buflen);
int kfunc_def(kern_path)(const char* name, unsigned int flags, struct path* path);
void kfunc_def(_raw_spin_lock)(raw_spinlock_t* lock);
void kfunc_def(_raw_spin_unlock)(raw_spinlock_t* lock);

static uint64_t task_struct_fs_offset = UZERO, task_struct_alloc_lock_offset = UZERO,
fs_struct_pwd_offset = UZERO, fs_struct_lock_offset = UZERO;

char hosts_source[] = "/system/etc/hosts";
char hosts_target[] = "/data/adb/hosts/0";

static uid_t current_uid() {
  struct cred* cred = *(struct cred**)((uintptr_t)current + task_struct_offset.cred_offset);
  uid_t uid = *(uid_t*)((uintptr_t)cred + cred_offset.uid_offset);
  return uid;
}

static inline void set_priv_selinx_allow(struct task_struct* task, int val) {
  struct task_ext* ext = get_task_ext(task);
  if (likely(task_ext_valid(ext))) {
    ext->priv_selinux_allow = val;
    dsb(ish);
  }
}

static bool endWith(const char* str, const char* suffix) {
  if (!str || !suffix)
    return false;
  size_t lenstr = strlen(str);
  size_t lensuffix = strlen(suffix);
  if (lensuffix > lenstr)
    return false;
  return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}

static void do_filp_open_before(hook_fargs3_t* args, void* udata) {
  args->local.data0 = 0;
  if (unlikely(hosts_target[16] == '0'))
    return;
  if (current_uid() != 0)
    return;

  struct filename* pathname = (struct filename*)args->arg1;

  if (unlikely(!strcmp(pathname->name, hosts_source))) {
    args->local.data0 = (uint64_t)pathname->name;
    pathname->name = hosts_target;
    set_priv_selinx_allow(current, true);
  } else if (unlikely(endWith(pathname->name, "hosts"))) {
    struct task_struct* task = current;
    spinlock_t task_lock = *(spinlock_t*)((uintptr_t)task + task_struct_alloc_lock_offset);
    spin_lock(&task_lock);

    struct fs_struct* fs = *(struct fs_struct**)((uintptr_t)task + task_struct_fs_offset);
    if (likely(fs)) {
    // spinlock_t fs_lock = *(spinlock_t*)((uintptr_t)fs + fs_struct_lock_offset);
    // spin_lock(&fs_lock);
      spin_lock(&fs->lock);
      struct path* pwd = (struct path*)((uintptr_t)fs + fs_struct_pwd_offset);
      if (likely(pwd)) {
        char buf[PATH_MAX];
        memset(&buf, 0, PATH_MAX);
        char* pwd_path = d_path(pwd, buf, PATH_MAX);
#ifdef DEBUG
        logkm("pwd_path=%s\n", pwd_path);
#endif /* DEBUG */

        * buf = '\0';
        if (pathname->name[0] != '/') {
          strncat(buf, pwd_path, strlen(pwd_path));
          strncat(buf, "/", strlen("/"));
        }
        strncat(buf, pathname->name, strlen(pathname->name));
#ifdef DEBUG
        logkm("full_path=%s\n", buf);
#endif /* DEBUG */

        struct path path;
        int err = kern_path(buf, LOOKUP_FOLLOW, &path);
        if (likely(!err)) {
          memset(&buf, 0, PATH_MAX);
          char* hosts_name = d_path(&path, buf, PATH_MAX);
#ifdef DEBUG
          logkm("hosts_name=%s\n", hosts_name);
#endif /* DEBUG */
          if (likely(!IS_ERR(hosts_name) && !strcmp(hosts_name, hosts_source))) {
            args->local.data0 = (uint64_t)pathname->name;
            pathname->name = hosts_target;
            set_priv_selinx_allow(task, true);
          }
        }
      }
      spin_unlock(&fs->lock);
    }
    spin_unlock(&task_lock);
  }
}

static void do_filp_open_after(hook_fargs3_t* args, void* udata) {
  if (unlikely(args->local.data0)) {
    set_priv_selinx_allow(current, false);
    struct filename* pathname = (struct filename*)args->arg1;
    pathname->name = (char*)args->local.data0;
  }
}

static long inline_hook_control0(const char* ctl_args, char* __user out_msg, int outlen) {
  char num = ctl_args ? *ctl_args : '1';
  if (unlikely(num < '0' || num > '9')) {
    return -11;
  }
  hosts_target[16] = num;

  char msg[64];
  snprintf(msg, sizeof(msg), "_(._.)_");
  compat_copy_to_user(out_msg, msg, sizeof(msg));
  return 0;
}

static long calculate_offsets() {
  // 获取 pwd 相关偏移
  // task->fs
  // fs->pwd
  int (*proc_cwd_link)(struct dentry* dentry, struct path* path);
  lookup_name(proc_cwd_link);

  uint32_t* proc_cwd_link_src = (uint32_t*)proc_cwd_link;
  for (u32 i = 0; i < 0x30; i++) {
#ifdef CONFIG_DEBUG
    logkm("proc_cwd_link %x %llx\n", i, proc_cwd_link[i]);
#endif /* CONFIG_DEBUG */
    if (proc_cwd_link_src[i] == ARM64_RET) {
      break;
    } else if ((proc_cwd_link_src[i] & MASK_LDP_64_) == INST_LDP_64_) {
      uint64_t imm7 = bits32(proc_cwd_link_src[i], 21, 15);
      fs_struct_pwd_offset = sign64_extend((imm7 << 0b11u), 16u);
      break;
    } else if (task_struct_alloc_lock_offset != UZERO && (proc_cwd_link_src[i] & MASK_ADD_64) == INST_ADD_64) {
      uint32_t sh = bit(proc_cwd_link_src[i], 22);
      uint64_t imm12 = imm12 = bits32(proc_cwd_link_src[i], 21, 10);
      if (sh) {
        fs_struct_lock_offset = sign64_extend((imm12 << 12u), 16u);
      } else {
        fs_struct_lock_offset = sign64_extend((imm12), 16u);
      }
    } else if (task_struct_alloc_lock_offset != UZERO && (proc_cwd_link_src[i] & MASK_LDR_64_) == INST_LDR_64_) {
      uint64_t imm12 = bits32(proc_cwd_link_src[i], 21, 10);
      task_struct_fs_offset = sign64_extend((imm12 << 0b11u), 16u);
    } else if (task_struct_alloc_lock_offset == UZERO && (proc_cwd_link_src[i] & MASK_ADD_64) == INST_ADD_64) {
      uint32_t sh = bit(proc_cwd_link_src[i], 22);
      uint64_t imm12 = imm12 = bits32(proc_cwd_link_src[i], 21, 10);
      if (sh) {
        task_struct_alloc_lock_offset = sign64_extend((imm12 << 12u), 16u);
      } else {
        task_struct_alloc_lock_offset = sign64_extend((imm12), 16u);
      }
      // MOV (to/from SP) is an alias of ADD <Xd|SP>, <Xn|SP>, #0
      if (task_struct_alloc_lock_offset == 0) {
        task_struct_alloc_lock_offset = UZERO;
      }
    }
  }
#ifdef CONFIG_DEBUG
  logkm("task_struct_fs_offset=0x%llx\n", task_struct_fs_offset);
  logkm("task_struct_alloc_lock_offset=0x%llx\n", task_struct_alloc_lock_offset);
  logkm("fs_struct_pwd_offset=0x%llx\n", fs_struct_pwd_offset);
  logkm("fs_struct_lock_offset=0x%llx\n", fs_struct_lock_offset);
#endif /* CONFIG_DEBUG */
  if (task_struct_fs_offset == UZERO || task_struct_alloc_lock_offset == UZERO || fs_struct_pwd_offset == UZERO || fs_struct_lock_offset == UZERO) {
    return -11;
  }
  return 0;
}

static long inline_hook_init(const char* args, const char* event, void* __user reserved) {
  int rc = inline_hook_control0(args, NULL, NULL);
  if (rc < 0) {
    return rc;
  }

  kfunc_lookup_name(d_path);
  kfunc_lookup_name(kern_path);
  kfunc_lookup_name(_raw_spin_lock);
  kfunc_lookup_name(_raw_spin_unlock);
  rc = calculate_offsets();
  if (rc < 0) {
    return rc;
  }

  lookup_name(do_filp_open);
  hook_func(do_filp_open, 3, do_filp_open_before, do_filp_open_after, 0);
  return 0;
}

static long inline_hook_exit(void* __user reserved) {
  unhook_func(do_filp_open);
  return 0;
}

KPM_INIT(inline_hook_init);
KPM_CTL0(inline_hook_control0);
KPM_EXIT(inline_hook_exit);
JavaScript
这个模块主要是hook VFS层do_sys_open, do_sys_open是open/openat的一个实现. VFS层是比syscal 更底层的实现
notion image

具体代码分析

  int rc = inline_hook_control0(args, NULL, NULL);
  if (rc < 0) {
    return rc;
  }

  kfunc_lookup_name(d_path);
  kfunc_lookup_name(kern_path);
  kfunc_lookup_name(_raw_spin_lock);
  kfunc_lookup_name(_raw_spin_unlock);
  rc = calculate_offsets();
  if (rc < 0) {
    return rc;
  }

  lookup_name(do_filp_open);
  hook_func(do_filp_open, 3, do_filp_open_before, do_filp_open_after, 0);
JavaScript

声明do_filp_open函数指针

struct file* (*do_filp_open)(int dfd, struct filename* pathname, const struct open_flags* op);
第一个参数: 目录文件描述符
第二个参数: 文件名结构体指针
第三个参数: 打开标志结构体指针
JavaScript

inline_hook_control0函数是设置文件编号, 假设是2

char hosts_target[] = “/data/adb/hosts/0”;
变成:
char hosts_target[] = “/data/adb/hosts/2”;
static long inline_hook_control0(const char* ctl_args, char* __user out_msg, int outlen) {
  char num = ctl_args ? *ctl_args : '1';
  if (unlikely(num < '0' || num > '9')) {
    return -11;
  }
  hosts_target[16] = num;

  char msg[64];
  snprintf(msg, sizeof(msg), "_(._.)_");
  compat_copy_to_user(out_msg, msg, sizeof(msg));
  return 0;
}
JavaScript

查找并保存几个重要的内核函数地址

// 查找并保存几个重要的内核函数地址
kfunc_lookup_name(d_path);          // 获取d_path函数的地址
kfunc_lookup_name(kern_path);       // 获取kern_path函数的地址
kfunc_lookup_name(_raw_spin_lock);  // 获取_raw_spin_lock函数的地址
kfunc_lookup_name(_raw_spin_unlock);// 获取_raw_spin_unlock函数的地址
JavaScript

hook do_filp_open

  lookup_name(do_filp_open);   //获取do_filp_open的函数地址
  hook_func(do_filp_open, 3, do_filp_open_before, do_filp_open_after, 0);
JavaScript

do_filp_open_before的实现

获取参数filename指针, 再获取pathname , 判断绝对路径和相对路径
绝对路径判断相等, 则执行重定向和设置selinux allow = true, hook完成后会改回去false
相对路径则获取工作目录拼接成绝对路径, 再执行相同的逻辑
static void do_filp_open_before(hook_fargs3_t* args, void* udata) {
  args->local.data0 = 0;    //设置local.data0为0
  if (unlikely(hosts_target[16] == '0'))
    return;
  if (current_uid() != 0)   //判断current_uid()是否为0, 也就是判断当前用户是否为root用户
    return;

  struct filename* pathname = (struct filename*)args->arg1;   //文件name struct

  if (unlikely(!strcmp(pathname->name, hosts_source))) {   //判断路径是否== /system/etc/hosts
    args->local.data0 = (uint64_t)pathname->name;          //保存old pathname
    pathname->name = hosts_target;                         //重定向到新的目录/data/adb/hosts/2
    set_priv_selinx_allow(current, true);                  //设置selinux权限
  } else if (unlikely(endWith(pathname->name, "hosts"))) { //判断是否hosts结尾, 相对路径模式
    struct task_struct* task = current;
    spinlock_t task_lock = *(spinlock_t*)((uintptr_t)task + task_struct_alloc_lock_offset);
    spin_lock(&task_lock);

    struct fs_struct* fs = *(struct fs_struct**)((uintptr_t)task + task_struct_fs_offset);
    if (likely(fs)) {
    // spinlock_t fs_lock = *(spinlock_t*)((uintptr_t)fs + fs_struct_lock_offset);
    // spin_lock(&fs_lock);
      spin_lock(&fs->lock);
      struct path* pwd = (struct path*)((uintptr_t)fs + fs_struct_pwd_offset);
      if (likely(pwd)) {
        char buf[PATH_MAX];
        memset(&buf, 0, PATH_MAX);
        char* pwd_path = d_path(pwd, buf, PATH_MAX);
#ifdef DEBUG
        logkm("pwd_path=%s\n", pwd_path);
#endif /* DEBUG */

        * buf = '\0';
        if (pathname->name[0] != '/') {
          strncat(buf, pwd_path, strlen(pwd_path));
          strncat(buf, "/", strlen("/"));
        }
        strncat(buf, pathname->name, strlen(pathname->name));
#ifdef DEBUG
        logkm("full_path=%s\n", buf);
#endif /* DEBUG */

        struct path path;
        int err = kern_path(buf, LOOKUP_FOLLOW, &path);
        if (likely(!err)) {
          memset(&buf, 0, PATH_MAX);
          char* hosts_name = d_path(&path, buf, PATH_MAX);
#ifdef DEBUG
          logkm("hosts_name=%s\n", hosts_name);
#endif /* DEBUG */
          if (likely(!IS_ERR(hosts_name) && !strcmp(hosts_name, hosts_source))) {   //判断组装后的完整路径相等, 执行重定向操作
            args->local.data0 = (uint64_t)pathname->name;
            pathname->name = hosts_target;
            set_priv_selinx_allow(task, true);
          }
        }
      }
      spin_unlock(&fs->lock);
    }
    spin_unlock(&task_lock);
  }
}
C

do_filp_open_after的实现

static void do_filp_open_after(hook_fargs3_t* args, void* udata) {
  if (unlikely(args->local.data0)) {
    set_priv_selinx_allow(current, false);    //seliux = false
    struct filename* pathname = (struct filename*)args->arg1; 
    pathname->name = (char*)args->local.data0;    //还原pathname
  }
}
JavaScript

编译(Ubuntu)

官方编译指南: https://github.com/bmax121/KernelPatch/blob/main/doc/en/build.md

先下载交叉编译

下载 AArch64 bare-metal target (aarch64-none-elf)解压

设置环境变量

export PATH=$PATH:/work/test/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf/bin
export TARGET_COMPILE=aarch64-none-elf-
JavaScript

编译

cd /work/test/APatch_kpm/hosts_redirect
make
JavaScript
完成!

KPM模块安装

此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注