Системный шпионаж в *nix часть 1 Крис Касперски ака мыщъх Хакер, номер #087, стр. 087-134-2 o контроль за динамически загружаемыми библиотеками осуществляется путем перехвата функций dlopen/dlsym, экспортируемыми libdl.so.x, но фактически реализованных в libc.so.x (там они называются _dl_open/_dl_sym); o непубличные функции самой программы и статические библиотеки перехватываются путем внедрения команды jump thunk в их начало (естественно, оригинальное содержимое нужно где-то предварительно сохранить) с поиском по сигнатурам или с привязкой к фиксированным адресам; * отсоединяемся от процесса через ptrace (PTRACE_DETACH/PT_DEATACH, pid, 0, 0), позволяя ему продолжить нормальное выполнение, но теперь уже с модифицированной GOT, вызывающей функции через наш хакерский thunk, который может протоколировать вызовы, "мухлевать" с аргументами или даже передавать управление подложным функциям; Метод "модификации импорта" легко реализуется, надежен, но не освобожден от недостатков. В Windows функции ReadProcessMemory/WriteProcessMemory не требуют от процесса, чтобы он находился под отладкой, и подопытному приложению очень трудно им противостоять. Их Linux-аналоги являются частью библиотеки ptrace, обломать которую очень легко (см. мою статью "Методология защиты в мире UNIX", опубликованную в Хакере с год назад). К тому же подопытный процесс может вырваться из лап шпиона. Для этого ему достаточно породить дочерний процесс или сделать себе exec(), чтобы перезапуститься. В этом случае системный загрузчик перечитает исходный образ ELF-файла с диска, и все изменения в GOT'е будут потеряны. Чтобы этого не произошло, наш шпион должен следить за всеми потенциально опасными функциями, пускай и ценой усложнения реализации. И последнее (но самое главное) ограничение — шпионаж носит сугубо локальный характер и может контролировать только дочерние процессы или процессы, явно переданные ему на "съедение". А вот другой популярный прием, называемый методом "подмены библиотеки", также позаимствованный из мира Windows: * создаем "обертку" (wrapper) вокруг интересующей нас библиотеки, экспортирующей те же самые функции, что и она; * оригинальную библиотеку переименовываем или размещаем в другом месте; * функции-обертки определяют идентификатор вызывающего их процесса, и, если это действительно "их" процесс, совершают заранее запланированные действия (пишут вызов в log, подменяют аргументы или код возврата и т.д). Как определить id процесса? Это легко, ведь функции-обертки вызываются из контекста процесса, который их использует, и решение задачи сводится к выяснению идентификатора текущего процесса, возвращаемого функцией getpid(); * функция-обертка передает управление оригинальной функции основной библиотеки или своей собственной подложной функции; За внешней простотой реализации такого подхода кроется целый ворох проблем. Создать обертки вокруг всех "системных" библиотек вручную практически нереально, и эту работу необходимо автоматизировать, написав несложный парсер so-файлов и кодогенератор. Необязательно генерировать готовый ELF-файл, проще создать Си-программу и откомпилировать ее с помощью gcc. |