在ARM64上的Linux内核中不能使用set_memory_rw

问题描述 投票:0回答:1

我正在尝试开发一个挂接read()系统调用的内核模块。由于某些原因,set_memory_rw()功能似乎不起作用。

我看到了另一个此类问题,但我并不十分了解该怎么做。

我正在使用Raspberry-pi 4开发Kali 4.19.93

我的代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/slab.h>
#include <linux/kern_levels.h>
#include <asm/unistd.h>
#include <asm/cacheflush.h>
#include <linux/semaphore.h>
#include <asm/set_memory.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Omri Ben David");
MODULE_DESCRIPTION("Hooking Linux System calls");
MODULE_VERSION("1.0");

unsigned long** SYS_CALL_TABLE = (unsigned long**) 0xc02011c4;

asmlinkage ssize_t (*original_read) (int fd, char *buf, size_t count);
asmlinkage ssize_t HookRead(unsigned int fd, char * buf, size_t count)
{
    printk(KERN_INFO "Rootkit_Debug: Yay you entered my function!!\n Now you can read\n");
    return (*original_read)(fd,buf,count);
}   

void (*seek)(unsigned long, int);
void (*hide)(unsigned long, int);

static int __init SetHooks(void)
{
    printk(KERN_INFO "Hooks Will now be set, hold on tight\n");
    printk(KERN_INFO "System calls table is at address %p\n",SYS_CALL_TABLE);

    original_read = (void*) SYS_CALL_TABLE[__NR_read];

    seek = (void*) kallsyms_lookup_name("set_memory_rw");
    hide = (void*) kallsyms_lookup_name("set_memory_ro");

    (*seek)((unsigned long)SYS_CALL_TABLE, 1);
    SYS_CALL_TABLE[__NR_read] = (unsigned long*)HookRead;
    (*hide)((unsigned long)SYS_CALL_TABLE, 1);
    printk(KERN_INFO "System calls hooked successfully\n");

    return 0;
}

static void __exit HookCleanup(void)
{
    printk(KERN_INFO "System calls restore innitiated\n");

    (*seek)((unsigned long)SYS_CALL_TABLE, 1);
    SYS_CALL_TABLE[__NR_read] = (unsigned long*) original_read;
    (*hide)((unsigned long)SYS_CALL_TABLE, 1);

    printk(KERN_INFO "System successfully restored. hope you had fun");
}

module_init(SetHooks);
module_exit(HookCleanup);

如何使set_memory_rw()函数起作用以覆盖syscall表?还是应该使用其他方法?

c linux-kernel hook system-calls rootkit
1个回答
0
投票

因此,正如我在上面的评论中所说,似乎函数change_memory_common()(由change_memory_common()使用)在应用请求的权限之前进行了检查。这是带有注释的文档:

set_memory_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()并不驻留在此类映射中。

关注点似乎与TLB冲突有关。我真的不确定为什么自功能sys_call_table以来,这会导致TLB冲突,但是我不是ARM专家,所以我可能会丢失一些东西。我想可以打电话给seems to properly call flush_tlb_kernel_range(),但似乎是不必要的。欢迎任何其他见解!

[在任何情况下,出于练习syscall劫持的目的,您都可以重写自己的flush_tlb_kernel_range()flush_tlb_all()版本,避免进行此检查。一种更简单的方法是只为所需的地址获取适当的PTE,然后更改权限,但是我并没有浏览所有不计其数的宏。

最后,但并非最不重要,因为flush_tlb_all()最终可能会跨越页面边界,所以在对页面应用更改时最好使用set_memory_common()而不是仅使用set_memory_rw/ro()

这是一个有效的示例:

sys_call_table
© www.soinside.com 2019 - 2024. All rights reserved.