judovana / java-runtime-decompiler

GNU General Public License v3.0
68 stars 14 forks source link

make decompilers cofigurable and pluginable #10

Closed judovana closed 6 years ago

judovana commented 6 years ago

Current implementation is tighten with one, semi hardcoded decompiler. Imho it would be easy to make it co-working with any java decompiler. Ideally offer rutime setting to decompile class with one or other. More detailed said, the decompiler-setting will only adjust classpath, and method name to execute byte[]/File->string/byte[] or simialrly. Advantage may be the decompiler download url (into XDG_CONFIG_DIR of JRD). However, co correct class-path will need luncher, or custom classlaoder fun. Especially with packaging in mind. With packaging in mind, the cassloader plugin may be located also in system.

RadekManak commented 6 years ago

I have no idea how to approach this. Do I need to create a class that implements an interface for every decompiler that's out there or is there some way to do it once for all? How can I even figure out what decompilers are installed on a system?

Advantage may be the decompiler download url (into XDG_CONFIG_DIR of JRD)

I have no idea what you meant by this. Could you clarify? I have found out this spec . but couldn't find what JRD is.

However, co correct class-path will need luncher, or custom classlaoder fun. Especially with packaging in mind. With packaging in mind, the cassloader plugin may be located also in system.

What do you mean by located also in system.? Isn't it something I need to write that loads the various decompilers at runtime? Therefore being inside the .jar?

judovana commented 6 years ago

Hi!

No , interface is not a way. You cant force all unknown developers to implement your interface. However, we can agree that 99% of decompilers have somewhere method with signatures of {File, byte[], stream} -> {file, String, Stream}. The only thing we need is to know exact signature and fully qualified name. So I had a config file in mind with columns like - id| download url or homepage or package name | description| classpath| method name| input type | output type. Then you can load this classpath into your new new (just once) classloader, and call this method by reflection (loaded from that config). To get the decompiler, you need its classes/jars. The can be already in system - system wide provided by packaging, or user-space only, which user downloaded, or even network based - both runtime-downlaoded and runtime-used. But for start, we can live with fact, that they are somewehre on the system. Obviously, we need to have the config file saved. Here yo have to think about two types of installation - downloaded, and packaged. Both can share read-only initial config in-jar which should ensure basic functionality if anythng goes wrong. Also both can share system-wide config in /etc/somewhere/soemthig (note, linux only), which should enable distribution-specific working stuff. And both can share user space config in XDG_CONFIG_DIR/somewhere/something (note, linux and win both), which should enable custom downloaded decompilers.

The specification you found is correct. The config file should lie in $XDG_CONFIG_DIR/somewhere/something if $XDG_CONFIG_DIR exists. In $HOME/.config/somewhere/something if not. Siilarly with XDG_CACHE_DIR and $HOME/.cache/somewhere/something if some cache (network runtime decompilers eg) is necessary.

"located also in system" are any decompilers user downloaded (user space) or installed via packages (rpm, deb, msi - system-wide). Such a jars, must be allowed to be easily integrated. Yo just need to program a logic, which will allow user to add them. As Iwrote, many can be preconfigured via system-wide config file.

hope to answer it all. Feel free to ping! Thanx, j.

RadekManak commented 6 years ago

However, we can agree that 99% of decompilers have somewhere method with signatures of {File, byte[], stream} -> {file, String, Stream}.

I wish it was that simple. The entry point for Procyon looks like this.

public static void decompile(
    final String internalName, 
    final ITextOutput output
);

For Fernflower we would have to do something like this. (No reflection in the example for simplicity)

decompiler = ConsoleDecompiler(File destination, Map<String, Object> options, IFernflowerLogger logger)
decompiler.addSource(file);
decompiler.decompileContext();

Since every decompiler is different we would need to create a plugin class file with decompile method {Byte[]}->{String} that abstracts Object initialization, I/O type conversion and method calls to Decompiler. We could then load these plugins from a directory at runtime. I made a plugin for Procyon https://gist.github.com/RadekManak/94748f776b6669efd610ee1186dbf1ef

Where should I store these plugins? If I need to store something in root-owned directory (for ex. /etc/) is permission something I need to worry about now or later when I'm packaging?

Also, $XDG_CONFIG_DIR doesn't exist did you mean $XDG_CONFIG_HOME?

Thanks!

judovana commented 6 years ago

sure, $XDG_CONFIG_HOME? -> you are right.

Thanx for looking into the pluginable part deeper then I did. If such an abstraction is needed, Then I'm afraid you approach is most correct and your ProcyonDecompilerWrapper or other future must implement some interface java runtime decompiler can read. That is likely only your decompile method. As the plugin requires the decompiler to exists, you can avoid reflection at all. That will also change your constuctor based approach.

Those plugins can be considered as config files. They can be distributed as .java and compiled on demand, or as .class/jar and shipped with javaruntimedecompiler or as independent jars/classes. The storage and usage remains identical to config files approach:

I would vote for the .java to be the format

Above approach do not provide information about the classpath. Do you have some better idea then having someOtherplugin.java accompanied with someOtherplugin.info which contain classpath and other informations? To use an annotations loks like solution, but I never used them for similar case Again, the .java plugins must be searched for main application. both on classpath and known filesystem locations

judovana commented 6 years ago

Does all decompilers you investigated have main method? MAybe it wil be much easier to stick with it....

RadekManak commented 6 years ago

Thank you for helping me with this issue! I wouldn't be able to do this without your help. fixed in #13 and #14.

judovana commented 6 years ago

Yah. really well done. I hope that internship at Pvel's was as good for you as I hoped....