| RSS



Меню

Bookmark and Share


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





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

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

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 PHP Эксплоит Windows Server 2008 qip Virtual chroot kernel proc sysctl tune FreeBSD bridge Boot Disk Bluetooth GEO game directx Emulator Python Shell DDoS червь Conficker вирус троян Лаборатория Касперского пиратство apple iPhone ИТ-отрасль Щеголев Microsoft экономический кризис Twitter социальная сеть анонимность Лицензия Open Source ASP.NET MVC уязвимость MySQL база данных файлообмен закон франция пират Skype мобильный Deutsche Telekom Хакер киберпреступник Trend Micro кибератака Германия робот утечка данных персональные данные ноутбук интернет Китай цензура ядро Linux Торвальдс Windows Vista Acer Linux патент браузер Firefox Internet Explorer Opera Net Applications Safari Intel Linux Foundation Moblin Oracle патч банкомат кардер HSM IBM X-Force Cofee сша кибервойна Эстония Dell ИТ-специалист хакерские атаки Pirate Bay контроль кибербезопасность язык программирования The Pirate Bay Пиратская партия утечка информации приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 Баллмер взлом Пентагон ботнет Украина Facebook Cisco cloud Windows XP нетбук торрент музыка биометрический nokia ФБР IP-адрес CIPAV Comcast sms RSA java Google CAPTCHA Symantec спам конфиденциальная информация инсайдер Perimetrix антивирус тест Anti-Malware Windows 7 операционная система Windows провайдер авторское право RapidShare UNIX свиной грипп шантаж дети EFF BluWiki копирайт экстремизм Panda Security cloud computing McAfee Cybercrime Response Unit Bottle Domains HTTPS ICANN студент шпионское ПО Норвегия школьник New York Times XSS YouTube Warner Music кибершпионаж КНДР Ubuntu свободное ПО AMD ATI касперский Россия РФ сервер хостинг фальшивый антивирус Comodo CA Wi-Fi D-Link суд пароль блог фишинг Одноклассники медведев контрафакт мошенник штраф Sony GPS по Gumblar JAVASCRIPT хакеры вредоносное ПО Yahoo ФАС компьютер Софт MPAA кибероружие PandaLabs Red Hat Минкомсвязи сбой ASUSTeK Computer мошенничество Доктор Веб ВКонтакте Cyber-Arc исходный код PCI DSS МВД фильтр порнография BREIN свобода слова Казахстан GEMA Autodesk сисадмин Gmail кредитная карта кибермошенник LiveJournal шифрование криптография Deep Purple банк нанотехнологии Wikipedia zero-day ColdFusion выборы кража данных DNS BIND Android BASIC атака Black Hat Mac OS X Click Forensics Clampi домен фсб Прокуратура Уголовное дело icq Barrelfish киберпреступность Sophos AT&T ошибка Electa Gamma Knife OpenBSD DARPA военные Сайт Visual Studio 2010 .NET Framework 4 Chrome OS электронная почта турция конференция спамер FTC полиция российская ОС Koobface Великобритания БЕЛОРУССИЯ грузия BSA Bittorrent облачные вычисления Azure Европа Dr.Web Билл Гейтс спецслужбы Cryzip Живой Журнал Royal Bank of Scotland смартфон Canonical Pwn2Own F-Secure Symbian Hotmail фильм

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

Подмена системных вызовов в ядрах 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)
Просмотров: 1761 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

02:55
Обновить


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

Поиск


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