Replacing java class? - java

I'm working on a sandbox feature for my java antivirus, and I've come into a question: Does the specified package on a class matter for compilation?
Example:
I'm running a program that wants to use Runtime.getRuntime().exec(), when the classloader attempts to load that to run a method, does it check the package qualified in the file, if they exist? I would prefer not to try and change files in the JVM, but to simply load ones from a different package. I can accomplish the loading and such, but my only dilemma, will it crash and burn? Inside the java, it would be registered as say, java.lang.Runtime, but the compiled code will say for example pkg.pkg.Runtime and will it need to extend the old runtime? My guess is that extending the old runtime would just break it. Does anyone know anything about this? I'm working on making a testable example, but I'm still a bit away and wanted to get some answers, as well as this might benefit some people.

Does the specified package on a class matter for compilation?
Yes it does matter. A class called pkg.pkg.Runtime() cannot be loaded as if it was java.lang.Runtime.
Furthermore, if my memory is correct, the JVM has some additional security measures in it to prevent normal applications from injecting classes into core packages such as java.lang.
If you need to change the behaviour of the java.lang.Runtime class (for experimental purposes!) then I think you will need to put your modified version on the boot classpath, ahead of the "rt.jar" file.
However:
This level of tinkering can easily result in JVM instability; i.e. hard JVM crashes that are difficult to diagnose.
If your aim is to produce a "production quality" tool, then you will find that things that involve tinkering with the JVM are not considered acceptable. People are going to be very suspicious of installation instructions that say things like "add this to your installed JVM's bootclasspath".
Distributing a "tinkered with" JVM may fall foul of Oracle's Java licensing agreement.
My advice would be to look for a less intrusive way of doing what you are trying to do. For instance, if you are trying to do virus checking, either do it outside of the JVM, or in a custom application classloader.
You commented:
I have a custom classloader, my question is: If I compile a class that is labelled as say, pkg.pkg.Runtime, can I register in my classloader as java.lang.Runtime?
As I said above, no you can't. A bytecode file has the classname embedded in it. If you attempt to "pull a swifty" by loading a class with a different name, the JVM will throw an Error.
And:
If not, then how can I replace the class? If the compiled package name has to equal the request referenced naming, then can I modify the .class file to to match, or perhaps compile it as if it were in the java.lang package?
That's what you would have to do. You need to name the class java.lang.Runtime in the source code and compile it as such.
But what I meant by my advice above is that you should use do the virus checking in the class loader. Forget about trying to replace / modify the behaviour of Runtime. It is a bad idea for the reasons I listed above.

Related

What is the preference for Java compilers regarding order of classes?

Do certain Java compilers prefer a different layout of a Java file before it is compiled unto a class file for the JVM?
What I mean is, by first writing your main Class and then writing all your other classes in the following lines bring or not a faster compile time?
Does the compiler take longer because it has not yet encountered what it is it needs for the relevant information in the main Class?
If I recall correctly, Java doesn't use explicit pointers either so I don't see that being an issue.
In other words, if you write your Classes outside of main first does this speed up compile time?
If any such difference exists, it would be so negligible you won't notice it.
In other words - you should focus on organizing the classes in a way that would make sense and would be easy for you to maintain, not on helping the compiler.
It is pretty simple: you specify the order of classes.
In other words: you give a list of file or directory names to the compiler. And then the compiler processes those in the order given, to then walk through each file. Sometimes it will make forward reference to understand that types are used that aren't defined yet.
I guess: when you ask the compiler to go for a complete directory, it will simply read the files in the order that the file system uses (like alphabetical).
Finally: this is definitely an implementation detail of the compiler (or even the build tool that generates the commands running the compiler). So a different tool, or tool version might lead to different results. So again: don't waste your time to "optimize" for this.

How to use the Java Instrumentation API to reload classes when they change on the the file system?

I don't want to use the URL Classloader to load classes.
I want to implement this myself.
I don't want to use a solution like JRebel (although it's great).
I've got prior experience of JavaAssist, bytecode generation, implementing javaagent class transformers etc.
I would like to write a javaagent which hooks into the classloader or defines it's own system classloader.
I'll store the class files in an in memory cache, and for particular files, periodically reload them from disk.
I'd prefer to do this in a way which doesn't involve continuously polling the file system and manually invalidating specific classes. I'd much rather intercept class loading events.
I last messed around with this stuff 4 years ago, and I'm sure, although my memory may deceive me that it was possible to do, but 8 hours of searching google doesn't present an obvious solution beyond building a patched JVM.
Is this actually possible?
I've created a stub implementation at https://github.com/packetops/poc_agent if anyone's interested in a simple example of javaagent use.
update
Just found this post - I may have been using the wrong approach, I'll investigate further.
It depends on what you want to do. If you want to reload your classes and define new ones, then you are fine with implementing your own classloader, as you already found.
If you want to replace existing classes, things become more "envolved". You can do this by implementing your own tiny Java agent. See the Java documentation, how to do this: http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html
With the instrumentation mechanism you can not freely redefine classes, quote from Instrumentation.redefineClass:
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
If you want to do more, you need to load it again. This can be done under the same name, by using a different classloader. The previous class definition will be unloaded, if no one else is using it any more. So, you need to reload any class that uses your previous class also. Utlimatly, you end up reinventing something like OSGi. Take a look at: Unloading classes in java?

Can I modify the byte code of a Java method in the runtime?

I am writing a plugin of another large java program .
I want to modify some byte code of some java method of the java program during runtime, so that I can intercept the method calls (namely, inject some hooking code into the method).
Any way can achieve this?
PS:
I've checked the following approaches:
1.change the classloader of the java program. (we CANNOT change it)
2.use java proxy. (We CANNOT use java proxy, because java proxy would create a new proxy object. We DON'T use the proxy object. We need to hook the java program's object, and Use that object)
3. use -javaagent option ( we CANNOT add the commandline option for the java program.)
PS more [Edited again]:
My classes was loaded by ext class loader (I put my jar files in JAVA_HOME\lib\ext folder).
The large java program is an applet program loaded by Browser. When the browser start the applet, it also loads my classes.
PS more more [Edited again]:
Although it's running in Applet. I can have full permission. Because I can modify java.policy and java.security file.
Thanks,
Calvin
Just use -javaagent opiton, which is used to modify the bytecode at runtime. You can find more about -javaagent from This Link or from This Link
There are several libraries which you can use. See for example here.
Once a class was already loaded/initialized by the VM it will be impossible to manipulate, though.
By the way, in principle you can also just replace the class to be 'hooked' with your own proxy class file. As long as the class' visible interface does not change this may work. (Sub-classes of the class may horribly fail at runtime though.) This replacement can be as easy as changing the classpath so that your class of the same name will be found first, before the original one. Delegating to the original class of the same name may be a little more complex in this case.
Yes, you can, but the process would be a bit tricky, as you would operate directly with memory. For this purpose, you'd look at unofficial documentation on sun.misc package and its Unsafe class.
Warning 1: the Unsafe class would be removed in JDK 9 according to official sources.
Warning 2: the Sun company would not take responsibility for your code to work correctly, as this class should not be used at all, and exists for system usage only.
Sorry, but this is not possible. First off, bytecode is immutable after classloading. The JVM provides several APIs that can be used to do something like this, but they are obviously highly privileged.
If you're running in a low privilege environment like a browser Applet, then you're obviously not going to be allowed to do this, and any method you could should be considered a security vulnerability.
But the question is why you are using applets in the first place, and why you want to modify code after loading. There's almost certainly a better way to do what you're trying to do.

How do I control which ClassLoader loads a class?

The situation at hand is not as simple as the title seems to indicate.
Java 1.6_17 running via JWS.
I have a class, lets say MyClass and one of its instance member variables is a Type from an errant 3rd party library where during class initialization it dynamically tries loading some of its own classes with Class.forName(String). In one of these cases it happens to dynamically call: Class.forName("foo/Bar").This class name doesn't follow the JLS for binary names and ultimately leads to a java.lang.NoClassDefFoundError: foo/Bar.
We have a custom ClassLoader which I've added a sanitize method to ClassLoader.findClass(String) and ClassLoader.loadClass(String) which fixes this problem.
I can call stuff like:
myCustomClassLoader.findClass("foo/Bar")
Which then loads the class without any problems. But even if I load the class ahead of time, I still get the exception later. This is because during initialization of MyClass which refers to Bar - their code ends up calling Class.forName("foo/Bar") in a static block somewhere. This actually would be OK if the ClassLoader it was trying to use was my custom class loader. But it isn't. It is the com.sun.jnlp.JNLPClassLoader which doesn't do such sanitation, thus my problem.
I've made sure that Thread.currentThread().getContextClassLoader() is set to my custom class loader. But this (as you know) has no effect. I even set it as the first thing i do in main() due to some stuff I read and still, MyClass.class.getClassLoader() - is the JNLPClassLoader. If I could force it to NOT be the JNLPClassLoader and to use mine instead, problem solved.
How can I control which ClassLoader is used to load the class via their static Class.forName("foo/Bar") call made during class initialization? I believe if I can force MyClass.class.getClassLoader() to return my custom class loader, my problem will be resolved.
I'm open to other options if anyone has ideas.
TL;DR: Help me force all Class.forName(String) calls in a third party library which are referenced by MyClass - to use the classloader of my choosing.
This reminds me of an article I read 10 years ago about the classloading arrangements in Java. It's still there on JavaWorld.
The article won't answer your question directly, but it may help understand your problem. You need to cause MyClass to be loaded through your custom class loader and trump the default class loading behavior, which is to first delegate class loading to the parent classloader and only attempt to load a class if that fails.
Allowing MyClass to get loaded by a classloader other than yours will store a relationship from the instantiated class to that classloader (via getClassLoader) and cause Java to use that other classloader to try to discover any referenced classes found at compile time, effectively bypassing your custom class loader by virtue of the class loader hierarchy and the delegation model. If MyClass is instead defined by your class loader, you get a second chance.
It sounds like a job for something like URLClassLoader, overriding loadClass and trumping the delegation model for classes residing in your JARs. You'll probably want to use a bootstrap approach (as suggested by Thomas in a comment above) to force a single entrypoint class to be loaded through your custom class loader, dragging all the others with it.
Also informative is this other JavaWorld article by the same guy, which warns you about the caveats of Class.forName. That too may trip your classloading arrangements.
I hope this helps and proves informative. In any case, it sounds like a difficult solution that is easy to break as your code evolves.
I think everyone gave good solid attempts at answering the problem. However, it turns out that I misdiagnosed the problem.
I had a coworker take over the problem and asked him to get a JDK with debug flags on so we could debug the JNLPClassLoader to see what was going on as I had tried all of the suggestions here + some.
We ended up getting OpenJDK because recompiling the JDK from scratch is a total nightmare (we tried). After getting OpenJDK working with our product and debugging through the JNLPClassLoader - it turns out that it was still using a REALLY old .jnlp from months earlier that had the resource path wrong and thus why it couldn't find the class.
We were confused why it was still using the ancient .jnlp even though we had redeployed the server correctly many times with the correct .jnlp and lots of code changes between which were reflected in our client application when run.
Well, it turns out that on client machines, Java caches the .jnlp file. Even if your application changes and it redownloads your application, it still won't re-download the new .jnlp for whatever reason. So it will use all of the new code, but look up resources/class paths using the cached .jnlp.
If you run:
javaws -uninstall
On the client machine then that will clear the .jnlp cache and next time it will use the correct .jnlp file.
Really sad that this was the problem. Hopefully, this saves someone else endless hours of frustration like it caused us.
If you run out of ideas with patching the ClassLoaders themselves, you might consider rewriting the library bytecode itself -- just replace the "foo/bar" constant with the correct value, and then you don't need to customize further class loading at all!
You could do this either at runtime or beforehand.

Finding new Java class at runtime

I have a functionality that I wish to provide to a customer for a software mockup that we are preparing - and I want to know if it's
possible
intelligent (a.k.a. not stupid)
the best thing
I want the customer to be able to write a java class that implements my Computable interface and stick it in some predetermined folder. This folder will contain the .java files rather than .class files. Then, at runtime, I want my program to search that folder and extract all of the Computables from that folder and store them in a map from the name of the Computable to the Computable object. The Computable should only have a default constructor and the it interface will only have one method called compute which maps an array of Object to an Object.
The Java Compiler API introduced in Java SE 6 should give you what you need.
You may find Google Reflections useful to find classes implementing/extending a certain interface/superclass in the classpath. It's then as straightforward as
Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class);
Then, to test if it indeed has a no-arg default constructor, just check for each if Class#newInstance() doesn't throw any exception.
There are several suggestions provided as answers to this question.
Here too On-the-fly, in-memory java code compilation for Java 5 and Java 6
If it's easy enough to compile at runtime that would be fine.
You can use javax.tools to do the compilation as needed. Create dynamic applications with javax.tools may help, too. It's also possible to do it in memory.
One caveat: using the compiler creates a dependency on the JDK; the JRE alone is insufficient.
take a look: Find Java classes implementing an interface
I think this would be simpler if you allowed your customer to type in a code declaration using something like Groovy, which is Java-ish enough, and easy to execute at runtime from a String value.
It's easy enough to iterate through the list of files in a folder. Someone mentioned that it's possible to call the Java compiler from Java (if you re-distribute the JDK, which I think is a point whose legality needs checking!!) That's much of the battle.
You seem to have a fixed model in your mind where only files fulfilling a certain interface are extracted from the folder. I think this is where your method needs to give a little. The sensible way (IMO) to do this would be to compile all files in that folder, and then with their classes stashed away somewhere, you can load and reflect them and then determine which of them "do" the interface and which don't. Those that don't will have been needlessly loaded into your JVM, but unless it's intentionally very space-wasteful, code you don't execute can't harm your program.
Having determined which ones do the computable thing, you can then store those classes (or instances thereof) in a Collection and do whatever you like with them. You simply ignore the other ones.
You could use BeanShell. This library is small and doesn't require the JDK. It is used in a number of IDE and web servers. The latest version appears to have the support you need loading .java files from the class path. (Still in beta)

Categories

Resources