Всегда ли я могу использовать Reflection API, если код будет запутан?

#java #reflection #obfuscation #proguard

#java #отражение #запутывание #предусмотрительный #proguard

Вопрос:

Я обнаружил, что, похоже, существует 2 общих решения:

  1. не запутывайте то, на что ссылается reflection API [Retroguard, Jobfuscate]
  2. замените строки в вызовах reflection API на запутанное имя.

Эти решения работают только для вызовов в рамках одного проекта — клиентский код (в другом проекте) может не использовать reflection API для доступа к методам закрытого API.

В случае 2 это также работает только тогда, когда Reflection API используется со строками, известными во время компиляции (тестирование частных методов?). В этих случаях dp4j также предлагает решение, вводящее код отражения после запутывания.

Читая Часто задаваемые вопросы по Proguard, я задавался вопросом, всегда ли работает 2 в противном случае, когда он говорит:

ProGuard автоматически обрабатывает конструкции, такие как Class.forName («SomeClass») и SomeClass.class. Классы, на которые даны ссылки, сохраняются на этапе сжатия, а строковые аргументы должным образом заменяются на этапе запутывания.

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

Вопрос: что означает утверждение, выделенное жирным шрифтом? Есть примеры?

Ответ №1:

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

 public Class loadIt(String clsName) throws ClassNotFoundException {
    return Class.forName(clsName);
}
  

в принципе, если вы передаете непостоянную строку в Class.forName, proguard или любой другой инструмент запутывания, как правило, не может определить, о каком классе вы говорите, и, следовательно, не может автоматически настроить код для вас.

Комментарии:

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

2. правильно. Фактически приведенный выше пример теоретически может означать 100 классов, которые загружаются через reflection.

Ответ №2:

Java-обфускатор Zelix KlassMaster может автоматически обрабатывать все вызовы Reflection API. У него есть функция под названием автоотражение, которая использует таблицу подстановки «зашифрованное старое имя» в таблицу подстановки «запутанное имя».

Однако это снова может работать только для вызовов в рамках одного и того же запутанного проекта.

Смотрите http://www.zelix.com/klassmaster/docs/tutorials/autoReflectionTutorial.html.

Ответ №3:

Это означает, что это:

 String className;
if (Math.random() <= 0.5) className = "ca.simpatico.Foo";
else className = "ca.simpatico.Bar";
Class cl = Class.forName(className);
  

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

На самом деле, ваш единственный правдоподобный вариант — решить, какие классы, интерфейсы и методы должны быть доступны через отражение, а затем не запутывать их. Вы фактически определяете странный тип API для клиентов — тот, к которому можно будет обращаться только рефлексивно.