Published Feb 2001 by +Tsehp


It is amazing how poor the literacy about reversing java is. We can easily find hundreds of essays dealing with VB or how to defeat all kinds of protections, but concerning java, almost nothing. And yet this increansingly popular langage should be more studied by reversers. Why ? Mainly because it makes network programming a child's play and this is in my sense the future of software protecting.

You may be wondering why bother patching a java class since it is so easy to decompile ? Well, that is a good question... but the fact is that decompilers rarely do their work 'perfectly' and then recompilation is impossible, so there no way getting a fonctionnal program this way. Decompilers do a good job for small and simple applets but try to decompile a stand-by java program of several megs and you will get loads of decompilation errors.

Furthermore decompilation may allow you to keygen a protection but since I am a lazzy guy I think patching is a far more quick and straigtforward way to crack.

Now let's the crack begin ! :-)

Our guinea-pig is called JavaSpy1.0 and is a debbugging utility for java projects (available at in the java section). When you are not registered, each time the program starts you are welcomed by an annoying nag. Our goal is to get rid of it.

First we are going to decompress the .jar. The jar format is in fact a zip format, so in order to decompress the javaspy.jar, you just have to rename it to and then unzip it. Next is the decompilation. For this purpose I used Jad (also available at

For some reasons I won't deal with here, I found out that in order to be considered as registered, we must meet two conditions. The first is having in the JavaSpy directory a file called "reginfo.txt" of three lines : one for the name, the second for the company and the third with the serial. Normally this file is created the first time you enter some registration information (even if the serial is false, what is a serious security hole). You can easily create such a file with the notepad for example.

The second his hidden in the depth of the source code .In the ah.jad we have this interesting method :

    boolean a(av av1)
            if(av1 == null || av1.B == null || av1.s == null || av1.u == null)	<- av1.B=name, av1.s=company, av1.u=serial
                return false;
            String s = r._mthif().a();								            <- check for the reginfo.txt ? I am not sure
            if(s == null)
                return false;
            PrintWriter printwriter = new PrintWriter(new FileWriter(s));		<- write the info in the reginfo ? Probably...
            if(!ac.a(av1.B, av1.s, av1.u, null))								<- THAT IS THE CRITICAL TEST
                return false;													<- try again
            } else
                av _tmp = av1;													<- you won, thanks for playing ;-)
                g._fldnull = true;
                return true;

So, once we have a reginfo.txt we have to manage to force the result of ac.a() to TRUE. At this stage, we could have a look inside the method a(String, String, String, b) in the ac class to find out how the serial is computed and try to keygen it. But it would be too easy so we are going to patch it ;-)

Now it is time for playing a little bit with disassembling. I used JCD (guess what ;-)... Here is what I got when disassembling the ac.class :


Method #15
00001644        Access Flags                          ACC_PUBLIC ACC_STATIC 
00001646        Name                                  a
00001648        Type                                  (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/javaspy/ac$b;)Z
0000164a        Attributes Count                      1
0000164c        Attribute Name                        Code
0000164e        Bytes Count                           373
00001652        Max Stack                             4
00001654        Max Locals                            15
00001656        Code Count                            361
       0        aload_0
       1        ifnull 12
       4        aload_1
       5        ifnull 12
       8        aload_2
       9        ifnonnull 14
      12        iconst_0
      13        ireturn
      14        aload_0
      15        invokevirtual java/lang/String/length()I
      18        iconst_2
      19        if_icmpge 24
      22        iconst_0
      23        ireturn

Hey ! That should be quite familiar to you ! Some raw, simple assembly langage :-)

In the first paragraph we have right some the caracteristics of the method (Name, Type...) and left the are the offsets in the .class. In the second one, the rigthmost column represents the VM (Virtual Machine) assembly code and left we have got the offsets since the beginning of the code. All these caracteristics are taken from the .class. The specifications of this format, the inner working of the VM and the opcodes of the VM instructions are defined in a document edited by sun, the " VMspec".

For example : aload_0 = load from local variable 0, iconst_0 = push 0, ireturn = ret, if_icmpge = jge...

In fact the java compiler translates the source code in this VM assembly and the VM translates "on the fly" his assembly into the native assembly of the processor.

As we are now on a well known field we are going to apply a well known patching technique... The value returned by the method is the value at the top of the stack, so we will just push a "1" in it (1 stands for true, "0" for false) and then return.

By a glance in the VM Specification, we learn that the instruction to push 1 in the stack is "iconst_1" (0x04) the return is "ireturn" (0xAC) and "nop" is (0x0)

We are near the end... Just open the ac.class with an hexeditor and replace the three bytes at offset 165Ah (1656+4 which is the length of the field "Code Count") by "0x04AC00".

Now we just have to recompress the classes, rename the archive into javaspy.jar, put everything in order and... go to bed ! The program can now work in a more civilized way : the nag "is no more" ! :-)

Here we are... I am sure you are disappointed, as I was first. I thought patching java would be a hard, long and merely impossible task but finally it has been so easy, so unsurprising : decompiling, disassembling changing some opcodes, nothing fantastic in there ! ;-)

Any remarks, suggestions, death threats or strings of abuse ->

8th February, 2001