Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 无法在ARM64上的Linux内核中使用set_memory_rw_C_Linux Kernel_Hook_System Calls_Rootkit - Fatal编程技术网

C 无法在ARM64上的Linux内核中使用set_memory_rw

C 无法在ARM64上的Linux内核中使用set_memory_rw,c,linux-kernel,hook,system-calls,rootkit,C,Linux Kernel,Hook,System Calls,Rootkit,我正在尝试开发一个内核模块来钩住read()系统调用。由于某种原因,set\u memory\u rw()函数似乎不起作用 我看到了另一个这样的问题,但我真的不知道该怎么办 我正在用树莓皮4制作卡利4.19.93 我的代码: #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 模块许可证(“GPL”); 模块作者(“Omri Ben David”); 模块描述(“挂接Linux系统调用”); 模块_版本(“1.0”); 无符号长**系统调用表=(无符号

我正在尝试开发一个内核模块来钩住
read()
系统调用。由于某种原因,
set\u memory\u rw()
函数似乎不起作用

我看到了另一个这样的问题,但我真的不知道该怎么办

我正在用树莓皮4制作卡利4.19.93

我的代码:

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
模块许可证(“GPL”);
模块作者(“Omri Ben David”);
模块描述(“挂接Linux系统调用”);
模块_版本(“1.0”);
无符号长**系统调用表=(无符号长**)0xc02011c4;
asmsize_t(*原始读取)(int fd,char*buf,size_t count);
asmsize\u t HookRead(无符号整数fd,字符*buf,大小\u t计数)
{
printk(KERN_INFO“Rootkit_Debug:Yay您输入了我的函数!!\n现在您可以阅读了);
返回(*原始读数)(fd、buf、计数);
}   
无效(*搜索)(无符号长,整数);
无效(*隐藏)(无符号长,整数);
静态int\uu init SetHooks(void)
{
printk(KERN_INFO“钩子现在将被设置,请按住\n”);
printk(内核信息“系统调用表位于地址%p\n”,系统调用表);
原始读取=(无效*)系统调用表[\uuuuu NR\uu read];
seek=(void*)kallsyms_lookup_name(“set_memory_rw”);
hide=(void*)kallsyms_lookup_name(“set_memory_ro”);
(*seek)((无符号长)系统调用表,1);
SYS_CALL_TABLE[\uu NR_read]=(无符号长*)HookRead;
(*隐藏)((无符号长)系统调用表,1);
printk(KERN_INFO“系统调用已成功挂接\n”);
返回0;
}
静态void\uu退出钩子清理(void)
{
printk(KERN_INFO“系统调用还原已启动”\n);
(*seek)((无符号长)系统调用表,1);
SYS\u CALL\u TABLE[\uu NR\u read]=(无符号长*)原始\u read;
(*隐藏)((无符号长)系统调用表,1);
printk(KERN_INFO“系统已成功恢复。希望您玩得开心”);
}
模块_init(设置挂钩);
模块_出口(挂钩清理);

如何使
set\u memory\u rw()
函数工作以覆盖syscall表?或者我应该使用另一种方法吗?

因此,正如我在上面的评论中所说的,该函数(由
set\u memory\u ro/rw()
使用)似乎在应用请求的权限之前进行了检查。这在文件中有一条注释:

/*
 * Kernel VA mappings are always live, and splitting live section
 * mappings into page mappings may cause TLB conflicts. This means
 * we have to ensure that changing the permission bits of the range
 * we are operating on does not result in such splitting.
 *
 * Let's restrict ourselves to mappings created by vmalloc (or vmap).
 * Those are guaranteed to consist entirely of page mappings, and
 * splitting is never needed.
 *
 * So check whether the [addr, addr + size) interval is entirely
 * covered by precisely one VM area that has the VM_ALLOC flag set.
 */
area = find_vm_area((void *)addr);
if (!area ||
    end > (unsigned long)area->addr + area->size ||
    !(area->flags & VM_ALLOC))
    return -EINVAL;
该函数似乎仅适用于通过
vmalloc()
vmap()
创建的映射,而
sys\u call\u表
不存在于此类映射中

问题似乎与TLB冲突有关。我真的不知道为什么这会导致TLB冲突,因为函数,但我不是ARM专家,所以我可能错过了一些东西。我想可以打电话,但似乎没有必要。欢迎有任何其他见解

在任何情况下,为了练习系统调用劫持,您可以重新编写自己版本的
set\u memory\u common()
set\u memory\u rw/ro()
以避免此检查。一个更简单的方法是为所需的地址获取适当的PTE,然后更改权限,但我没有查看所有的宏

最后,但并非最不重要的一点是,由于
sys\u call\u表
最终可能会跨越页面边界,因此在对页面应用更改时,最好使用
syscall\u table+\uu NR\u read
而不仅仅是
sys\u call\u表

下面是一个工作示例:

// SPDX-License-Identifier: GPL-3.0
#include <linux/init.h>     // module_{init,exit}()
#include <linux/module.h>   // THIS_MODULE, MODULE_VERSION, ...
#include <linux/kernel.h>   // printk(), pr_*()
#include <linux/kallsyms.h> // kallsyms_lookup_name()
#include <asm/syscall.h>    // syscall_fn_t, __NR_*
#include <asm/ptrace.h>     // struct pt_regs
#include <asm/tlbflush.h>   // flush_tlb_kernel_range()
#include <asm/pgtable.h>    // {clear,set}_pte_bit(), set_pte()
#include <linux/vmalloc.h>  // vm_unmap_aliases()
#include <linux/mm.h>       // struct mm_struct, apply_to_page_range()
#include <linux/kconfig.h>  // IS_ENABLED()

#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

static struct mm_struct *init_mm_ptr;
static syscall_fn_t *syscall_table;
static syscall_fn_t original_read;

/********** HELPERS **********/

// From arch/arm64/mm/pageattr.c.
struct page_change_data {
    pgprot_t set_mask;
    pgprot_t clear_mask;
};

// From arch/arm64/mm/pageattr.c.
static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
{
    struct page_change_data *cdata = data;
    pte_t pte = READ_ONCE(*ptep);

    pte = clear_pte_bit(pte, cdata->clear_mask);
    pte = set_pte_bit(pte, cdata->set_mask);

    set_pte(ptep, pte);
    return 0;
}

// From arch/arm64/mm/pageattr.c.
static int __change_memory_common(unsigned long start, unsigned long size,
                  pgprot_t set_mask, pgprot_t clear_mask)
{
    struct page_change_data data;
    int ret;

    data.set_mask = set_mask;
    data.clear_mask = clear_mask;

    ret = apply_to_page_range(init_mm_ptr, start, size, change_page_range, &data);

    flush_tlb_kernel_range(start, start + size);
    return ret;
}

// Simplified set_memory_rw() from arch/arm64/mm/pageattr.c.
static int set_page_rw(unsigned long addr)
{
    vm_unmap_aliases();    
    return __change_memory_common(addr, PAGE_SIZE, __pgprot(PTE_WRITE), __pgprot(PTE_RDONLY));
}

// Simplified set_memory_ro() from arch/arm64/mm/pageattr.c.
static int set_page_ro(unsigned long addr)
{
    vm_unmap_aliases();
    return __change_memory_common(addr, PAGE_SIZE, __pgprot(PTE_RDONLY), __pgprot(PTE_WRITE));
}

/********** ACTUAL MODULE **********/

static long myread(const struct pt_regs *regs)
{
    pr_info("read() called\n");
    return original_read(regs);
}

static int __init modinit(void)
{
    int res;

    pr_info("init\n");

    // Shouldn't fail.
    init_mm_ptr = (struct mm_struct *)kallsyms_lookup_name("init_mm");
    syscall_table = (syscall_fn_t *)kallsyms_lookup_name("sys_call_table");

    original_read = syscall_table[__NR_read];

    res = set_page_rw((unsigned long)(syscall_table + __NR_read) & PAGE_MASK);
    if (res != 0) {
        pr_err("set_page_rw() failed: %d\n", res);
        return res;
    }

    syscall_table[__NR_read] = myread;

    res = set_page_ro((unsigned long)(syscall_table + __NR_read) & PAGE_MASK);
    if (res != 0) {
        pr_err("set_page_ro() failed: %d\n", res);
        return res;
    }

    pr_info("init done\n");

    return 0;
}

static void __exit modexit(void)
{
    int res;

    pr_info("exit\n");

    res = set_page_rw((unsigned long)(syscall_table + __NR_read) & PAGE_MASK);
    if (res != 0) {
        pr_err("set_page_rw() failed: %d\n", res);
        return;
    }

    syscall_table[__NR_read] = original_read;

    res = set_page_ro((unsigned long)(syscall_table + __NR_read) & PAGE_MASK);
    if (res != 0)
        pr_err("set_page_ro() failed: %d\n", res);

    pr_info("goodbye\n");
}

module_init(modinit);
module_exit(modexit);
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Syscall hijack on arm64.");
MODULE_AUTHOR("Marco Bonelli");
MODULE_LICENSE("GPL");
//SPDX许可证标识符:GPL-3.0
#包含//模块{init,exit}()
#包括//此模块,模块版本。。。
#包括//printk(),pr_*()
#包括//kallsyms\u lookup\u name()
#包括//系统调用_*
#包括//struct pt\u regs
#包括//刷新\u tlb\u内核\u范围()
#include/{clear,set}_pte_bit(),set_pte()
#包括//vm\u取消映射\u别名()
#包括//struct mm\u struct,将\u应用于\u页面\u范围()
#include//IS_ENABLED()
#ifdef pr_fmt
#未定义pr_fmt
#恩迪夫
#定义pr_fmt(fmt)KBUILD_MODNAME:“fmt
静态结构mm_struct*init_mm_ptr;
静态syscall\u fn\u t*syscall\u表;
静态系统调用(原始读取);
/**********助手**********/
//从arch/arm64/mm/pageattr.c。
结构页面\更改\数据{
pgprot设置屏蔽;
pgprot清除遮罩;
};
//从arch/arm64/mm/pageattr.c。
静态整数更改页面范围(pte*ptep,无符号长地址,void*数据)
{
结构页面\更改\数据*cdata=数据;
pte_t pte=读取一次(*ptep);
pte=清除位(pte,cdata->清除掩码);
pte=设置pte位(pte,cdata->设置掩码);
set_pte(ptep,pte);
返回0;
}
//从arch/arm64/mm/pageattr.c。
静态整数更改内存公用(无符号长启动、无符号长大小、,
pgprot设置屏蔽、pgprot清除屏蔽)
{
结构页面\更改\数据;
int ret;
data.set_mask=set_mask;
data.clear\u mask=clear\u mask;
ret=将页面应用到页面范围(初始页面、开始、大小、更改页面范围和数据);
刷新\u tlb\u内核\u范围(开始,开始+大小);
返回ret;
}
//来自arch/arm64/mm/pageattr.c的简化集合\u memory\u rw()。
静态整数集\页面\ rw(无符号长地址)
{
vm_取消映射_别名();
返回uuu change_memory_common(地址、页面大小、uuu pgprot(PTE_WRITE)、uuu pgprot(PTE_RDONLY));
}
//arch/arm64/mm/pageattr.c中的简化集合\u memory\u ro()。
静态整型集合页面(无符号长地址)
{
vm_取消映射_别名();
返回uuu change_memory_common(地址、页面大小、uuu pgprot(仅PTE RDU)、_uuupgprot(PTE WRITE));
}
/**********实际模块**********/
静态长myread(常量结构pt_regs*regs)
{
pr_info(“read()调用\n”);
返回原始读数(regs);
}
静态int\uu init modinit(void)
{
国际关系;
请购单信息(“初始信息”);
//不应该失败。
init_mm_ptr=(struct mm_struct*)kallsyms_lookup_name(“init_mm”);
syscall_table=(syscall_fn_t*)kallsyms_lookup_name(“syscall_table”);
原始读取=系统调用表[\uuuuunr\uread];
res=set_page_rw((无符号长)(syscall_表)+