Программирование в Linux: Linux Kernel Modules #2: system_call (исходники)Источник: CodingClub
Данная статья является логическим продолжением предыдущей, так что для получения каких-то ответов на поставленные вопросы, не следует сразу писать мне - прочтите предыдущий материал. В предыдущей статье я писал, для чего используются модули, из чего состоят и, даже, привел самый простой пример... Но стоит заметить, что приведенный пример не являлся частью ядра (точнее код программы), так как в функции инициализации/деинициализации в код ядра ничего небыло добавленно (напомню, что при установке модуля выводилось сообщение). Как я уже говорил, модули добавляют/изменяют какие-то системные вызовы (функции). Именно об этом я и попытаюсь рассказать, но вначале немного теории. Допустим мы написали некий модуль, который должен изменить указатель в таблице на новую функцию-обработчик, которая теперь будет совершать некоторые действия предписанные предыдущей функции. Так как мы не знаем о том, заменен ли оригинал функции какой либо другой (до нас могли уже установить другой обработчик), существует возможность очень сильного повреждения ядра. Дело в том, что если кто-то уже заменил стандартный обработчик, то, допустим, после нашей установки, пользователь решил удалить свой модуль, при откате действий, "его" модуль попробует заменить указатель в таблице на предыдущий... Теперь давайте представим, что после этого мы решили также удалить наш модуль. Что будет при откате? Если мы плохие программисты (то мы не предохраняясь) востанавливаем указатель на старый "его" обработчик, которого, стоит заметить, уже нет в памяти... Это ведет к неминуемому исполнению произвольного кода на машине, так что во избежание таких несчастных случаев можно использовать хотя бы счетчик ссылок. Во вторых (оффтопик)... У человека всегда должна быть цель... сегодня она у меня есть - я исследую, я хакер... а завтра я умру... Начнем. Обычно для построения руткитов используют замену каких-либо системных вызовов... так поступим и мы... воспользовавшись командой "strace" мы получаем список всех системных вызовов использованных программой. В ядре существует место, куда передается управление из пользовательского процесса; такое место называется system_call. Здесь ядро проверяет номер системного вызова, по которому ядро определяет, какая функция требуется процессу. Далее просматривается таблица системных вызовов sys_call_table, для определения адреса системной функции в ядре. И, наконец, вызывается эта функция. Что же нам нужно для изменения работы некоторого системного вызова? Для начала нам нужно написать новую функцию для реализации системного вызова. Далее мы изменим указатель на нашу новую функцию в таблице системных вызовов sys_call_table. Давайте расмотрим пример. Пусть данная программа и не идеальна, но она наглядно показывает то, что показывает... Наша программа будет добавлять пользователя rootteam в файл /etc/passwd при каждом системном вызове open. Согласен, глупо, но это лишь демонстрация. ------------------------------------------CODE_START------------------------------------- // sys_open.c #include #if CONFIG_MODVERSIONS==1 /* ------------------------------------------CODE_ENDS-------------------------------------- Вот собственно и все... вполне рабочий руткит... хотя нет, забыл об одной детали. Так как нашему модулю передается параметр-UID пользователя от которого мы ждем вызова open, то установка модуля в систему происходит следующим образом: $/sbin/insmod uid=1000 -c sys_open.c |