Обфускация кода с ProGuard и JAXB

опубликовано: ⏰ 3

ProGuard – это мощный инструмент, который позволяет не только обфусцировать код, но и оптимизировать его, удаляя ненужные классы, методы и поля. Это помогает сократить размер финального приложения и сделать процесс реверсинжиниринга вашего кода более трудным.

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

В этой небольшой заметке покажу, как настроить ProGuard таким образом, чтобы он корректно работал с JAXB.

Основные проблемы при использовании ProGuard с JAXB

Обфускация кода с JAXB требует особого внимания, так как JAXB использует рефлексию для доступа к полям и методам классов. Если ProGuard переименует эти элементы или удалит их, то JAXB не сможет корректно работать с вашими объектами.

То же самое касается перечислений (enum) и аннотаций, которые также могут быть повреждены при обфускации. При включенной оптимизации !class/unboxing/enum ( см. Документацию ProGuard по оптимизациям), часть перечислений может быть заменена на числовые константы.

Настройка ProGuard для работы с JAXB

Для решения проблем с переименованием классов и атрибутов достаточно использовать стандартные аннотации, указывающие на настоящие названия элементов и атрибутов. Например:

Java

@XmlType(name = "documentType")
@XmlRootElement(name = "document")  // <1>
public final class Document {

    @XmlElement(name = "name")      // <2>
    private String name;

    @XmlElement(name = "type")
    private Type type;

    @XmlEnum
    @XmlType(name = "sourceType")
    public enum Source {
        LOCAL,
        REMOTE
    }
}
  1. Определяет имя корневого элемента XML.
  2. Определяет имя элемента XML для поля name.

При десериализации и сериализации JAXB будет использовать указанные имена из аннотаций, а не переименованные ProGuard.

Для того чтобы ProGuard правильно обрабатывал классы, используемые JAXB, необходимо добавить соответствующие правила в конфигурационный файл.

HTML
-optimizations !class/unboxing/enum # <1>

-keepattributes InnerClasses,Signature,LineNumberTable,*Annotation*,EnclosingMethod # <2>
-keepclassmembers enum com.test.jaxb.** { # <3>
<fields>; # <4>
    public static **[] values();
    public static ** valueOf(java.lang.String);
    }
  1. Отключает оптимизацию, которая может привести к проблемам с перечислениями.
  2. Сохраняет атрибуты, необходимые для работы JAXB.
  3. Сохраняет членов класса перечислений в указанном пакете.
  4. Сохраняет все поля перечислений.

Дополнительно – Java SPI

В случае использования Java SPI так же могут быть проблемы из-за оптимизаций ProGuard и переименования классов. Списки доступных сервисов хранятся в ресурсах META-INF/services/, и важно, чтобы имя интерфейса соответствовало полному имени класса.

Для того чтобы ProGuard не переименовал интерфейсы SPI, нужно указать их в конфигурационном файле. Например:

HTML
-keepnames class com.test.spi.HardwareMemoryProvider // <1>
  1. Достаточно сохранять полный путь к классу.

Заключение

Использование ProGuard для оптимизации и сокращения размера JAR может привести к проблемам при работе JAXB и Java SPI. Однако, указав соответствующие правила, можно избежать этих проблем.

Proguard Jaxb