4

I want to decompile a java program and recompile the derived (obfuscated) source. I unpacked the .jar archive and got a directory structure like that:

com/
com/foo/A/
com/foo/A/A.class
com/foo/A/B.Class
com/foo/B/A.class
...
com/foo/A.class
com/foo/B.class
org/foo/Bar.class
...

The problem is that there are name collisions between packages and classes, which makes it impossible to recompile the decompiled class files. A decompiled class will look like this:

package org.foo;
import com.foo.A; // <-- name collision error

class Bar {
    ...
}

Is there any way to resolve those naming issues, without renaming the class files?

EDIT: This is not a decompiler problem, but the question how it is possible to have a working .jar file with classes that violate naming conventions.

EDIT2: Okay, i guess on bytecode level such naming is possible, so with a smarter decompiler (who automatically renames the classes and fixes their references) this problem could be solved.

johnd
  • 49
  • 1
  • 3

3 Answers3

2

Do you really need to unpack the entire jar and recompile everything? Instead of recompiling the entire decompiled source by itself, use the original jar as the classpath, and extract and recompile only those classes that you need to modify. Then, when you need to package up your recompiled code, just copy the original jar and use jar -uf to replace the modified class files in place:

jar -uf ./lib/copy_of_original_jar_file.jar -C ./bin com/foo/A.class com/foo/B.class [...]

...and ./lib/copy_of_original_jar_file.jar becomes your new library.

One thing is for sure, and that is that the original jar must work properly with a Java classloader in order for the program to run. It should work just as well for compiling your one-off .class files.

You should experience much fewer naming collision issues by using the original jar because you keep the same classpath scanning order that the running application would use. Not only that, but Java decompilers aren't perfect. By eliminating the majority of the decompiled code from recompilation, you avoid the majority of issues that decompilers have with things like exception handler overlaps, special characters in obfuscated symbols, variable scoping issues, etc.

smallfire
  • 59
  • 2
  • Recompiling only some of the classes was exactly what i had in mind, but if I decompile a class A and this class imports a class B, which has such an ambiguous name, then i can't compile class A. I could rename class B but then i would have to fix all references on B in A and other classes. – johnd Dec 29 '10 at 09:15
  • I'm not quite sure that the error necessarily means you have an ambiguity issue. Have you tried to import another obfuscated class that is non-ambiguous? – smallfire Dec 30 '10 at 03:14
  • Dang. I was hoping my anecdotal experience would trump your reality. I guess it doesn't work that way. Perhaps you can try to use something like JDO (Java Deobfuscator). http://sourceforge.net/projects/jdo/ I found it mentioned here: http://stackoverflow.com/questions/1662766/tool-to-deobfuscate-java-codes/1662928#1662928 – smallfire Dec 30 '10 at 17:04
  • That was one of the few deobfuscators i didn't try... and it's pretty smart as it renamed the classes with name collisions. Unfortunately there are still many errors, but its a good starting point. Thanks :) – johnd Dec 30 '10 at 18:26
1

Java's import mechanism provides a shorthand for naming things, but you obviously cannot use it when there are collisions. You can always use the fully qualified name in your code, e.g.

package org.foo;  

class Bar { 
    private com.foo.Bar aDifferentBar;
    ...
}

EDIT:

I suppose there could be class files that comply with the JVM spec but which cannot be produced by a Java program that complies with the JLS spec. If so then you'll definitely need a smarter decompiler.

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
  • I know, but that doesn't solve the problem if com.foo.Bar is ambiguous. – johnd Dec 28 '10 at 17:41
  • I don't know what you mean. There can only be one com.foo.Bar, right? Is there some obfuscator trick that will give you multiple com.foo.Bar? – President James K. Polk Dec 28 '10 at 17:44
  • If there is a class "Bar" in the package org.foo, then there usually can't be a package org.foo.Bar. However, such class/package name collisions occur in the jar i want to decompile. – johnd Dec 28 '10 at 17:50
0

You can not import packages in Java, so why should this be a name collision? Which error message do you get from the compiler?

If there would be a name collision in the obfuscated code, the code would not run. So the decompiled code should be collision free.

Reboot
  • 1,716
  • 2
  • 14
  • 27
  • The error message is "the import ... cannot be resolved". There could be a public inner class named "A" in com/foo/A.class, so import com.foo.A.A could mean that inner class, or com/foo/A/A.class. That's why this kind of naming is forbidden in Java, but somehow the program must have been compiled... – johnd Dec 28 '10 at 17:31
  • Inner classes were not part of the question. In the class files classes are loaded using their path, so inner classes are A$A and classes in packages are A/A. That these classes have the same notation in the source file is a problem auf the Java language. So either the decompiler has to resolve the naming conflict and rename classes, if it should generate compilable code, or it would have to generate code that is using reflection, which will make the code pretty much unreadable, what is usually not the purpose of decompiling. – Reboot Dec 28 '10 at 20:04