Pull to refresh

Comments 26

Вообще круто!
P.S. но «Загрузка динамической библиотеки из памяти в Linux» звучит как будто вы загружаете что-то в сам Linux
Ни один из вариантов с созданием файла не является безопасным, так как можно подменить файл между проверкой подписи и его загрузкой


Не согласен. Кто может подменить файл? При правильно выставленных правах на файл — только процесс с правами root или с правами этого пользователя. Если вы не доверяете root, то о любой безопасности на данной системе можно забыть. Если вы не доверяете другим программам этого же пользователя — аналогично.
Здесь моей целью было защитить программу от несанкционированного копирования и снятия ограничений, а не от подмены кода вредоносной программой. Да, я не доверяю руту. Насчет «о безопасности можно забыть»… в чем-то вы правы. Обеспечить проверку доверенности всего выполняемого кода достаточно сложно.

Для загрузки постороннего кода в приложение в линуксе есть как минимум следующие пути:
1. Банальный LD_PRELOAD. От него можно защититься, модифицировав загрузчик.
2. Подмена системных библиотек. Слинковать с библиотеками в рантайме, перед загрузкой проверяя подпись собственных копий библиотек.
3. ptrace. В качестве побочного эффекта этот код препятствует отладке, но этого недостаточно.
4. Запись через /dev/mem или /proc/../mem. От этого не защититься, поэтому надо контролировать целостность образа достаточно хитрым образом.
5. Патч исполняемого файла на диске. Контроль такой же, как в случае 4.
5. Экзотические варианты типа ядерного модуля. Ну тут уже делать нечего.
> 2. Подмена системных библиотек. Слинковать с библиотеками в рантайме, перед загрузкой проверяя подпись собственных копий библиотек
Что будет после обновления системных библиотек. Ваша програма будет работать пока вы будете её поддерживать, а после окончания срока поддержки первый же апдейт всё сломает.
Я понимаю желание защитить свою работу, но к сожаление как по мне вы больше неудобств оставите легальным пользователям.
Многие коммерческие программы под линукс таскают с собой заведомо рабочие копии библиотек, чтобы такого не было.
Ага, а потом в один прекрасный день разработчики ядра закрывают какую-то багу изменив системный вызов и мы остаёмся с нерабочей версией програмы. Вы знаете я 10 раз подумаю чем купить софт с такой защитой, потому что проблемы будут в первую очередь у легальных пользователей. Мне нужно ставить именну ту ОС и в той версии на которой вы тестировали, а иначе ни черта не бедт работать скорее всего.
Разве в linux нельзя открыть файл на чтение так, чтобы его нельзя было модифицировать/удалять пока он не закрыт?
А можно открыть файл с блокировкой по записи, проверить подписи и не закрывая его загрузить как библиотеку? Просто любопытно т.к. под Linux никогда не писал, а под Windows я бы сделал именно так.
Ну или проверять подпись файла вместе с датой последнего его изменения уже после загрузки библиотеки но до ее вызова?
А кто мешает эту самую дату изменить на любую другую? И проверить после загрузки нельзя, о чем я и написал в статье: еще до возврата из dlopen вызываются конструкторы, которые могут делать, что угодно. Например, конструктором можно пропатчить проверку, чтобы плагин прошел проверку и нормально загрузился.
Это не имеет никакого значения. Кто может подменить файл при правильно выставленных правах? Администратор или другие программы текущего пользователя. Если мы не доверяем администратору, то наши проверки подписей бесполезны. Если не доверяем другим программам — тоже.
Запускаем программу под отладчиком, ставим бряк на open. Снимаем флаг блокировки. Ставим бряк на dlopen. Продолжаем выполнение. Меняем файл, как угодно. Продолжаем выполнение. Непроверенный код успешно загружен. Это можно даже скриптом gdb автоматизировать. Так что нет, нельзя.
Ох, ну если по условиям задачи программу можно запускать под отладчиком, тогда никакая защита не спасет. В том числе и загрузка библиотек через память — против лома нет приема :)
Блин, да это же быдлокод в исконном стиле виндоуз с ручной правкой всяких там таблиц импорта и внедрением в чужую память… я не очень понимаю исходной задачи, у вас видимо цель защититься от копирования/декомпиляции/подмены файла на клиенте? Ибо нормальные программы держат свои плагины там, где только если root может их подменить.
Да, для защиты от копирования. В ответе на комментарий выше я расписал подробнее.
А вообще, самый красивый способ сделать это — написать свой ELF-загрузчик. Это не особо сложно и не зависит от внутренностей системы, но зависит от платформы. Но мне нужен был именно загрузчик в ld.so.
Код конечно интересный, но извините, это мартышкин труд.
Если рут может патчить плагины — почему он не сможет пропатчить ваш основной эльф и отключить вот эту вашу проверку?
Именно поэтому нужен дополнительный контроль целостности основного эльфа, что я и написал в комментарии выше.
Послушайте. если я уже и так патчу ваш эльф, что мне мешает заодно отключить самопроверку?
Если вы знаете, как она должна выглядеть и где она — ничего. Абсолютной защиты не бывает, любая защита отсекает людей ниже определенного уровня.
А еще я могу дампнуть лицензионный образ из памяти после прохождения всех проверок и распространять его.
Хотите действительно серьезной защиты — делайте не программу, а сервис, часть функций которого крутится на ваших серверах. И хорошо платите админам и программистам, чтобы не растащили как многие ММО игры.
Вот про дамп-то я и не подумал. Значит, подумаю в сторону чего-нибудь SaaS-подобного.
Против дампа есть динамическое шифрование машинного кода, при котором программа вообще никогда не бывает в памяти полностью распакованной. Но это уже совсем черная магия с кучей подводных камней.
Мой вам совет — лучше думайте в сторону хорошего продукта, а не хорошо защищенного продукта.
С дампом не все так просто. Программа уже успела запуститься, изменить переменные и.т.д. Если вы просто запустите такой дамп с оригинальной точки входа — он упадет. Снятие дампа и превращение его в работающую программу — это целое искусство.
Не буду повторять вопросов о целесообразности данного подхода, высказанных выше.
У меня небольшая заметка по реализации. Так как вы сказали что не доверяете руту, то использование некриптографического генератора случайных чисел (rand()) является серьезной уязвимостью, так как с легкостью может быть предсказанно, даже после использования seed(time()).
Имя библиотеки тут исключительно для создания уникального имени в пределах процесса. ld.so ищет файл в первую очередь по абсолютному пути, так что он сразу натыкается на псевдофайл и не грузит ничего с диска.
Sign up to leave a comment.

Articles