О FernFlower
FernFlower — первый реально работающий аналитический декомпилятор для Java и, возможно, для языка программирования высокого уровня в целом. Естественно, он все еще находится в стадии разработки. Пожалуйста, присылайте свои отчеты об ошибках и предложения по улучшению в [систему отслеживания проблем](https://youtrack.jetbrains.com/newIssue?project=IDEA&clearDraft=true&c=Subsystem+Java. Decompiler).
FernFlower и ForgeFlower
FernFlower включает в себя некоторые патчи от ForgeFlower. Искренняя признательность выражается разработчикам ForgeFlower за их ценный вклад и улучшения.
Лицензия
FernFlower распространяется по лицензии Apache версии 2.0.
Запуск из командной строки
java -jar fernflower.jar [-<option>=<value>]* [<source>]+ <destination>
* означает 0 или более раз
+ означает 1 или более раз
<источник>: файл или каталог с файлами, которые нужно декомпилировать. Каталоги сканируются рекурсивно. Разрешенные расширения файлов: class, zip и jar. Источники с префиксом -e= означают «библиотечные» файлы, которые не будут декомпилироваться, но будут учитываться при анализе отношений между классами или методами. Информация о внешних классах особенно полезна при переименовании идентификаторов (например, опция «ren»).
<пункт назначения>: каталог назначения.
<опция>, <значение>: параметр командной строки с соответствующим значением (см. «Параметры командной строки» ниже).
Примеры:
java -jar fernflower.jar -hes=0 -hdc=0 c:Tempbinary -e=c:Javart.jar c:Tempsource
java -jar fernflower.jar -dgs=1 c:Tempbinarylibrary.jar c:TempbinaryBoot.class c:Tempsource
Параметры командной строки
За исключением mpm и urc, значение 1 означает, что опция активирована, 0 — деактивирована. Значение по умолчанию, если оно имеется, указывается в круглых скобках.
Обычно следующие параметры изменяются пользователем, если таковые имеются: hes, hdc, dgs, mpm, ren, urc Остальные параметры можно оставить как есть: они предназначены для профессиональных реверс-инженеров.
- rbr (1): скрыть методы моста
- rsy (0): скрыть синтетические члены класса.
- din (1): декомпилировать внутренние классы
- dc4 (1): свернуть ссылки на классы версии 1.4.
- das (1): декомпилировать утверждения
- hes (1): скрыть пустой супервызов
- hdc (1): скрыть пустой конструктор по умолчанию
- dgs (0): декомпилировать общие подписи
- ner (1): предположим, что возврат не вызывает исключений
- den (1): декомпилировать перечисления
- rgn (1): удалить вызов getClass(), если он является частью квалифицированного нового оператора.
- горит (0): выводить числовые литералы «как есть»
- по возрастанию (0): кодировать символы, отличные от ASCII, в строковых и символьных литералах как escape-символы Юникода.
- bto (1): интерпретировать int 1 как логическое значение true (обход ошибки компилятора)
- nns (0): разрешить не устанавливать синтетический атрибут (обход ошибки компилятора)
- uto (1): рассматривать безымянные типы как java.lang.Object (обходной недостаток архитектуры компилятора)
- udv (1): восстановить имена переменных из отладочной информации, если она присутствует.
- ump (1): восстановить имена параметров из соответствующих атрибутов, если они есть.
- rer (1): удалить пустые диапазоны исключений
- fdi (1): отменить встраивание структурfinally
- mpm (0): максимально допустимое время обработки для каждого декомпилированного метода в секундах. 0 означает отсутствие верхнего предела
- ren (0): переименовывать неоднозначные (соответственно запутанные) классы и элементы классов.
- urc (-): полное имя предоставленного пользователем класса, реализующего интерфейс IIdentifierRenamer. Он используется для определения того, какие идентификаторы классов следует переименовать, и предоставляет новые имена идентификаторов (см. «Переименование идентификаторов»).
- inn (1): проверьте аннотацию @NotNull, специфичную для IntelliJ IDEA, и удалите вставленный код, если он найден.
- lac (0): декомпилировать лямбда-выражения в анонимные классы
- nls (0): определяет символ новой строки, который будет использоваться для вывода. 0 – 'rn' (Windows), 1 – 'n' (Unix), значение по умолчанию зависит от ОС.
- ind: строка отступа (по умолчанию — 3 пробела)
- crp (0): используйте шаблоны записи, где это возможно.
- cps (0): используйте переключатель с шаблонами, где это возможно.
- log (INFO): уровень ведения журнала, возможные значения: TRACE, INFO, WARN, ERROR.
- iec (0): включить весь путь к классу в контекст при декомпиляции
- isl (1): встроенные простые лямбда-выражения
- ucrc (1): скрыть ненужный конструктор записей и геттеры
- cci (1): проверьте, действительно ли ресурс в try-with-resources реализует интерфейс
AutoCloseable
. - jvn (0): перезаписать любые имена локальных переменных именами в стиле JAD.
- jpr (0): включать имена параметров в именование JAD.
Переименование идентификаторов
Некоторые обфускаторы дают классам и их элементам-членам короткие, бессмысленные и, прежде всего, неоднозначные имена. Перекомпиляция такого кода приводит к большому количеству конфликтов. Поэтому желательно предоставить декомпилятору возможность переименовывать элементы по очереди, обеспечивая уникальность каждого идентификатора.
Опция «ren» (т.е. -ren=1) активирует функцию переименования. Стратегия переименования по умолчанию выглядит следующим образом:
- переименуйте элемент, если его имя является зарезервированным словом или короче 3 символов.
- новые имена строятся по простому шаблону: (класс|метод|поле)_<последовательный уникальный номер>
Вы можете перезаписать эти правила, предоставив собственную реализацию четырех ключевых методов, вызываемых декомпилятором при переименовании. Просто передайте класс, реализующий org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer, в опции «urc» (например, -urc=com.example.MyRenamer) в FernFlower. Класс должен быть доступен в пути к классам приложения.
Смысл каждого метода должен быть ясен из названия: toBeRenamed определяет, будет ли элемент переименован, а остальные три предоставляют новые имена для классов, методов и полей соответственно.