I would use the asmtools from the OpenJDK project to disassemble the files to a bytecode assembly format.
So for example a helloworld looks like this (jdis NameOfClass.class>NameOfClass.j
):
super public class A
version 59:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello World!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
} // end Class A
After that you edit the file:
super public class A
version 59:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello Stackoverflow!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
} // end Class A
And then you can compile it to .class again:
jasm NameOfClass.j
and then you can run it normally with Java.
This was just an example.
You would just have to find the class with the method that checks for the version. For example you could unzip the jar files and if for example the message for a non-matching version is, for example:
"Bad version detected: "
You can just grep for it (grep -R Bad.version
) and then you get the class.
There you will have to change the method responsible for checking the Java version.
An example:
A.java:
public class A{
static boolean hasMatchingJavaVersion() {
return System.getProperty("java.version").matches("1.4.*");//Just Java 1.4
}
public static void main(String[] args) {
if(hasMatchingJavaVersion()) {
System.out.println("Matches");
} else {
System.out.println("Bad version");
System.exit(-1);
}
}
}
Run it: false
(On Java 15, e.g.)
As assembly.
super public class A
version 59:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
static Method hasMatchingJavaVersion:"()Z"
stack 2 locals 0
{
ldc String "java.version";
invokestatic Method java/lang/System.getProperty:"(Ljava/lang/String;)Ljava/lang/String;";
ldc String "1.4.*";
invokevirtual Method java/lang/String.matches:"(Ljava/lang/String;)Z";
ireturn;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
invokestatic Method hasMatchingJavaVersion:"()Z";
ifeq L17;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Matches";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
goto L29;
L17: stack_frame_type same;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Bad version";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
iconst_m1;
invokestatic Method java/lang/System.exit:"(I)V";
L29: stack_frame_type same;
return;
}
} // end Class A
This method checks for the version:
static Method hasMatchingJavaVersion:"()Z"
stack 2 locals 0
{
ldc String "java.version";
invokestatic Method java/lang/System.getProperty:"(Ljava/lang/String;)Ljava/lang/String;";
ldc String "1.4.*";
invokevirtual Method java/lang/String.matches:"(Ljava/lang/String;)Z";
ireturn;
}
So you could for example change it to:
static Method hasMatchingJavaVersion:"()Z"
stack 2 locals 0
{
iconst_1;//Load true, always return true
ireturn;
}
And then compile it again with jasm
.
Edit:
that JVM is made by Oracle rather than Sun.
I overread this, but it works the same way as described above, just another system property and some other minor changes,