Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
В ответ получим:
0xc0109050 <system_call+48>: 0xc02000520
Таким образом, найдя в файле /dev/kmem последовательность xffx14x85 и считав следующие за ней 4 байта, мы получим адрес таблицы системных вызовов sys_call_table. Зная ее адрес, мы можем получить содержимое этой таблицы (адреса всех системных функций) и изменить адрес любого системного вызова, перехватить его.
Рассмотрим псевдокод, выполняющий операцию перехвата:
readaddr (&old_syscall, sct + SYS_CALL*4, 4);
writeaddr (new_syscall, sct + SYS_CALL*4, 4);
Функция readaddr считывает адрес системного вызова из таблицы системных вызовов и сохраняет его в переменной old_syscall. Каждая запись в таблице sys_call_table занимает 4 байта. Искомый адрес расположен по смещению sct+SYS_CALL*4 в файле /dev/kmem (здесь sct – адрес таблицы sys_call_table, SYS_CALL – порядковый номер системного вызова). Функция writeaddr перезаписывает адрес системного вызова SYS_CALL адресом функции new_syscall, и все обращения к системному вызову SYS_CALL будут обслуживаться этой функцией.
Кажется, все просто и цель достигнута. Однако давайте вспомним, что мы работаем в адресном пространстве пользователя. Если разместить новую системную функцию в этом адресном пространстве, то при вызове этой функции мы получим красивое сообщение об ошибке. Отсюда вывод – новый системный вызов необходимо разместить в адресном пространстве ядра. Для этого необходимо: получить блок памяти в пространстве ядра, разместить в этом блоке новый системный вызов.
Выделить память в пространстве ядра можно при помощи функции kmalloc. Но вызвать напрямую функцию ядра из адресного пространства пользователя нельзя, поэтому воспользуемся следующим алгоритмом:
n зная адрес таблицы sys_call_table, получаем адрес некоторого системного вызова (например, sys_mkdir);
n определяем функцию, выполняющую обращение к функции kmalloc. Эта функция возвращает указатель на блок памяти в адресном пространстве ядра. Назовем эту функцию get_kmalloc;
n сохраняем первые N байт системного вызова sys_mkdir, где N – размер функции get_kmalloc;
n перезаписываем первые N байт вызова sys_mkdir функцией get_kmalloc;
n выполняем обращение к системному вызову sys_mkdir, тем самым запустив на выполнение функцию get_kmalloc;
n восстанавливаем первые N байт системного вызова sys_mkdir.
В результате в нашем распоряжении будет блок памяти, расположенный в пространстве ядра.
Функция get_kmalloc выглядит следующим образом:
struct kma_struc {
ulong (*kmalloc) (uint, int);
int size;
int flags;
ulong mem;
} __attribute__ ((packed));
int get_kmalloc(struct kma_struc *k)
{
k->mem = k->kmalloc(k->size, k->flags);