Sobre FernFlower
FernFlower é o primeiro descompilador analítico realmente funcional para Java e provavelmente para uma linguagem de programação de alto nível em geral. Naturalmente, ele ainda está em desenvolvimento. Envie seus relatórios de bugs e sugestões de melhorias para o [rastreador de problemas](https://youtrack.jetbrains.com/newIssue?project=IDEA&clearDraft=true&c=Subsystem+Java. Decompiler).
FernFlower e ForgeFlower
FernFlower inclui alguns patches do ForgeFlower. Agradecimentos sinceros são estendidos aos mantenedores do ForgeFlower por suas valiosas contribuições e melhorias.
Licença
FernFlower é licenciado sob a licença Apache versão 2.0.
Executando a partir da linha de comando
java -jar fernflower.jar [-<option>=<value>]* [<source>]+ <destination>
* significa 0 ou mais vezes
+ significa 1 ou mais vezes
<fonte>: arquivo ou diretório com arquivos a serem descompilados. Os diretórios são verificados recursivamente. As extensões de arquivo permitidas são class, zip e jar. Fontes prefixadas com -e= significam arquivos de "biblioteca" que não serão descompilados, mas levados em consideração ao analisar relacionamentos entre classes ou métodos. Especialmente a renomeação de identificadores (opção 'ren') pode se beneficiar de informações sobre classes externas.
<destino>: diretório de destino
<opção>, <valor>: uma opção de linha de comando com o valor correspondente (veja "Opções de linha de comando" abaixo).
Exemplos:
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
Opções de linha de comando
Com exceção de mpm e urc, o valor 1 significa que a opção está ativada, 0 - desativada. O valor padrão, se houver, é fornecido entre parênteses.
Normalmente, as seguintes opções serão alteradas pelo usuário, se houver: hes, hdc, dgs, mpm, ren, urc O restante das opções pode ser deixado como está: elas são destinadas a engenheiros reversos profissionais.
- rbr (1): ocultar métodos de ponte
- rsy (0): ocultar membros da classe sintética
- din (1): descompilar classes internas
- dc4 (1): recolher referências de classe 1.4
- das (1): descompilar asserções
- hes (1): oculta a super invocação vazia
- hdc (1): oculta o construtor padrão vazio
- dgs (0): descompilar assinaturas genéricas
- ner (1): assume que o retorno não lança exceções
- den (1): descompilar enumerações
- rgn (1): remove a invocação de getClass(), quando faz parte de uma nova instrução qualificada
- aceso (0): produz literais numéricos "como estão"
- asc (0): codifica caracteres não ASCII em strings e caracteres literais como escapes Unicode
- bto (1): interpreta int 1 como boolean true (solução alternativa para um bug do compilador)
- nns (0): permite não definir atributos sintéticos (solução alternativa para um bug do compilador)
- uto (1): considere tipos sem nome como java.lang.Object (solução alternativa para uma falha na arquitetura do compilador)
- udv (1): reconstrói nomes de variáveis a partir de informações de depuração, se presentes
- ump (1): reconstrói nomes de parâmetros a partir de atributos correspondentes, se presentes
- rer (1): remove intervalos de exceção vazios
- fdi (1): estruturas finais de-inline
- mpm (0): tempo máximo de processamento permitido por método descompilado, em segundos. 0 significa sem limite superior
- ren (0): renomeia classes e elementos de classe ambíguos (resp. ofuscados)
- urc (-): nome completo de uma classe fornecida pelo usuário que implementa a interface IIdentifierRenamer. É usado para determinar quais identificadores de classe devem ser renomeados e fornece novos nomes de identificadores (consulte "Renomeando identificadores")
- inn (1): verifique a anotação @NotNull específica do IntelliJ IDEA e remova o código inserido, se encontrado
- lac (0): descompila expressões lambda para classes anônimas
- nls (0): define o novo caractere de linha a ser usado para saída. 0 - 'rn' (Windows), 1 - 'n' (Unix), o padrão depende do sistema operacional
- ind: string de recuo (o padrão é 3 espaços)
- crp (0): use padrões de registro onde for possível
- cps (0): use switch com padrões onde for possível
- log (INFO): um nível de registro, os valores possíveis são TRACE, INFO, WARN, ERROR
- iec (0): inclui o caminho de classe inteiro no contexto ao descompilar
- isl (1): expressões lambda simples embutidas
- ucrc (1): oculta construtores de registros e getters desnecessários
- cci (1): verifique se o recurso em try-with-resources realmente implementa a interface
AutoCloseable
- jvn (0): substitui quaisquer nomes de variáveis locais por nomes de estilo JAD
- jpr (0): inclui nomes de parâmetros na nomenclatura JAD
Renomeando identificadores
Alguns ofuscadores dão às classes e aos seus elementos membros nomes curtos, sem sentido e, acima de tudo, ambíguos. A recompilação desse código leva a um grande número de conflitos. Portanto, é aconselhável deixar o descompilador renomear os elementos por sua vez, garantindo a exclusividade de cada identificador.
A opção 'ren' (ou seja, -ren=1) ativa a funcionalidade de renomeação. A estratégia de renomeação padrão é a seguinte:
- renomear um elemento se seu nome for uma palavra reservada ou tiver menos de 3 caracteres
- novos nomes são construídos de acordo com um padrão simples: (class|method|field)_<consecutive unique number>
Você pode sobrescrever essas regras fornecendo sua própria implementação dos 4 métodos principais invocados pelo descompilador durante a renomeação. Simplesmente passe uma classe que implemente org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer na opção 'urc' (por exemplo, -urc=com.example.MyRenamer) para FernFlower. A classe deve estar disponível no classpath da aplicação.
O significado de cada método deve ficar claro na nomenclatura: toBeRenamed determina se o elemento será renomeado, enquanto os outros três fornecem novos nomes para classes, métodos e campos, respectivamente.