需要左值作为赋值的左操作数-函数指针

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

我正在为内核编程和内存管理类编写家庭作业。我需要动态获取sys_call_table地址并安装一个简单的钩子,该钩子在打印一些文本后立即调用原始的sys_call(在这种情况下为sys_read)。

首先,我使用grep和/boot/System.map对获得的sys_call_table地址进行了硬编码,并遵循了一些我在网上找到的代码示例:

  1. https://gajastechnologies.blogspot.com/2016/12/basics-of-making-rootkit-from-syscall.html
  2. https://syprog.blogspot.com/2011/10/hijack-linux-system-calls-part-iii.html

这些帖子对sys_call_table地址有不同的看法,即一个使用单个指针,而另一个使用双指针。但是,在两种情况下,我都得到分配lvalue required as left operand of assignment的错误original_read = table[__NR_read];

  • 我的错误在哪里?较新的内核有什么变化吗?

  • 您会注意到我留下了两种禁用只读存储器的方法保护,都适合较新的5.X 32位内核?

  • 如何动态获取sys_call_table在代码中,什么将用作参考?我没能力在较新版本的导出的sys_calls上查找信息。我发现经常使用sys_close,但是编译器无法识别它,建议改用ksys_close

代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/compat.h>
#include <asm/uaccess.h>
#include <uapi/asm/unistd.h>

#include <asm/cacheflush.h>
#include <linux/highmem.h>
#include <asm/pgtable_types.h>

#define DISABLE_W_PROTECTED_MEMORY \
    preempt_disable(); \
    barrier(); \
    write_cr0(read_cr0() & (~ 0x00010000));

#define ENABLE_W_PROTECTED_MEMORY \
    write_cr0(read_cr0() | 0x00010000); \
    barrier(); \
    preempt_enable();

MODULE_LICENSE("GPL");

asmlinkage long *original_read(unsigned int fd, char __user *buf, size_t count);
asmlinkage long modified_read(unsigned int fd, char __user *buf, size_t count) {
    pr_info("sys_read\n");
    return original_read(fd, buf, count);
}

void **table = (void *)0xc16e7180;

/*Make page writeable*/

int make_rw(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    if(pte->pte &~_PAGE_RW){
        pte->pte |=_PAGE_RW;
    }
    return 0;
}

/* Make the page write protected */

int make_ro(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte = pte->pte &~_PAGE_RW;
    return 0;
}

static int __init mod_init(void)
{
    make_rw((unsigned long)table);
    original_read = table[__NR_read];
    table[__NR_read] = modified_read;
    return 0;
}
static void __exit mod_exit(void)
{
    table[__NR_read] = original_read;
    make_ro((unsigned long)table);
}

module_init(mod_init);
module_exit(mod_exit);

编辑:

我将修复程序应用于函数指针,并编辑了代码以匹配第二个链接中显示的代码。尽管在modified_read中运行了一些示例C代码,但dmesg中的打印从未出现在read()中。另外,如果删除用于写保护内存的宏(并保留make_romake_rw),则代码在insmod上崩溃。我把两者都留在那里,以供参考。有什么建议吗?

#define DISABLE_W_PROTECTED_MEMORY \
    preempt_disable(); \
    barrier(); \
    write_cr0(read_cr0() & (~ 0x00010000));

#define ENABLE_W_PROTECTED_MEMORY \
    write_cr0(read_cr0() | 0x00010000); \
    barrier(); \
    preempt_enable();

asmlinkage long (*original_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage long modified_read(unsigned int fd, char __user *buf, size_t count) {
    pr_info("sys_read\n");
    return original_read(fd, buf, count);
}

unsigned long *table = (unsigned long*)0xc16e7180;

int make_rw(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    if(pte->pte &~_PAGE_RW){
        pte->pte |=_PAGE_RW;
    }
    return 0;
}

int make_ro(unsigned long address){
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte = pte->pte &~_PAGE_RW;
    return 0;
}

static int __init mod_init(void)
{
    DISABLE_W_PROTECTED_MEMORY
    make_rw((unsigned long)table);
    original_read = (void*)*(table + __NR_read);
    *(table + __NR_read) = (unsigned long) modified_read;
    make_ro((unsigned long)table);
    ENABLE_W_PROTECTED_MEMORY
    return 0;
}
static void __exit mod_exit(void)
{
    DISABLE_W_PROTECTED_MEMORY
    make_rw((unsigned long)table);
    *(table + __NR_read) = (unsigned long) original_read;
    make_ro((unsigned long)table);
    ENABLE_W_PROTECTED_MEMORY
}

module_init(mod_init);
module_exit(mod_exit);
c linux kernel function-pointers system-calls
1个回答
3
投票

original_read是一个函数。您不能分配给功能。例如,您无法执行printf = something;

[您似乎想让original_read成为函数指针。要声明函数指针,您需要额外的一组括号:

    asmlinkage long (*original_read)(unsigned int fd, char __user *buf, size_t count);
                    ^              ^
© www.soinside.com 2019 - 2024. All rights reserved.