Я работаю над домашней работой по программированию ядра и классам управления памятью. Мне нужно динамически получить адрес sys_call_table
и установить простой хук, который вызывает оригинальный sys_call (в данном случае sys_read
) сразу после печати некоторого текста.
Для начала я жестко закодировалsys_call_table
адрес, который я получил с помощью grep и /boot/System.map и следовал за некоторыми примерами кода, которые я нашел в Интернете:
- https://gajastechnologies.blogspot.com/2016/12/basics-of-making-rootkit-from-syscall.html
- 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];
Где моя ошибка? Что-то изменилось для более новых ядер?
Вы заметите, что я оставил два метода для отключения защиты памяти только для чтения, оба подходят для более новых 32-битных ядер 5.X?
Как можно получить динамическое получение 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
никогда не появляется в dmesg
, несмотря на запуск некоторого примера кода C с read()
. Кроме того, если я удаляю макросы для памяти, защищенной от записи (и оставляю make_ro
, make_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);