| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 216.73.216.86
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС своя операционная система своя ОС видио Tor Обратная сторона антенна 4.6 php эксплоит Windows Server 2008 QIP Virtual sysctl kernel Tune proc freeBSD monitoring LiveCD Disk GEO Bluetooth game emulator Python Shell червь Conficker вирус троян лаборатория касперского пиратство Apple iPhone Microsoft twitter социальная сеть анонимность лицензия Open Source уязвимость MySQL база данных Закон Франция Пират Skype мобильный хакер trend micro кибератака Германия робот искусственный интеллект Персональные данные Ноутбук Интернет китай цензура windows vista Linux патент TomTom браузер Firefox Internet Explorer Opera Safari Intel цахал патч Oracle Банкомат IBM США Dell контроль кибербезопасность приговор Mozilla Chrome безопасность Госдума СМИ КПРФ Windows 8 взлом Пентагон Украина Facebook Cisco Windows XP нетбук торрент музыка Биометрический Nokia ФБР IP-адрес sms RSA java Google Captcha Symantec Спам Антивирус тест Windows 7 операционная система windows провайдер авторское право rapidshare UNIX свиной грипп шантаж Дети Service Pack копирайт McAfee HTTPS icann студент Норвегия New York Times YouTube Warner Music КНДР БД Ubuntu касперский Россия РФ люди сервер хостинг верховный суд Wi-Fi суд пароль блог фишинг одноклассники Медведев контрафакт мошенник sony Gps по JavaScript Хакеры Yahoo фас компьютер софт Минкомсвязи Сбой мошенничество Доктор ВЕб Вконтакте Италия исходный код тестирование МВД фильтр порнография Outlook свобода слова казахстан сисадмин Autodesk Gmail кредитная карта LiveJournal шифрование банк Нанотехнологии wikipedia выборы DNS KaZaA Android атака Mac OS X домен ФСБ прокуратура уголовное дело ICQ Sophos Google Voice ошибка DARPA военные сайт Онлайн игра турция конференция спамер Полиция Koobface Перевод Великобритания IRC белоруссия Грузия Bittorrent Европа Билл Гейтс спецслужбы Royal Bank of Scotland смартфон F-Secure Symbian фильм Новая Зеландия Дата-центр Adobe Австралия IDC Internet Explorer 9 руткит iPad Рунет Ирландия поиск МТС Реклама слежка Zeus личные данные eset avast G Data Software защита Defcon виртуализация dll Черный список BlackBerry система защиты льготы индия Москва социальные сети flash player paypal BitDefender сертификат Евросоюз honda налог Anonymous технологии техника Чипы Ассанж передача данных Оптоволокно Xbox 360 арест nissan Samsung Иск акция конкуренция учетная запись Timeline iTunes исследование угрозы счетчик Санкт-Петербург климат SOPA PIPA NASA событие обвинение кража ico Megaupload отчет приложение паспорт правительство соглашение Инвестиции релиз платформа отключение Непал DRM Valve роскомнадзор выдача ИНСТРУМЕНТ

Главная » Статьи » Общие Статьи

Подмена системных вызовов в ядрах 2.6.х
Данная статья была написана в долгих и мучительных попытках реализовать подмену системного вызова sys_mkdir на ядре версии 2.6.23. Исходным шагом для нее стала работа dev0id-а о защите от исполнения в стеке ОС Linux (ссылку на статью можно найти в конце данной статьи). И как и говорил уважаемый dev0id, первоочередной задачей для нас стала подмена системных вызовов своими. Для примера (уж не знаю почему, возможно так сошлись звезды в созвездии стрельца) был выбран системный вызов sys_mkdir. Но для начала немного остановимся на том, как вообще писать модули.

Любой модуль должен обязательно состоять как минимум из двух функций: int init_module() и void cleanup_module(). Вообще данные функции можно заменить и своими, но в нашем случае мы не будем это рассматривать, как и то, что функция init_module может в себя принимать параметры как и функция main(). Я думаю, что из названия становится понятно, что функция init_module() вызывается в тот самый момент когда вы делаете /sbin/insmod, т.е. загружаете свой модуль в ядро. Ну и соответственно cleanup_module() происходит при выгрузке модуля из ядра.

Простейший же модуль выглядит так:

/*------------------------------------------------*/
#include
#include
/*------------------------------------------------*/
MODULE_LICENSE("GPL");
/*------------------------------------------------*/
int init_module(void)
{
printk("It`s our rules module :-)\n");
return 0;
}
/*------------------------------------------------*/
void cleanup_module(void)
{
printk("Our module was unload :-(\n");
}

В этом листинге вызывается макрос MODULE_LICENSE("GPL");, он вызывается для того, чтобы при загрузке модуля не было сообщения о неизвестной лицензии модуля. Теперь необходимо скомпилировать наш модуль, для этого создаем простой Makefile, содержащий всего одну строчку:

obj-m := simple_module.o, где simple_module нужно поменять на имя вашего исходника.

Теперь остается сделать

make -C путь_к_исходникам_ядра M=$PWD modules

У меня путь к исходникам /usr/src/kernels/2.6.23.15-80.fc7-x86_64, у вас он может быть другим.

Загрузим наш модуль в ядро командой /sbin/insmod название_модуля. Модули в ядрах 2.6.х имеют расширение .ko. На первый взгляд ничего не произошло, но это только на первый взгляд. Выполним команду dmesg | tail -n 1 для того, чтобы просмотреть сообщения ядра - как видите, наш модуль вывел «It`s our rules module :-)», а это значит у нас все получилось.

Теперь вернемся к основной нашей проблеме - когда динозавры были еще маленькие, а ядра имели версию 2.4.х., можно было без проблем вызывать любой системный вызов с помощью тогда еще экспортируемой Таблицы системных вызовов (sys_call_table). Однако в ядрах версии 2.6.х лафа закончилась и таблицу системных вызовов экспортировать перестали. Однако и ум человеческий не стоит на месте. И dev0id таки придумал, как убрать этот маленький недостаток. Дело в том, что вызов sys_close экспортируется, а так как адрес этого вызова находится как раз в таблице системных вызовов, то достаточно пробежаться в секции данных для того, чтобы найти необходимый нам адрес. Более подробно вы можете прочитать в статье dev0da, замечу лишь, что нужно немножко переделать данную функцию для того, чтобы она заработала на х86-64, как это сделать вы можете посмотреть в прилагаемом листинге.

Однако же на этом все проблемы и душевные терзания не закончились - дело в том, что попытавшись в лоб поменять адрес системного вызова, мне надавали пощечин, сказали «Ошибка сегментирования» и ко всему прочему в ядре остался модуль, который будет продолжать висеть там до перезагрузки. В связи с этим напрашивалось всего два решения: или бросить это гиблое дело, или попробовать переписать вызов sys_mkdir на лету. Но так как времени было много, а пива еще больше, было решено проверить возможность перезаписи системных вызовов. Сохраним первый байт функции sys_mkdir, что бы восстановить его при выгрузке модуля. Как и все гениальное это очень просто.

long* sys_call_table = find_sys_call_table();
// нашли адрес sys_call_table
_sys_mkdir = *(sys_call_table + __NR_mkdir);
// взяли адрес sys_mkdir
char old_first_byte = *((char*)_sys_mkdir);
// а вот и первый байт

Итак это готово, в общем случае можно записать по этому байту что угодно, однако, чтобы не получить при вызове команды mkdir ошибку сегментирования, было решено записать туда опкод команды ret, т.е. 0хс3. Загрузив модуль ошибки сегментирования получено не было, значит писать в эту функцию можно, теперь попробуем вызвать команду mkdir. В лучшем случае мы получаем ответ о том, что пропущен аргумент, в худшем команда вроде бы исполняется, но естественно никакой директории не создает. Отлично, значит можно в эту функцию, дописать что угодно, но что угодно не лучшее решение, поэтому нужно было дописать код, который бы вызывал нашу функцию, а затем делал ret чтобы предотвратить исполнение оставшейся части функции sys_mkdir. Сказано - сделано. Прежде всего пришлось разобраться с опкодами команд для процессоров Intel. В этом помогает статья об опкодах на wasm.ru. Значит дело осталось за малым - взять документацию по процессорам, которую Intel любезно предоставляет всем страждущим. На ассемблере код нашей новой функции выглядит так.

xor eax, eax ;(для х86-84 rax)
mov rax, адрес_нашей_функции
call rax ;вызвали нашу функцию
ret ;вернулись в функцию вызвавшую sys_mkdir

Вот и все, теперь смотрим опкоды инструкций для Интела. Для первой инструкции подходит опкод

31 /r XOR r/m32, r32 для 32 битной системы, и
REX.W + 31 /r XOR r/m64, r64 для 64 битной.

По суффиксу /r становится ясно, что необходимо задать следующим байтом оба операнда, байт этот получается 11 000 000, на wasm его называют ModR/M, не будем от этого отступать, все тонкости как он получается я не буду объяснять, так, как все это подробно описано в статье на wasm.ru. Для 64 битной же системы существует еще и префикс REX - как его получить вы можете также узнать из документации по процессорам Intel. Он просто должен быть равен 0х48. Значит для первой инструкции опкод получается 0х31 0хс0. Аналогично получаем опкод инструкции mov:

B8 +rd MOV r32, imm64 и
REX.W B8 +rd MOV r64, imm64

Так как мы используем регистр eax, то опкод инструкции так и есть 0x0b8 за которым следует адрес нашей функции. Если бы у нас был регистр ecx, то опкод был бы 0хb9, если edx то 0хba, ebx - 0xbb и т. д. Кстати, адрес нашей функции должен быть перевернут, так как в памяти байты хранятся в обратном порядке, т. е. если у вас был адрес 0х00a1b2c3d4e5f611 то он станет 0x11f6e5d4c3b2a100, от такие вот пироги.

Инструкция call:

FF /2 CALL r/m32 и
FF /2 CALL r/m64

Это говорит о том, что данная инструкция одинакова как для 32 так и для 64 битных платформ. Суффикс /2 говорит о том, что в байте ModR/M Reg должно всегда быть числом 2. Получаем Mod(11) Reg(010 = 2) R/M(000 = EAX). Получаем 0хd0. Значит опкод для обоих платформ будет 0xff 0xd0.

Ну и как я уже говорил остается ret. Её опкод 0хс3.

У нас получилось, что весь наш код занимает 16 байт для х86-64 и 10 для 32 битной платформы. Остается только сохранить эти байты для того, чтобы восстановить их после выгрузки модуля.

char old_commands[COMMANDS_COUNT];
memcpy(old_commands, (void *)sys_mkdir_ptr, COMMANDS_COUNT);

Вот вам в принципе и вся теория, позволяющая подменять системные вызовы в ядрах версии 2.6.х. Только не забывайте, что если вам понадобится использовать аргументы, которые передаются системному вызову, то взять их можно из регистров ebx — 1, ecx — 2 и т.д., а для этого функция должна быть как asmlinkage, в противном случае функция будет искать все аргументы в стеке. Ну и соответственно желательно бы, чтобы после отработки ваша функция таки вызывала оригинал, для этого достаточно перенести ее в другую область памяти. Вот и все, пора идти допивать оставшееся пиво :-).
Ссылки

Статья от dev0idа:

http://www.securitylab.ru/contest/212111.php

Статьи на wasm.ru:

http://www.wasm.ru/print.php?article=codech03
http://www.wasm.ru/print.php?article=codech04
http://www.wasm.ru/print.php?article=codech05

Документация от Intel:

http://www.intel.com/products/processor/manuals/index.htm

Исходники

Категория: Общие Статьи | Добавил: aka_kludge (08.07.2008)
Просмотров: 1861 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

19:14
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2026 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика