How to modify bytecode on class load JVM no args - java

I have an exe that is starting a JVM and loading java classes into memory. I was successfully able to dump these classes with a -javaagent from the running JVM by attaching it to the process and retransforming the classes. Now I am trying to modify the classes as they are loaded. My issue is that my java agent cannot handle premain as I cannot add command line options without modifying the loader executable, which is packed with Themida. By the time my java agent has been attached, the classes to be modified have already been loaded. I was thinking I could use the JVMTI class load hook to capture the class file and transfer it to a separate JVM and modify it with javassist or ASM then return it to to the original JVM via the JVMTI Agent. If I use JVMTI I'd need to load my agent with -agentlib, which brings me back to the problem of having to modify the executable. Can you think of any other ways I could preform this modification? Could I modify the JVM itself to load a java agent always on startup? Is there some other way to force the JVM to always load a java agent? To see if the software was calling any sort of exe in the JRE, I removed all of the exes from j64\bin. The program still loaded without error. When I removed java.dll, the program failed to load entirely, while the program still loads but throws an error when other dlls are removed. If I found which JRE dll was receiving the command line args from the loader, could I implement a dll proxy? Is java.dll the dll I'd want to proxy?

I can't really speak to the idea of proxying the jvm.dll. Sounds like very delicate and error-prone work. Don't know much about Themida either, but from some cursory browsing, you would be deliberately breaking Themida's security intent.
Without the ability to change JVM command line parameters, you don't really have a lot of options. (Rhetorical: What do you do if you need to change heap sizes etc. ?)
However, if you can append and additional execution after the JVM launches, you could use a JVM Attach execution to connect to the running JVM and and load your JVMTI agent via loadAgent. It's a real race-condition threat since your app could very well be under-way by the time you get your instrumentation installed, but as I said, your options are limited.
I would look into how you can use Themida to re-package the application and introduce a proper javaagent command line parameter. Plus, if you don't, you may find that Themida may detect your workarounds and disable them, or disable the JVM altogether.

Related

Jna external library and jvm exception instead of crash

I had to link my java app to an external library using JNA.
I don't have its source and then I can't change it.
Sometimes happeneds that this external library crash the jvm of my app, I don't know what can be... Maybe an unmanaged exception of the external library, what I see is just a app crash when an external native method is called.
Is there any way to avoid the entire jvm crash and simply get an Exception by JNA?
To better detail the problem: this library is a smartcard driver. During some s.o. auto-update or after the s.o. standby process sometimes I got that crash. No logs or errors, just the end of the jvm process.
JNA provides a system property, jna.protected, which if set true will result in an exception rather than a crash. This is enabled by default on windows, but on other platforms you need to pre-link with libjsig.so, since JNA uses some of the same signals used by the JVM to catch memory faults.
From the JavaDoc:
It is not uncommon when defining a new library and writing tests to
encounter memory access errors which crash the VM. These are often
caused by improper mappings or invalid arguments passed to the native
library. To generate Java errors instead of crashing the VM, call
Native.setProtected(true). Not all platforms support this protection;
if not, the value of Native.isProtected() will remain false.
NOTE:
When protected mode is enabled, you should make use of the jsig
library, if available (see Signal Chaining) to avoid interfering with
the JVM's use of signals. In short, set the environment variable
LD_PRELOAD (or LD_PRELOAD_64) to the path to libjsig.so in your JRE
lib directory (usually ${java.home}/lib/${os.arch}/libjsig.so) before
launching your Java application.
Even so, it's not recommended for production code, and certainly not recommended to attempt to continue execution after the fault occurs.

Load process as a thread?

So I saw some code in passing that referenced com.sun.tools.javac.Main, and I got curious, can I run the java process AS A THREAD inside my process? Other executables? I've loaded other java programs from ClassLoaders and injected them with Java Agents, but now I'm curious, could one load an EXE inside java?
I assume it's possible with memory reading/writing, but there aught to be a safer way. (If not, where would one find some specification?)
Extendings the Answer by Banthar:
Every process on a system has his own adress space.:
Threads are so called light - weighted processes which are related to the parent - process they were started from.:
Within assembly code or C / C++ where you can directly access hardware adresses :
you could break into the adress space of another process perhaps, though :
usually the system which is responsible for creating them will try to avoid such things.:
AFAIK there is no direct access to a certain memory region not allocated by the :
process trying to access it. IPC (inter process communication) is a good starting point to find out more about how to connect processes
So no access to other processes not started by your process.:
Still you can start other java processes (threads are processes, too):
or execute commandlines like 'java -jar xx.jar'.:
:
And of course nothing stops you from doing things such as calling a method on an object which is declared pulic such as static public void main within your classpath.
This is not possible in general. Executable files have to be loaded at specific address. This address is already occupied by java executable. In general one process can execute only one executable.
You can invoke other Java programs. Just add the jar to classpath and invoke main() method. That's probably how you saw com.sun.tools.javac.Main invoked.
If you have native shared library you can load it into java process with System.loadLibrary.
If you want to execute non-shared, native executable, the only way is to create new process.
You can compile classes in your code, if that is what your asking? See method getClass in https://github.com/tgkprog/jCompile/blob/master/JCompService/src/main/java/s2n/jComp/services/impl/DefaultClazzCompilerService.java
Can see other examples on the internet too. Javac compiler is just another written in Java tool since ages back. I'm guessing the next version of Java gets compiled by javac written in the previous version :) Sounds strange but fine if you think about what a java compiler does.
So you could call it as an API as above or make a process and call it (so its not part of your JVM just that your JVM invoked it). Not sure about calling the main method in a thread, i dont see why they would stop you. But it would not be heavy weight process, just an API call to the main mehtod if the class like this:
public static void main(String[] args) throws Exception {
com.sun.tools.javac.Main.main(args);
}
Similar : No com.sun.tools.javac in JDK7 , how to set classpath for com.sun.tools.javac.Main.compile() function?

How to prevent NoClassDefFoundError when Java runtime is on a removable drive?

I have a Java application on a USB stick along with the JRE (one for each Windows, Mac OSX and Linux) so that it can be run on any system even when Java is not installed. I have a thread running to detect if the USB stick is removed and if it is it exits the application.
I want to have it display a message before exiting (or tell them to re-insert the drive) but if I try to dispaly a JOptionPane I get the NoClassDefFoundError because the JRE has been removed along with the USB.
Is there a way to keep the needed classes in memory so that Java does not try to load them from the filesystem that is no longer present?
Thanks!
For most runtimes, any classes that are loaded will be in RAM, in the PermGen section of Java's memory.
To my mind what's likely happening is that displaying the error requires classes that haven't been loaded before - which are only available on the drive that's no longer there.
You might be able to work around this by triggering your error displaying logic when the program starts up, except have it in a mode where it's displayed invisibly. This should exercise the same code path such that all the required classes are loaded, and ensure that they're already known when you need to display your error. If this is too difficult, you could just manually call Class.forName("javax.swing.JOptionPane") instead (for each class required), though this is more brittle and likely to break if you change your rendering code without updating the hard-coded classes to load.
If this isn't the case (i.e. all the required classes have previously been loaded, and you still have the problem) then your runtime is obviously unloading classes. You'd have to look at its documentation to see what it's doing here, and how to stop it.

Reconstruction of java command line arguments

Is there a way to reconstruct the command line arguments passed to Java within a Java program, including the JVM options and classpath option?
I have a Java program that needs to restart the JVM and manipulate its bootclasspath (i.e. trying to override some system classes). I use the libc system method to invoke the new JVM.
I'm open for better approaches, but Java agents isn't an option.
Why not use a file that has these properties just like the Eclipse ini file and NetBeans conf files. That way you just read these properties and spawn the new Java process with these properties.
Back to your question, this previous answer should do
I agree that futzing with the bootclasspath is generally a poor idea. But...
Grab the code for "java.c" - the C program that compiles down to java.exe. You'll find that it just uses the JNI Invocation API to construct a JVM and call the main method. You could modify and re-compile this to look for particular exit codes, etc. and loop around and re-launch the JVM if required.
Alternatively, Eclipse does this (or at least used to), but having one Java program construct the command line (from a props file, etc.) and launch a sub-process. Again, it hooked the sub-process exit code and used that to decide whether or not to re-launch a new sub-process.
Err... modifying a whole core java class at runtime is a very very bad idea.
Whats wrong with subclassing here? Are you trying to modify an external library, add functionality, or be lazy?

Is there a way to include a VM parameter inside a .jar?

I have a game implemented in Java that was having a problem when running too much code from scripts: depending on the script language, the game could have these "hiccups" where the game would freeze for a couple frames every now and then, making the game "jerky" at times.
After some research, I discovered that was happening when the Garbage Collector decided to run. After some more research and testing, I discovered that using the incremental garbage collector (by using the -Xincgc VM parameter) fixed the problem. Yes, I am aware it makes the GC run about 10% slower, but it is the cost I pay.
With that background information, now what I want to do is package the game in a .jar like I have been doing so far, but I know no way of making the application use the incremental GC without using -Xincgc, and I didn't want to create .bat/.sh files where before the user only had to double-click the .jar.
Is there any way to make the .jar run with the incremental GC without needing some kind of loader (.bat/.sh) or wrapper around it? Is there some way to include that parameter in the .jar?
No, there's no way to do that. VM arguments can only be supplied as command-line parameters to JVM invocation: Java Tool
You can definitely do this with JNLP, which can be configured to add a shortcut to the desktop and automatically keep jars up to date, among other things.
From just a jar file, you can't do this. Adding Java WebStart can allow you to add java VM commands. If you are not against wrapping the jar in an executable Launch4J will wrap the jar in a executable as well. It only makes a windows exe, but it can make it on linux or windows. I haven't found a good alternative for linux.
I don't know of too many java apps outside of internal coorporate or dev stuff that people run via clicking a jar. Even a shortcut can specify this. Fancier options exist that let you create an exe, run as a service, or even wrap the whole thing in an installer... if we are talking windows, similar things exist for linux.
Besides Java Web Start, you could consider wrapping with JSMooth. It gives an EXE which in turn invokes the JVM - you can provide arguments there.
One option - I always wondered - is to re-run the jar program with Runtime.exec() call when the parameters are inadequate? Never tried it but seems possible.

Categories