In-memory compilation of freshly decompiled classes back into a running VM

This thesis is concerned with theoretical aspects of overcoming the limitations of standard instrumentation of processes running under the Java Virtual Machine (JVM). Bytecode instrumentation is the ability to modify the bytecode of a running process without the necessity of restarting it. This feature is subject to limitations imposed by the implementation of JVM under the OpenJDK project. The work then implements a Java compiler wrapper tool which works less traditionally, by using a dynamic classpath. This allows compilation of source code obtained at runtime while also resolving dependencies at runtime using a custom interface. We aim to integrate these features into the Java Runtime Decompiler project. Used together, this makes it possible to decompile the bytecode of running Java processes into source code and then observe, modify, recompile, and overwrite the currently executing bytecode.

Java platform with its classloader hierarchy and security manager provides the perfect environment to run third-party applications in a secure, isolated environment, e.g., javaws or former JBoss. When debugging such runtime, developers are very often forced to run third-party binary blob to reproduce the error. At that moment, decompilers and disassemblers come to play to see what the blob is actually doing. If an issue is found more likely in blob than in the runtime, then it is necessary to prove a fix. That forces developers of runtime to change the blob and use a new version in runtime. In addition, such binary blobs are very often hard to decompile and are very often incomplete. So the work has to move from filesystem into running JVM. This approach, when automated, may open new areas of testing based on automated runtime patching of JVM.

Java offers interesting approaches to obtain bytecode of currently running classes. By using easy tricks, this runtime bytecode can be decompiled (done in previous thesis).

This thesis aims to enable composition of an in-memory dependence tree and compile a freshly decompiled class back to a running JVM (Java Virtual Machine). The freshly decompiled class fragments are very likely not to be able to compile out of the box, and the student will have to elaborate on their structure. This issue may not be solvable on Java language level, and bytecode operations or java-assembly operations may be necessary to be used. Even if the class bytes are adapted and its decompiled source modified and compiled, the replacement of classes in a running JVM has its limitations. The student need to investigate possible solutions and propose the best approach.

University

Faculty of Informatics

Date of Completion

Autumn 2022

Resources

Leader

Jiří Vaněk

Consultant

Adam Rambousek

Student

Marián Konček