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


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

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

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

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

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

10 82

10 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

Что делать?

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

посмотри JavaWorld статьи взлом шифрования байт-кода Java Владимир Рубцов. Это объясняет, почему шифрование файлов класса в основном бессмысленно.

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

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

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

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

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

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

вы можете использовать шифрование байт-кода без страха.

дело в том, что процитированная выше статья "Cracking Java Byte-code encryption" содержит логическую ошибку. Основная претензия статьи -перед запуском все классы должны быть расшифрованы и переданы ClassLoader.defineClass(...) метод. Но это не так.

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

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

A: проблема предотвращения декомпиляции байт-кода Java почти так же стара, как и сам язык. Несмотря на ряд инструментов запутывания, доступных на рынке, начинающие программисты Java продолжают думать о новых и умных способах защиты своей интеллектуальной собственности. В этом выпуске Java Q&A я часто Развеиваю некоторые мифы вокруг идеи перефразировал в дискуссионных форумах.

крайняя легкость, с которой Java .файлы классов могут быть восстановлены в источники Java, которые очень похожи на оригиналы, имеют много общего с целями проектирования байт-кода Java и компромиссами. Среди прочего, байтовый код Java был разработан для компактности, независимости от платформы, мобильности сети и простоты анализа интерпретаторами байтового кода и динамическими компиляторами JIT (just-in-time)/HotSpot. Возможно, скомпилированный .файлы класса выражают программиста намерение настолько ясно, что их можно было бы легче проанализировать, чем исходный исходный код.

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

к сожалению, оба подхода должны фактически изменить код, который будет выполняться JVM, и многие пользователи боятся (по праву), что это преобразование может добавить новые ошибки в свои приложения. Кроме того, переименование метода и поля может привести к тому, что вызовы отражения перестанут работать. Изменение фактические имена классов и пакетов могут нарушать несколько других API Java (JNDI (Java Naming and Directory Interface), поставщики URL и т. д.). В дополнение к измененным именам, если связь между смещениями байт-кода класса и номерами исходных строк изменяется, восстановление исходных трассировок стека исключений может стать затруднительным.

тогда есть возможность запутать исходный исходный код Java. Но в принципе это вызывает аналогичный набор проблем. Шифровать, а не запутать?

возможно, вышеизложенное заставило вас подумать: "Ну, а что, если вместо того, чтобы манипулировать байтовым кодом, я шифрую все свои классы после компиляции и расшифровываю их на лету внутри JVM (что можно сделать с помощью пользовательского загрузчика классов)? Затем JVM выполняет мой исходный байтовый код, и все же нет ничего, чтобы декомпилировать или перепроектировать, верно?"

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