I want to modify a connection string that's hard-coded in a Java application (jar without source).
I presume it's possible to decompile the jar, then change the source and recompile to a new jar, but is there a quicker way to do this?
EDIT:
It's a standalone application, not a jar I'm loading from my own code
I doubt it will have been obfuscated: niche scientific application, author AWOL.
A solution that entails modifying the string "in memory" while the app is running would also suffice, but not ideal
In your application that uses that jar, you could use reflection to set the connection String. (Reflection can be used even with private setters).
Obviously, if the setter is public, you could just call it without reflection.
I think decompilation is probably the quickest way, provided the code hasn't been obfuscated such that a decompilation/compilation round-trip is not possible. You're going to have to decompile the code anyway to find the connection string, so you're half-way there already.
More importantly, you can take advantage of this method to pull the connection string out into a properties file, and hence (hopefully) only perform the decompilation once!
Since Jars are often not compressed, there's a small chance that the address will be visible as plain text in the Jar. You could try editing the Jar with an editor that's not afraid of binary data (I use vim) and just search for and change the text, provided the old address and the new use the same number of characters. That's primitive but very simple.
If it doesn't work, you'll need one of the other approaches.
Of course you'll want to keep a backup copy of the jar in case this approach fails.
Since jar files are simply ZIP-Files with a certain structure, you can use a zip tool (WinZip etc.) to extract the class files; then you use a hex editor to modfiy the class files (should not be too difficult if the new connection string has the same length like the old one); after that, you zip it back into the jar file.
Of course this should only be your last-ditch attempt when all the other possibilities described above don't work.
I assume you already thought of this, but maybe you could simply use inheritance, if the compiled method in the .jar file looks something like this:
public String getConnectionString(){...
then just extend the class, override the method to return your new string and use your class instead. Obviously this only works if the super class is not final, the method is not final, and it's public or protected (if you can use the same package name).
Related
Have a problem with undocumented libraries, where I am trying to replace some classes in the .jar without any source code provided. One class is implemented from an existing one (no java file for it) so i have all the methods and method signatures but the no way to make any sens out of parameters because they are all named arg0, arg1..., because there are a lot of methods and some contain up to 43 parameters trying to loop through the parameters in order to see what is coming in. Is there any way to use String and dynamically get to that variable?
edit:
---more info---
Everything is compiled in the jar file, which I was able to repackage without one class that I want to change. So, the class that I want to change extended another class which is compiled. So, when extended the compiled class my IDE auto-generated all the methods and their signatures whre the parameters are named sequentially and I would like to place a for-loop in every function to see what is coming in instead of go one-by-one and print it to the console. I think I was a little vague in the original question.
Thank you
No, if those symbols have been removed from the compiled class file, you cannot recover them.
You can't get access to the parameter names unless the class was compiled in debug mode. But if you just want to iterate and print the values of each parameter passed in, mockito might be able to help you there if you mock the method. Or you can just step with a graphical debugger.
Is there a way to hook into the Eclipse compiler to specify custom class reading/resolving/loading logic while a Java source file is being compiled? I'm not sure what the correct term is, but essentially the compile-time equivalent of "class loading" that happens at run-time.
For example, say I have the Java source:
package foo;
import bar.Bar;
public final class Foo {
// getQux() returns type: qux.Qux
private final Bar bar = baz.Baz.getQux().getBar();
[...]
}
The compiler should request that 3 classes are read while compiling the source file foo/Foo.java:
bar.Bar - It is specified as an import.
baz.Baz - It is used in its fully qualified form (... = baz.Baz.getQux()...).
qux.Qux - It is an "indirect" dependency (it is returned by the call to baz.Baz.getQux(), which in turn is used to access a bar.Bar through the call to its getBar() method).
I'd like to be able intercept each of these "class requests" so that I can provide custom logic to obtain the class in question (perhaps it lives in a database, perhaps it it served up by some server somewhere, etc).
Also, I'd like it if no attempt was made to compile any of the source files in the Eclipse project until they are explicitly opened by the user. So in the example above, the 3 class requests (bar.Bar, baz.Baz, qux.Qux) aren't made until the user actually opens the source file foo/Foo.java. Ideally the list of source files in the project needn't be actual files on the filesystem (perhaps they too live in a database, etc) and a compile attempt is made only when a user opens/loads a source file.
I realize that, if possible, this has some drawbacks. For example, if I edit source file foo/Foo.java to make the class "package private", this will silently break any class that depends on foo.Foo until a "full" compile is done of the project. For now, that is fine for my purposes (there are things that I can do later to solve this).
Any ideas/suggestions?
Thank you!
Probably not, this would fall under the Java build path part of the JDT and I don't think it has that level of customization. There does not appear to be a documented extension point for this. To get a definitive answer you would need to look at the source. You could probably add this capability and it would mean that your would need to use an alternate version of the JDT, which might be difficult or impossible.
I am writing tests for some Java file handling code and want to make sure all files are closed properly. I don't want to run 'lsof' as that will open more files and make the test suite non-portable. Anyone know a way to do this?
If you're looking for something that's part of the JDK, the answer is no.
You might find something that uses JVMTI, but that wouldn't be portable (it's a native interface). Or something that uses JPDA, but that would require a second JVM. I give you those two acronyms as a start for Googling.
If you want to run in-JVM and be portable, you'll have to introduce a factory for your file references: replace all new FileInputStream(), new FileOutputStream(), new RandomAccessFile(), new FileReader, and new FileWriter calls with methods on that factory object. This factory will return subclasses of these objects, that have the close() method overridden. It will also increment an "open files" counter, that is then decremented by the overridden close().
The factory methods and counter will need to be static and synchronized (unless you want to inject the factory), and should use a system property to decide whether to return a subclassed stream or the JDK version.
Personally, I'd take the advice in the comment, and use FindBugs first.
I would like to know which is in your opinion the best way to parse a Java file and automatically change either a variable name, a method name or the class name. I would like to do so because I want to offuscate some code by just changing one small part of it (one of the three cited above).
For example I could have a class that has a global variable public static final int index = 0 and I would like to change it to public static final int xxx = 0. Of course i should be replaced to xxx in each occurrence in the file. Same goes for class name or method name.
I've been told ANTLR may work for me, but I've never used it and I don't want to waste time learning it if then I discover it's not suited for my purpose.
Thanks
EDIT:
I do not need to obfuscate the code, I need to change a small part of it. Either one of those mentioned above.
If you only need to change a few such identifiers, then refactoring (supported by most IDEs, including Eclipse) is simple, quick, and reliable.
If you need to change a lot (for example, if you're trying to replace uses of english with roughly equivalent identifiers in a foreign language - e.g., counter => compteur), then I'd personally find myself using something scriptable, like sed or Perl. And I'd be very careful to make sure I was hitting exact matches (e.g., when changing lie to truth, that I don't also change belief' to 'betruthf)
One caution if you go with an automated, do-a-lot-at-a-time solution: be very sure you can test functionality before and after to assure that you haven't broken anything.
Maybe the easiest is to use an existing code obfuscator, like the free Proguard :
http://proguard.sourceforge.net/
Use a code obfuscator to do the work for you.
Or use an IDE like Eclipse, which has this kind of thing built in using the Refactor menu.
I am getting a practical issue and the issue can be dascribed as follows.
We are developing a component (Say a plugin) to do some task when an event is triggered within an external CMS using the API provided by them. They have provided some jar libraries, So what we are doing is implementing an Interface provided by them. Then an internal method is called when an event is triggered. (The CMS is creating only one instance of class when the first event triggers, then it just executes the method with each event trigger)
The function can be summarized as follows,
import com.external.ProvidedInterface;
public class MonitorProgram implements ProvidedInterface{
public void process(){
//This method is called when an event is triggered in CMS
}
}
Within our class we are using "javax.net.ssl.HttpsURLConnection" (JAVA 1.5). But HttpsURLConnection migrated to javax.net.ssl from com.sun.net.ssl for 1.4. But it seems the CMS I am referring to (We dont know their implementation actually) uses something like this
System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
leading to a ClassCastException in our code.
I think my question is clear. In our case we cant set VM parameters,
-Djava.protocol.handler.pkgs=
Also we cant set it back using,
System.setProperty("")
because the VM instance is same for CMS and our program.
What can I do for get this problem resolved? And idea or experiences?
This is not clear for me.
Do you want to overwrite a system property?
You can do this.
Overwrite the System.property before calling the external library method and when the method returns you can set the old System.property back
final String propertyName = "Property";
String oldProperty = System.getProperty(propertyName);
System.setProperty(propertyName,"NEW_VALUE");
monitorProgram.process();
System.setProperty(propertyName,oldProperty);
Or do you want to prevent, that the called process overwrites the system.property?
And why you can not set the system property by hand?
I don't think you are going to have much success getting two pieces of code to use different properties.
In your own code however, you can define your own URLStreamHandlerFactory. Doing this will allow you to create a javax.net.ssl.HttpsURLConnection from a URL. While protocol handlers aren't the easiest thing to figure out, I think you can get them to do the job.
See http://java.sun.com/developer/onlineTraining/protocolhandlers/
Find the offending class in the stack trace
Use jad or a similar tool to decompile it.
Fix the name of the property
Compile the resulting file and either replace the .class file in the CMS's jar or put it into a place which is earlier in the classpath.
Use ant to automate this process (well, the compile and build of the JAR; not the decompiling)
When it works, make sure you save everything (original file, changed file, build file) somewhere so you can easily do it again.
While this may sound like a ridiculous or dangerous way to fix the issue, it will work. Especially since your CMS provider doesn't seem to develop his product actively.