【问题标题】:Jprobe to 'do_execve' on Ubuntu 14 doesn't work but work on Ubuntu 12Jprobe to 'do_execve' 在 Ubuntu 14 上不起作用,但在 Ubuntu 12 上工作
【发布时间】:2015-03-23 12:30:31
【问题描述】:

我正在尝试使用 Jprobes 对 Linux 内核上的函数 'do_execve()' 执行挂钩,但我遇到了某些系统的问题。我尝试使用我在 Ubuntu 12、64 位(内核版本 3.11)上在线找到的代码:

钩子.c:

/* Trace do_execv.  Taken basically from Documentation/kprobes.txt */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>

/*
 * Pre-entry point for do_execve.
 */
static int my_do_execve(char * filename,
                        char __user *__user *argv,
                        char __user *__user *envp,
                        struct pt_regs * regs)
{
        printk("do_execve for %s from %s\n", filename, current->comm);
        /* Always end with a call to jprobe_return(). */
        jprobe_return();
        /*NOTREACHED*/
        return 0;
}

static struct jprobe my_jprobe = {
        .entry = (kprobe_opcode_t *) my_do_execve
};

int init_module(void)
{
        int ret;
        my_jprobe.kp.addr = 
                (kprobe_opcode_t *) kallsyms_lookup_name("do_execve");
        if (!my_jprobe.kp.addr) {
                printk("Couldn't find %s to plant jprobe\n", "do_execve");
                return -1;
        }

        if ((ret = register_jprobe(&my_jprobe)) <0) {
                printk("register_jprobe failed, returned %d\n", ret);
                return -1;
        }
        printk("Planted jprobe at %p, handler addr %p\n",
               my_jprobe.kp.addr, my_jprobe.entry);
        return 0;
}

void cleanup_module(void)
{
        unregister_jprobe(&my_jprobe);
        printk("jprobe unregistered\n");
}

MODULE_LICENSE("GPL");

生成文件:

# This is taken straight from Documentation/kprobes.txt

obj-m := trace-exec.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
    rm -f *.mod.c *.ko *.o

该模块按预期工作。它首先在系统上正确编译,然后使用函数“insmod”(具有 ROOT 权限)插入。运行 dmesg 显示正确的输出:

Planted Jprobes at [ADDRESS HERE], handler addr [ADDRESS HERE]
do_execve for /bin/sh from wcstatusd [PRINTED FOR ANY EXECUTED PROCESS]

当我在 Ubuntu 14、64 位(内核版本 3.13)系统上尝试相同的代码时出现问题。我在系统上重新编译它并像在以前的系统上一样插入它,但是这次它不起作用。我没有收到任何错误,并且打印了成功消息(“在 [ADDRESS WAS HERE] 处种植 jprobe,处理程序地址 [ADDRESS WAS HERE]”),但未打印 'do_execve' 行。我扫描了谷歌,但找不到解释或解决方案。有什么想法吗?

注意:我还尝试在 Ubuntu 14 上挂接“do_fork()”,它成功了!这只是 'do_execve()' 的东西,我不知道是什么!

【问题讨论】:

    标签: c linux ubuntu execve jprobe


    【解决方案1】:

    do_execve() 的定义在 exec.c 中 http://lxr.free-electrons.com/source/fs/exec.c?v=3.11#L1584

    这里是 do_execve() 的代码。后面加一行

    int do_execve(struct filename *filename,const char __user *const __user *__argv,const char __user *const __user *__envp)
    {
           struct user_arg_ptr argv = { .ptr.native = __argv };
           struct user_arg_ptr envp = { .ptr.native = __envp };
           return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
    }
    EXPORT_SYMBOL(do_execve);  // Add this line.
    

    此文件将在 linux/fs/exec.c 中。在函数之后添加 EXPORT_SYMBOL() 行。然后执行 make、make install 和 reboot。 它几乎就像挂钩,因为我们必须再次构建和安装内核。假设您没有通过在运行时修改系统调用地址来拦截调用。

    【讨论】:

    • 等等,我想我不明白你的意思。您是否建议修改我的内核模块?还是您告诉我在编辑源代码后再次编译内核?如何在原始“do_execve”之后添加这一行?无论如何,如果它在'kallsyms_lookup_name'中导出,我为什么要导出这个符号?
    • @Shtut 是的,您必须在给定文件中添加行,然后再次重建内核。关于 EXPORT_SYMBOL() 见这个 stackoverflow 问题stackoverflow.com/questions/22712114/…
    猜你喜欢
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 2013-12-28
    • 1970-01-01
    相关资源
    最近更新 更多