通过修改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");