Как заблокировать скомпилированные классы Java, чтобы предотвратить декомпиляцию?

98

Как заблокировать скомпилированные классы Java, чтобы предотвратить декомпиляцию?

Я знаю, что это должна быть очень хорошо обсуждаемая тема в Интернете, но я не мог прийти к какому-либо выводу, направив их.

Многие люди предлагают обфускатор, но они просто переименовывают классы, методы и поля с помощью сложных для запоминания последовательностей символов, но как насчет чувствительных значений констант?

Например, вы разработали компонент шифрования и дешифрования, основанный на методе шифрования на основе пароля. Теперь в этом случае любой средний Java-человек может использовать JAD для декомпиляции файла класса и легко получить значение пароля (определенное как константа), а также соль и, в свою очередь, может расшифровать данные, написав небольшую независимую программу!

Или такие чувствительные компоненты должны быть встроены в собственный код (например, VC ++) и вызывать их через JNI ?

джатанп
источник
Даже дизассемблированный собственный код в любом случае вполне читаем для некоторых людей, вам, вероятно, придется использовать какой-то обфускатор или ручную сборку, чтобы сделать его неочевидным (обычный C ++, скомпилированный с оптимизацией, достаточно читабелен). Какой бы код ни выполнялся на устройстве пользователя, его можно перехватить. Хотя требования по стоимости / навыкам такого перехвата могут быть довольно высокими, например, взлом кода микросхемы смарт-карты, защищенного от несанкционированного доступа, не является тривиальным делом, его можно выполнить только с помощью высшего оборудования и навыков. С классами Java ... Я бы особо не заморачивался, вы, вероятно, можете зашифровать их достаточно, чтобы отпугнуть детей скриптов, не больше.
Ped7g

Ответы:

97

Некоторые из более продвинутых обфускаторов байт-кода Java делают гораздо больше, чем просто изменение имени класса. Zelix KlassMaster , например, также может скремблировать поток кода таким образом, чтобы за ним было действительно трудно следить, и работает как отличный оптимизатор кода ...

Также многие из обфускаторов также могут шифровать ваши строковые константы и удалять неиспользуемый код.

Другое возможное решение (не обязательно исключающее обфускацию) - использовать зашифрованные файлы JAR и специальный загрузчик классов, который выполняет расшифровку (предпочтительно с использованием собственной библиотеки времени выполнения).

В-третьих (и, возможно, предлагая наиболее надежную защиту), является использование встроенных опережающих компиляторов, таких как, например, GCC или Excelsior JET , которые компилируют ваш Java-код непосредственно в собственный двоичный файл платформы.

В любом случае следует помнить, что по-эстонски говорится: «Замки - для животных». Это означает, что каждый бит кода доступен (загружен в память) во время выполнения и при наличии достаточных навыков, решимости и мотивации люди могут и будут декомпилировать, расшифровывать и взламывать ваш код ... Ваша задача просто сделать процесс настолько неудобным, насколько вы можете и по-прежнему поддерживать работу ...

Роланд Тепп
источник
14
+1 за «Замки для животных». Я полагаю, что подходящим термином здесь были бы сценаристы.
Сурьма
Вы имеете в виду GCJ, а он мертв.
Маркиз Лорн
1
Шифрование файла Componio jar тоже мертво. Вместо этого используйте JarProtector .
J.Profi
16

Пока у них есть доступ как к зашифрованным данным, так и к программному обеспечению, которое их расшифровывает, вы практически не можете сделать это полностью безопасным. Способы, которыми это было решено ранее, - это использование какой-либо формы внешнего черного ящика для обработки шифрования / дешифрования, например ключей, удаленных серверов аутентификации и т. Д. Но даже тогда, учитывая, что пользователь имеет полный доступ к своей собственной системе, это только делает вещи сложно, но возможно - если вы не можете напрямую привязать свой продукт к функциям, хранящимся в «черном ящике», как, скажем, игровые серверы онлайн.

Эрленд Халворсен
источник
13

Отказ от ответственности: я не эксперт по безопасности.

Это звучит как плохая идея: вы позволяете кому-то шифровать данные с помощью «скрытого» ключа, который вы ему даете. Я не думаю, что это можно сделать безопасным.

Возможно, асимметричные клавиши могут работать:

  • развернуть зашифрованную лицензию с открытым ключом для расшифровки
  • позволить клиенту создать новую лицензию и отправить ее вам для шифрования
  • отправить клиенту новую лицензию.

Я не уверен, но я считаю, что клиент действительно может зашифровать лицензионный ключ с помощью открытого ключа, который вы ему дали. Затем вы можете расшифровать его своим закрытым ключом, а также повторно зашифровать.

Вы можете сохранить отдельную пару открытого / закрытого ключей для каждого клиента, чтобы убедиться, что вы действительно получаете данные от нужного клиента - теперь вы несете ответственность за ключи ...

Дарен Томас
источник
2
Я использовал эту технику раньше, и она отлично работает. Однако с точки зрения атаки первым подходом было бы просто изменить код, выполняющий проверку лицензии, и удалить его. Есть вещи, которые вы можете сделать, чтобы усложнить этот вектор атаки, но если вы предоставите злоумышленнику контроль над оборудованием, вам суждено потерпеть неудачу с соответствующим мотивированным и опытным злоумышленником. На практике цель состоит в том, чтобы сохранить честность в основном честных людей.
Джим Раш,
12

Что бы вы ни делали, его можно «декомпилировать». Черт возьми, его можно просто разобрать. Или посмотрите на дамп памяти, чтобы найти свои константы. Видите ли, компьютер должен их знать, значит, ваш код тоже должен это знать.

Что с этим делать?

Старайтесь не поставлять ключ как жестко заданную константу в своем коде: сохраните его как настройку для каждого пользователя. Возложите на пользователя ответственность за присмотр за этим ключом.

Дарен Томас
источник
6

@jatanp: или, что еще лучше, они могут декомпилировать, удалить код лицензирования и перекомпилировать. Я не думаю, что с Java есть правильное и надежное решение этой проблемы. Даже маленький злой ключ не смог бы предотвратить это с Java.

Мои собственные бизнес-менеджеры беспокоятся об этом, и я слишком много думаю. Но с другой стороны, мы продаем наше приложение крупным корпорациям, которые, как правило, соблюдают условия лицензирования - как правило, безопасная среда благодаря счетчикам и юристам. Сам акт декомпиляции может быть незаконным, если ваша лицензия написана правильно.

Итак, я должен спросить, действительно ли вам нужна усиленная защита, как вы ищете для своего приложения? Как выглядит ваша клиентская база? (Корпорации? Или подростковые массы игроков, где это будет более серьезной проблемой?)

Стю Томпсон
источник
На самом деле, есть подходящее, защищенное от взлома решение, которое, кстати, выглядит как электронный ключ: excelsior-usa.com/blog/excelsior-jet/…
Дмитрий Лесков
Может быть, @DmitryLeskov «устойчив к взлому». Но это всего лишь «лежачий полицейский» для всех, кто хочет знать код. В конце концов, байт-код должен выполняться на хост-платформе в незашифрованном виде. Полная остановка.
Стю Томпсон
Вы не читали сообщение, на которое я ссылаюсь. Байт-код преобразуется в код ЦП ключа и зашифровывается. Когда конечный пользователь запускает защищенное приложение, этот зашифрованный код передается в «ключ». Ключ дешифрует и запускает его на своем ЦП.
Дмитрий Лесков
2
Корпоративные подростковые геймеры.
odiszapc
3

Если вы ищете решение для лицензирования, вы можете воспользоваться TrueLicense API . Он основан на использовании асимметричных клавиш. Однако это не означает, что ваше приложение невозможно взломать. Каждое приложение можно взломать, приложив достаточно усилий. Что действительно важно, как ответил Стю , это выяснить, насколько сильная защита вам нужна.

хакан
источник
2

Я не думаю, что существует какой-либо эффективный офлайн-метод борьбы с пиратством. Индустрия видеоигр пыталась обнаружить это много раз, и их программы всегда были взломаны. Единственное решение состоит в том, что программа должна быть запущена в интерактивном режиме и подключена к вашим серверам, чтобы вы могли проверить лицензионный ключ, и чтобы лицензиат имел только одно активное соединение за раз. Так устроены World of Warcraft или Diablo . Даже несмотря на то, что существуют частные серверы, разработанные для них, чтобы обойти безопасность.

Сказав это, я не верю, что средние / крупные корпорации используют нелегально скопированное программное обеспечение, потому что стоимость лицензии для них минимальна (возможно, я не знаю, сколько вы собираетесь взимать за свою программу) по сравнению с стоимость пробной версии.

Telcontar
источник
2

Вы можете без опасений использовать шифрование с помощью байтового кода.

Дело в том, что процитированная выше статья «Взлом шифрования байтового кода Java» содержит логическую ошибку. Основная претензия статьи - перед запуском все классы должны быть расшифрованы и переданы в ClassLoader.defineClass(...)метод . Но это не так.

Упущенное здесь допущение заключается в том, что они работают в аутентичной или стандартной среде выполнения Java . Ничто не может заставить защищенное Java-приложение не только запускать эти классы, но даже расшифровывать и передавать их ClassLoader. Другими словами, если вы используете стандартную JRE, вы не можете перехватить defineClass(...)метод, потому что стандартная java не имеет API для этой цели, и если вы используете модифицированную JRE с исправленным ClassLoaderили любым другим «хакерским трюком», вы не можете этого сделать, потому что защищенный java-приложение вообще не будет работать, а значит вам нечего будет перехватывать. И совершенно не имеет значения, какой «поиск патчей» используется или какой прием используют хакеры. Эти технические детали - совсем другая история.

Юрий Бендерский
источник
Как именно вы собираетесь обнаруживать исправленную JVM? В любом случае, все это немного усложняет задачу.
Сурьма
Разве вы не можете просто найти вызов defineClass () в панели запуска приложений? Когда вы делаете этот вызов, вам все равно нужно передать массив расшифрованных байтов. Разве это не еще одна точка, где может просочиться первоисточник?
Ascendant
4
Я не совсем согласен с этим ответом. Для меня это звучит так: «Вопрос: как проще всего найти Пи? Ответ: Возьмите 2 * Пи и разделите на два». Я не не согласен с этой идеей, но не могли бы вы рассказать подробнее? Например, вы ожидаете, что основная программа будет написана на чистой java? Включает ли это код, требующий изменений?
Patrick M
-1

В: Если я зашифрую свои файлы .class и использую собственный загрузчик классов для их загрузки и дешифрования на лету, предотвратит ли это декомпиляцию?

О: Проблема предотвращения декомпиляции байт-кода 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 выполнит мои оригинальный байт-код, и все же нечего декомпилировать или реконструировать, верно? "

К сожалению, вы ошибаетесь как в том, что думаете, что вы были первым, кто придумал эту идею, так и в том, что она действительно работает. И причина не в надежности вашей схемы шифрования.

С Хариш Морампуди
источник