Как заблокировать скомпилированные классы Java, чтобы предотвратить декомпиляцию?
Как заблокировать скомпилированные классы Java, чтобы предотвратить декомпиляцию?
Я знаю, что это должна быть очень хорошо обсуждаемая тема в Интернете, но я не смог прийти к какому-либо выводу после обращения к ним.
Многие люди предлагают обфускатор, но они просто переименовывают классы, методы и поля с жесткими для запоминания последовательностями символов, но как насчет чувствительных постоянных значений?
Например, вы разработали компонент шифрования и дешифрования на основе метода шифрования на основе пароля. Теперь в этом случае любой средний Java-человек может использовать JAD для декомпиляции файла класса и легко получить значение пароля (определяемое как константа), а также соль и, в свою очередь, может расшифровать данные, написав небольшую независимую программу!
Или такие чувствительные компоненты должны быть встроены в нативный код (например, VC++) и вызывать их через JNI?
10 ответов
Некоторые из более продвинутых обфускаторов Java-байт-кода делают гораздо больше, чем просто искажение имен классов. Zelix KlassMaster, например, может также закодировать ваш поток кода таким образом, чтобы сделать его действительно трудным для понимания, и работает как отличный оптимизатор кода...
Также многие из обфускаторов также могут шифровать ваши строковые константы и удалять неиспользуемый код.
Другое возможное решение (не обязательно исключающее запутывание) заключается в использовании зашифрованных файлов JAR и пользовательского загрузчика классов, который выполняет дешифрование (предпочтительно с использованием собственной библиотеки времени выполнения).
В-третьих (и, возможно, предлагая самую надежную защиту), необходимо использовать собственные опережающие компиляторы, такие как, например, GCC или Excelsior JET, которые компилируют ваш код Java непосредственно в собственный двоичный файл конкретной платформы.
В любом случае нужно помнить, что, как говорится на эстонском языке, "замки для животных". Это означает, что каждый бит кода доступен (загружен в память) во время выполнения и при наличии достаточных навыков, решимости и мотивации, люди могут и будут декомпилировать, расшифровывать и взламывать ваш код... Ваша задача - просто сделать процесс настолько неудобным, как Вы можете и до сих пор держать вещь в рабочем состоянии...
Пока они имеют доступ как к зашифрованным данным, так и к программному обеспечению, которое их расшифровывает, практически невозможно обеспечить их полную безопасность. Пути, которые были решены ранее, - это использование некоторой формы внешнего черного ящика для обработки шифрования / дешифрования, например ключей, удаленных серверов аутентификации и т. Д. Но даже тогда, когда пользователь имеет полный доступ к своей собственной системе, это только делает вещи сложно, не невозможно - если только вы не можете напрямую привязать свой продукт к функциональности, хранящейся в "черном ящике", как, скажем, серверы онлайн-игр.
Отказ от ответственности: я не эксперт по безопасности.
Это звучит как плохая идея: вы позволяете кому-то шифровать данные с помощью "скрытого" ключа, который вы ему даете. Я не думаю, что это можно сделать безопасным.
Может быть, асимметричные ключи могут работать:
- развернуть зашифрованную лицензию с открытым ключом для расшифровки
- позволить клиенту создать новую лицензию и отправить ее вам для шифрования
- отправить новую лицензию обратно клиенту.
Я не уверен, но я верю, что клиент может фактически зашифровать лицензионный ключ с открытым ключом, который вы ему дали. Затем вы можете расшифровать его с помощью своего закрытого ключа, а также повторно зашифровать.
Вы можете сохранить отдельную пару открытых / закрытых ключей для каждого клиента, чтобы убедиться, что вы действительно получаете информацию от нужного клиента - теперь вы несете ответственность за ключи...
Независимо от того, что вы делаете, его можно "декомпилировать". Черт возьми, ты можешь просто разобрать его. Или посмотрите на дамп памяти, чтобы найти ваши константы. Видите ли, компьютер должен их знать, поэтому и ваш код тоже.
Что с этим делать?
Старайтесь не использовать ключ как жестко закодированную константу в своем коде: сохраняйте его как настройку для каждого пользователя. Сделайте пользователя ответственным за присмотр за этим ключом.
Взгляните на статью JavaWorld " Взлом шифрования байт-кода Java " Владимира Рубцова. Это объясняет, почему шифрование файлов классов в большинстве случаев бессмысленно.
@jatanp: или еще лучше, они могут декомпилировать, удалять лицензионный код и перекомпилировать. С Java я не думаю, что есть правильное, взломанное решение этой проблемы. Даже злой маленький ключик не смог бы предотвратить это с помощью Java.
Мои собственные бизнес-менеджеры беспокоятся об этом, и я слишком много думаю. Но опять же, мы продаем наше приложение крупным корпорациям, которые стремятся соблюдать условия лицензирования - как правило, безопасную среду благодаря счетчикам компонентов и юристам. Сам процесс декомпиляции может быть незаконным, если ваша лицензия написана правильно.
Итак, я должен спросить, действительно ли вам нужна усиленная защита, как вы ищете для своего приложения? Как выглядит ваша клиентская база? (Корпорации? Или массы геймеров-подростков, где это было бы больше проблемой?)
Если вы ищете решение для лицензирования, вы можете проверить TrueLicense API. Он основан на использовании асимметричных ключей. Однако это не означает, что ваше приложение не может быть взломано. Каждое приложение может быть взломано с достаточным усилием. Что действительно важно, как ответил Стю, выяснить, насколько сильная защита вам нужна.
Вы можете использовать шифрование байт-кода без страха.
Дело в том, что цитируемая выше статья "Взлом Java-шифрования байт-кода" содержит логическую ошибку. Основное требование статьи - перед запуском все классы должны быть расшифрованы и переданы ClassLoader.defineClass(...)
метод. Но это не так.
Предположение, пропущенное здесь, при условии, что они работают в аутентичной или стандартной среде выполнения Java. Ничто не может обязать защищенное Java-приложение не только запускать эти классы, но даже расшифровывать и передавать их ClassLoader
, Другими словами, если вы находитесь в стандартной JRE, вы не можете перехватить defineClass(...)
метод, потому что стандартный Java не имеет API для этой цели, и если вы используете модифицированный JRE с исправленным ClassLoader
или любой другой "хакерский трюк", который вы не можете сделать, потому что защищенное Java-приложение не будет работать вообще, и, следовательно, вам нечего будет перехватывать. И абсолютно неважно, какой "патч-искатель" используется или какой трюк используют хакеры. Эти технические детали - совсем другая история.
Я не думаю, что существует какой-либо эффективный метод борьбы с пиратством. Индустрия видеоигр пыталась найти это много раз, и их программы всегда были взломаны. Единственное решение заключается в том, что программа должна быть запущена в режиме онлайн, подключенной к вашим серверам, чтобы вы могли проверить ключ lincense, и что лицензиат имеет только одно активное соединение одновременно. Так работает World of Warcraft или Diablo. Даже несмотря на то, что существуют частные серверы, разработанные для обхода безопасности.
Сказав это, я не верю, что средние / крупные корпорации используют нелегально скопированное программное обеспечение, потому что стоимость лицензии на них минимальна (возможно, я не знаю, сколько вы собираетесь взимать за свою программу) по сравнению с стоимость пробной версии.
В: Если я зашифрую свои файлы.class и использую пользовательский загрузчик классов для загрузки и дешифрования на лету, это предотвратит декомпиляцию?
A: Проблема предотвращения декомпиляции байт-кода Java почти так же стара, как сам язык. Несмотря на широкий спектр инструментов запутывания, доступных на рынке, начинающие Java-программисты продолжают думать о новых и умных способах защиты своей интеллектуальной собственности. В этой статье, посвященной Java Q&A, я развеял некоторые мифы вокруг идеи, часто перефразированной в дискуссионных форумах.
Чрезвычайная легкость, с которой файлы Java.class могут быть реконструированы в исходные коды Java, которые очень похожи на оригиналы, во многом связана с целями и компромиссами проектирования байт-кода Java. Помимо прочего, байт-код Java был разработан для обеспечения компактности, независимости от платформы, мобильности сети и простоты анализа с помощью интерпретаторов байт-кода и динамических компиляторов JIT (точно в срок)/HotSpot. Возможно, скомпилированные файлы.class выражают намерение программиста настолько ясно, что их легче проанализировать, чем исходный код.
Можно сделать несколько вещей, если не полностью предотвратить декомпиляцию, по крайней мере, сделать ее более сложной. Например, в качестве шага после компиляции вы могли бы массировать данные.class, чтобы сделать байт-код трудным для чтения при декомпиляции или более сложным для декомпиляции в допустимый код Java (или оба). Такие методы, как выполнение экстремальной перегрузки имен методов, хорошо работают для первых и манипулируют потоком управления для создания структур управления, которые невозможно представить с помощью синтаксиса Java, хорошо работают для последних. Более успешные коммерческие обфускаторы используют сочетание этих и других методов.
К сожалению, оба подхода должны фактически изменить код, который будет запускать JVM, и многие пользователи опасаются (справедливо), что это преобразование может добавить новые ошибки в их приложения. Кроме того, переименование методов и полей может привести к прекращению работы вызовов отражений. Изменение фактических имен классов и пакетов может нарушить работу нескольких других API Java (JNDI (Java Naming and Directory Interface), поставщиков URL и т. Д.). В дополнение к измененным именам, если связь между смещениями байт-кода класса и номерами строк исходного кода изменяется, восстановление исходных трассировок стека исключений может стать затруднительным.
Тогда есть возможность запутать оригинальный исходный код Java. Но в основном это вызывает аналогичный набор проблем. Зашифровать, не запутать?
Возможно, вышеизложенное заставило вас задуматься: "Ну, что если вместо манипулирования байтовым кодом я зашифрую все свои классы после компиляции и расшифрую их на лету внутри JVM (что можно сделать с помощью специального загрузчика классов)? Тогда JVM выполняет мой оригинальный байт-код, и все же нечего декомпилировать или перепроектировать, верно?"
К сожалению, вы ошибаетесь, думая, что вы первыми предложили эту идею, и думая, что она действительно работает. И причина не имеет ничего общего с силой вашей схемы шифрования.