the matt jones website.‎ > ‎Java‎ > ‎

Hacking a jar file for debugging

What you will need:
  • A Jar File to work with.
  • Java JRE
  • A Java JDK.
  • A Java Decompiler
  • A text editor

Suppose you have been provided with a jar file that is not working correctly, and you wish to determine what is going on when you execute this jar. This JAR might be part of a very large application, or just a small set of classes where a problem is difficult to diagnose in some environments. One wa to begin debugging the JAR file is to add in some custom logging and classes. 

If the standard logging utilities: log4j or java util loggers are being used in the class you are about to debug, I recommend using these classes. However, if this logging is used in the ENVIRONMENT but not the class or not used at all, I suggest to avoid making too many changes to the class, use a minamal logger, or at a pinch standard output.

To help you follow along I have included a a Java Project and the respective JAR's below. I suggest you read through this guide first and then attempt the tasks with my or your own JAR's once you have got the idea.

Determining what you want to know
In the application CountingSheep is designed to count all the black sheep in a list and all the non-blacksheep in the list. In theory, the user of this program should be able to enter the following and get the respective results:

java -jar CountingSheep.jar sheep blacksheep sheep
This tool counts the number of non-black sheep in the list
Not Black Sheep: 2
Black Sheep: 1

java -jar CountingSheep.jar sheep blacksheep redsheep
This tool counts the number of non-black sheep in the list
Not Black Sheep: 2
Black Sheep: 1

We can see an error when we run the last use-case:
java -jar CountingSheep.jar sheep blacksheep redsheep
Incorrectly Returns:
This tool counts the number of non-black sheep in the list
Not Black Sheep: 1
Black Sheep: 2

As we are pretending we don't have the source code, and that we have no idea what could be going on! (It's a very simple error for demonstrative purposes).

We need to workout when the sums are going wrong, so we are going to want to collect some additional information arond the sheep counting process. 

Opening the JAR in Java Decompiler shows two classes: 
- countingsheep.Main
- countingsheep.SheepCounter

The Java code for counting sheep appears in the Main Class:

    private static void inputParse(String[] args) {
        SheepCounter NotBlackSheep = new SheepCounter();
        SheepCounter BlackSheep = new SheepCounter();

        for (int i = 0; i < args.length; i++) {
            if (args[i].equals("sheep")) {
                NotBlackSheep.addSheep();
            } else {
                BlackSheep.addSheep();
            }

        }
        System.out.println("Not Black Sheep: " + NotBlackSheep.getTotalSheep());
        System.out.println("Black Sheep: " + BlackSheep.getTotalSheep());
    }

In this example, we want to manipulate the "if-statements" to report the total number of recorded sheep at each point.
But we will need to rewrite this class to look like this:

package countingsheep;

import java.io.PrintStream;

public class Main
{
  public static void main(String[] args)
  {
    System.out.println("This tool counts the number of non-black sheep in the list");
    inputParse(args);
  }

  private static void inputParse(String[] args) {
    SheepCounter NotBlackSheep = new SheepCounter();
    SheepCounter BlackSheep = new SheepCounter();

    for (int i = 0; i < args.length; i++) {
      if (args[i].equals("sheep"))
 {
        NotBlackSheep.addSheep();
// added statement below for debugging
System.out.println("Not Black Sheep: " + NotBlackSheep.getTotalSheep());
      }
else {
        BlackSheep.addSheep();
// added statement below for deugging
System.out.println("Black Sheep: " + BlackSheep.getTotalSheep());
      }
    
 }
    System.out.println("Not Black Sheep: " + NotBlackSheep.getTotalSheep());
    System.out.println("Black Sheep: " + BlackSheep.getTotalSheep());
}
}

To add this into a JAR file we will need to compile the new class and swap the old jar with the new jar to do this:

1) Compile the new class:
javac -classpath .\dist\CountingSheep.jar Main.java

This will result in a new Main.class file being created in the same directory as Main.java.
(if you want to place this class in another location use the "-s" option it will need to follow standard package conventions used in java)

2) Update the new class into the jar:
jar uf CountingSheep.jar countingsheep\Main.class

3) Execute the jar file:
java -jar CountingSheep.jar

With this added output, we have more information to realise that the "if-else statement" is incorrect and should instead look for blacksheep first.

And there you have it, a simplistic guide to editing a compiled JAR for debugging.

If you care:
- The Decompiler I use is here: http://java.decompiler.free.fr
ċ
CountingSheep.jar
(3k)
Matthew Jones,
21 Mar 2011, 19:25
ċ
CountingSheepDebugged.jar
(3k)
Matthew Jones,
21 Mar 2011, 19:26
Comments