Перехват библиотечных функций в linux и bsd


         

/Dev/mem


Чтение документации ("man mem") показывает, что файл /dev/mem имеется практически на всех UNIX-подобных системах, а если его вдруг нет, он может быть создан в любой момент следующими командами:

mknod -m 660 /dev/mem c 1 1

chown root:kmem /dev/mem

Листинг 2 создание файла-устройства /dev/mem, предоставляющего доступ к физической памяти компьютера с прикладного уровня

Здесь: 660 – права доступа, /dev/mem – имя файла (может быть любым, например /home/kpnc/nezumi), "c" – тип устройства (символьное устройство), "1 1" – устройство (физическая память). Файл /dev/mem (или как вы его назовете) свободно доступен с прикладного уровня, но только для root, что есть саксь.

Структура файла предельно проста — линейные смещения соответствуют физическим адресам. Допустим, нам известно, что по адресу FFFFh:FFF0h во всех BIOS'ах хранится команда перехода на загрузочный код, а за ним (как правило) лежит дата создания прошивки. Переводим "сладкую парочку" сегмент:смещение в линейный вид (linear == seg*10h + offset), получаем FFFF0h. Это и будет смещение в файле.

Рисунок 2 чтение содержимого BIOS'а через файл /dev/mem

Основной камень преткновения в том, что оперативная память компьютера используется UNIX'ом как кэш и потому один и те же физические страницы в различное время могут соответствовать различным виртуальным адресам. Но это не проблема. Можно найти каталог страниц и выполнить трансляцию вручную. Указатель на текущий каталог храниться в регистре CR3, попытка доступа к которому с прикладного уровня возбуждает исключение, но поскольку каталог имеет довольно характерную структуру (описанную в документации на процессор), его легко найти простым сканированием физической памяти.

Часть виртуальных страниц, принадлежащих процессу, может быть выгружена на диск и тогда в файле /dev/mem ее не окажется. При хроническом недостатке оперативной памяти, значительный процент адресного пространства процесса попадает на диск и хотя совместно используемые библиотеки вытесняются в последнюю очередь, они все-таки вытесняются (особенно редко используемые функции). Это значит, что прежде чем ковыряться в /dev/mem необходимо загрузить соответствующую функцию в память. А как это сделать? Ну, например, просто вызывать ее. Вызов функции не гарантирует загрузки всех принадлежащих ей страниц, но нам этого и не надо! Достаточно, чтобы загрузилась первая страница (а она наверняка загрузится!), чтобы воткнуть в начало функции jump на свой thunk.




Содержание  Назад  Вперед