通过修改pte页表属性使内存可写
一、相关API
/*
 * Lookup the page table entry for a virtual address. Return a pointer
 * to the entry and the level of the mapping.
 *
 * Note: We return pud and pmd either when the entry is marked large
 * or when the present bit is not set. Otherwise we would return a
 * pointer to a nonexisting mapping.
 */
pte_t *lookup_address(unsigned long address, unsigned int *level)
{
        return lookup_address_in_pgd(pgd_offset_k(address), address, level);
}
EXPORT_SYMBOL_GPL(lookup_address);

#define _PAGE_PRESENT   0x001
#define _PAGE_NEWPAGE   0x002
#define _PAGE_NEWPROT   0x004
#define _PAGE_RW        0x020
#define _PAGE_USER      0x040
#define _PAGE_ACCESSED  0x080
#define _PAGE_DIRTY     0x100
#define _PAGE_PROTNONE  0x010 

lookup_address通过传入的虚拟地址找到对应的页表项,通过修改页表项的属性来修改对应物理读写属性。

二、修改内存写保护并hook 系统调用mkdir
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kallsyms.h>

unsigned long *sys_call_table = NULL;
unsigned long (*orig_mkdir)(const char __user *path, int mode);

static int make_memory_rw(unsigned long address)
{
	unsigned int level = 0;	
	pte_t *pte = NULL;

	pte = lookup_address(address, &level);
	if(pte == NULL) {
		printk("%s: get pte failed\n", __func__);
		return -1;
	} 
	
	if(pte->pte & ~_PAGE_RW)
		pte->pte |= _PAGE_RW;

	return 0;
}

static int make_memory_ro(unsigned long address)
{
	unsigned int level = 0;	
	pte_t *pte = NULL;

	pte = lookup_address(address, &level);
	if(pte == NULL) {
		printk("%s: get pte failed\n", __func__);
		return -1;
	} 
	
	pte->pte &= ~_PAGE_RW;

	return 0;
}

asmlinkage long hook_mkdir(const char __user *path, int mode)
{
	printk("%s: the mkdir has been hook\n", __func__);

	return orig_mkdir(path, mode);
}

static int __init lkm_init(void)
{

	sys_call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table");
	if(sys_call_table == NULL) {
		printk("%s: can not find sys_call_table address\n", __func__);
		return -1;
	}
	printk("%s: sys_call_addr = 0x%lx\n", __func__, sys_call_table);

	orig_mkdir = (unsigned long)(sys_call_table[__NR_mkdir]);
	make_memory_rw((unsigned long)sys_call_table);
	sys_call_table[__NR_mkdir] = (unsigned long)hook_mkdir;
	make_memory_ro((unsigned long)sys_call_table);

	return 0;
}

static void __exit lkm_exit(void)
{
	make_memory_rw((unsigned long)sys_call_table);
	sys_call_table[__NR_mkdir] = (unsigned long)orig_mkdir;
	make_memory_ro((unsigned long)sys_call_table);

	printk("Goodbye\n");
}

module_init(lkm_init);
module_exit(lkm_exit);

MODULE_LICENSE("GPL");
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐