[Linux] Сплайсинг в ядре

Left4Dead

(L3) cache
Пользователь
Регистрация
08.05.2010
Сообщения
259
Реакции
3
Кому-то интересна разработка LKM-руткитов для Linux? Пытался сделать сплайсинг на CentOS 6.0 2.6.32-71.29.1.el6.i686, возникла проблема доступа к важным кускам памяти ядра (unable to handle kernel paging request), выяснилось что
The Linux kernel attempts to protect portions of its memory
from unexpected modification (through potential future exploits)
by setting areas read-only where the compiler has allowed it.
This ... reduces the number of easily writable kernel memory
targets for attackers.

CONFIG_DEBUG_RODATA=y is the default in RHEL/CentOS (they disable for debug kernel) [2] and in Debian/Ubuntu [3].

проблема решилась предварительным снятием RO-бита с соотв. страницы памяти через lookup_address (2.6.26+):

Код:
...

void set_addr_rw(unsigned long addr)
{
	unsigned int level;
	pte_t *pte = lookup_address(addr, &level);
	if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
}


int splice_func(unsigned char *old_func_ptr, unsigned char *my_func_ptr)
{
	int offset;  
	struct splice_struct *splice_ptr = NULL;
	splice_ptr = kmalloc(sizeof(struct splice_struct), GFP_KERNEL);
	if(!splice_ptr) return 0; 

	lock_kernel();
	memset(splice_ptr, 0, sizeof(struct splice_struct));
	memcpy(&splice_ptr->save_data, old_func_ptr, 5);
	splice_ptr->modified_address = old_func_ptr;
	list_add(&splice_ptr->list, &splice_func_list);
	offset = (int)my_func_ptr - ((int)old_func_ptr+5);
	set_addr_rw((unsigned long)old_func_ptr);
	set_addr_rw((unsigned long)old_func_ptr+1);
	set_addr_rw((unsigned long)old_func_ptr+2);
	set_addr_rw((unsigned long)old_func_ptr+3);
	set_addr_rw((unsigned long)old_func_ptr+4);
	*old_func_ptr = 0xE9;
	old_func_ptr++;
	memcpy(old_func_ptr, &offset, 4);
	unlock_kernel();
	return 1;
}

...
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх