Today I am going to show a nice trick to prevent usual unpacking of JAR files, before presenting the trick, please let me introduce some terms that we are going to use: JAR file, Manifest and Constant Pool.
From Oracle SE documentation: “JAR stands for Java ARchive. It’s a file format based on the popular ZIP file format and is used for aggregating many files into one. Although JAR can be used as a general archiving tool, the primary motivation for its development was so that Java applets and their requisite components (.class files, images and sounds) can be downloaded to a browser in a single HTTP transaction, rather than opening a new connection for each piece”.
From Oracle SE documentation: “A JAR file manifest consists of a main section followed by a list of sections for individual JAR file entries, each separated by a newline. Both the main section and individual sections follow the section syntax specified above. They each have their own specific restrictions and rules”.
The Java Constant Pool
From Wikipedia: “The constant pool table is where most of the literal constant values are stored. This includes values such as numbers of all sorts, strings, identifier names, references to classes and methods, and type descriptors. All indexes, or references, to specific constants in the constant pool table are given by 16-bit (type u2) numbers, where index value 1 refers to the first constant in the table (index value 0 is invalid).
Due to historic choices made during the file format development, the number of constants in the constant pool table is not actually the same as the constant pool count which precedes the table. First, the table is indexed starting at 1 (rather than 0), so the count should actually be interpreted as the maximum index. Additionally a couple types of constants, namely longs and doubles, take up two consecutive slots in the table, although the second such slot is a phantom index that is never directly used.
The type of each item (constant) in the constant pool is identified by an initial byte tag. The number of bytes following this tag and their interpretation are then dependent upon the tag value”.
Well, now that we know about the basis of this article, let’s proceed with the interesting stuff.
Java-side file name
According to the Java Specification, the Class name of a common Java Class is represented internally as a constant, to be precise as a CONSTANT_UTF8, which has a size of 16-bit (u2). Follows that we can use at most 65535 chars for the class name representation. Any idea at this point? If you have knowledge of how the Windows filesystem handles the file name length, you can quickly guess where the trick is. Why? Please follow me.
Windows-side file name
If you take a look at the MSDN documentation here, you can see that the maximum file name length allowed is at most 255 chars. Do you see any conflict here?
Java vs Windows
To recap, we can create a runnable Java application composed by Class files with names longer than 255, deployed as JAR, which will be hard to unpack in the common way, because we can’t drop such files directly on the filesytem. If fact if we try to extract the content of such JAR file we will have to fight against Windows :]
Are you curious to know how to craft such JAR? Let’s go.
Crafting the JAR
Now, I will explain how to lock a simple application composed by only one Class, say: Hello.class.
Open the class in a hex editor and locate the Class name definition in the Constant Pool (you can search for the “Hello” string). Once you have located the class name you need to edit its name, by keeping in mind to edit also its name length (remember the endianness!), so in my case I am going to use a name like: HelloRRR..RR.class, which has length of 0×204 ( > 255 ). Here is a screenshot of my edited Class file:
Once your class file is ready, you need to modify the Manifest.mf according to our new Class name. This step is required in case that we want a runnable application. In my case, I have the following Manifest.mf:
Caveat: you will need to split the Main-Class entry in several lines, otherwise the Runtime will complain with you :] In particular, keep in mind that: no line may be longer than 72 bytes (not characters), in its UTF8-encoded form. If a value would make the initial line longer than this, it should be continued on extra lines (each starting with a single SPACE).
Well, now we have our custom class and manifest, so what is the next step?
You need to rename the Hello.class, I mean the real file name, in the new long Class name. Once you have such file, you have just to put all together in a JAR file, and you will have a “locked” JAR.
Please don’t complain, but I am not going to explain you how to do this last step, since it easy to find out a way to do that, and also you will have some fun ;]
Here is the PoC (.zip instead of .jar because of blog restriction), you can download and test it. To run the application use: java –jar jcne-poc.zip.
I have created a tool to automatically pack and unpack Class files inside JAR by using this approach, but I am not going to upload it now.
I had a lot of fun while playing with this stuff and I hope that you have enjoyed the reading.