JAR/Class-file de-compilation reverse engineering and IP protection

R

Richard Maher

Hi,

I appreciate that this has been discussed at length previously and there is
some useful stuff to be found on the net but can I please just ask someone
to confirm that there's not a whole lot one can do to stop an enthusiastic
(let alone dedicated) coder from converting a Java class file back to its
original source format?

My understanding (too strong a word here :) is that a custom class-loader
is probably the best bet but does anyone have a very simple example of one
of these, especially one that would not fall foul of the sandpit and other
requirements of an *unsigned* applet?

Are people routinely paying for "supported" obfuscators or rolling their
own? (And are they much of a deterrant and/or footprint-reduction impact in
the first place?)

Do you have examples of the quality of output one can produce from publicly
available de-compilers?

"All too hard", just rely on copyright protection and those companies who
might use it coughing up?

Cheers Richard Maher
 
J

Joshua Cranmer

My understanding (too strong a word here :) is that a custom class-loader
is probably the best bet but does anyone have a very simple example of one
of these, especially one that would not fall foul of the sandpit and other
requirements of an *unsigned* applet?

One method I have demonstrated (or rather, I first saw demonstrated), is
to replace java.lang.ClassLoader with a slightly modified version,
namely one that dumps the bytecodes out passed through the bottleneck
defineClass methods. I first saw this method online somewhere, but I
really have no clue as to how to find it.

And, of course, once you have the bytecode, you can run all the
decompilers and other tools you want on it as if it were a regular
classpath.
Are people routinely paying for "supported" obfuscators or rolling their
own? (And are they much of a deterrant and/or footprint-reduction impact in
the first place?)

Obfuscation, insomuch as the names are turned into stuff like `a',
probably has a footprint-reduction impact, but I don't have hard numbers.

In terms of a deterrent, it would probably provide little to an
experienced hacker. Indeed, experienced hackers can easily crack the
copy protection on many new games or reverse engineer the license key
sections--and this is native code, which is theoretically much harder to
crack than bytecode. So fully reproducing readable source code, even in
full obfuscation mode, should only take a few hours for a moderately
complex class.
"All too hard", just rely on copyright protection and those companies who
might use it coughing up?

The best defense is to keep as much logic off the client side as
possible. Outside of that, all you'd do is slow down somewhat those who
would try to break it. Of course, if people do attempt that, that
generally means that you're program's successful enough to attract the
cracking community. :)
 
A

Arne Vajhøj

Richard said:
I appreciate that this has been discussed at length previously and there is
some useful stuff to be found on the net but can I please just ask someone
to confirm that there's not a whole lot one can do to stop an enthusiastic
(let alone dedicated) coder from converting a Java class file back to its
original source format?

My understanding (too strong a word here :) is that a custom class-loader
is probably the best bet but does anyone have a very simple example of one
of these, especially one that would not fall foul of the sandpit and other
requirements of an *unsigned* applet?

Are people routinely paying for "supported" obfuscators or rolling their
own? (And are they much of a deterrant and/or footprint-reduction impact in
the first place?)

Do you have examples of the quality of output one can produce from publicly
available de-compilers?

"All too hard", just rely on copyright protection and those companies who
might use it coughing up?

See below for an example.

I would not start messing around with a decrypting classloader.

Possible run an obfuscator like Proguard.

It ensure that the crackers actually have to do a little
bit of work.

And as a nice side effect it reduces the size of the
jar files a bit which is great for applets.

Arne

================================================

C:\>type Maher.java
public class Maher {
public static void main(String[] args) {
Richard r = new Richard();
r.dosomething();
}
}

class Richard {
public void dosomething() {
for(int i = 0; i < 3; i++) {
print();
}
}
private static void print() {
System.out.println("Ofuscation sucks");
}
}

C:\>javac Maher.java

C:\>java -cp . Maher
Ofuscation sucks
Ofuscation sucks
Ofuscation sucks

C:\>jad -o Maher.class
Parsing Maher.class...The class file version is 50.0 (only 45.3, 46.0
and 47.0 a
re supported)
Generating Maher.jad

C:\>type Maher.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: Maher.java


public class Maher
{

public Maher()
{
}

public static void main(String args[])
{
Richard richard = new Richard();
richard.dosomething();
}
}

C:\>jad -o Richard.class
Parsing Richard.class...The class file version is 50.0 (only 45.3, 46.0
and 47.0
are supported)
Generating Richard.jad

C:\>type Richard.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: Maher.java

import java.io.PrintStream;

class Richard
{

Richard()
{
}

public void dosomething()
{
for(int i = 0; i < 3; i++)
print();

}

private static void print()
{
System.out.println("Ofuscation sucks");
}
}

C:\>jar cvf rm.jar Maher.class Richard.class
added manifest
adding: Maher.class(in = 317) (out= 241)(deflated 23%)
adding: Richard.class(in = 520) (out= 368)(deflated 29%)

C:\>java -cp rm.jar Maher
Ofuscation sucks
Ofuscation sucks
Ofuscation sucks

C:\>type rm.pro
-injars rm.jar
-outjars rmx.jar
-libraryjars <java.home>/lib/rt.jar

-keep public class Maher {
public static void main(java.lang.String[]);
}

C:\>java -jar proguard.jar @rm.pro
ProGuard, version 4.2
Reading program jar [C:\rm.jar]
Reading library jar [C:\SUNJava\jdk1.6.0\jre\lib\rt.jar]
Preparing output jar [C:\rmx.jar]
Copying resources from program jar [C:\rm.jar]

C:\>java -cp rmx.jar Maher
Ofuscation sucks
Ofuscation sucks
Ofuscation sucks

C:\>jar xvf rmx.jar
inflated: META-INF/MANIFEST.MF
inflated: Maher.class
inflated: a.class

C:\>jad -o Maher.class
Parsing Maher.class...The class file version is 50.0 (only 45.3, 46.0
and 47.0 a
re supported)
Generating Maher.jad

C:\>type Maher.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)


public class Maher
{

public Maher()
{
}

public static void main(String args[])
{
new a();
a.a();
}
}

C:\>jad -o a.class
Parsing a.class...The class file version is 50.0 (only 45.3, 46.0 and
47.0 are s
upported)
Generating a.jad

C:\>type a.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)

import java.io.PrintStream;

final class a
{

a()
{
}

public static void a()
{
for(int i = 0; i < 3; i++)
System.out.println("Ofuscation sucks");

}
}

C:\>
 
R

Richard Maher

Hi Arne,

Wrote lots of good stuff with examples (see below for details)

Thanks very much for the great info and examples!

That JAD looks pretty scary! Even preserves/provides indentation.
Source-code on demand - How easy was that :-(

I do like the look of that Proguard though (especially being able to "keep"
the Applet or Main class) so I will read up on it (licensing etc).

I guess one downside of this method is having to re-test all your code after
it's been PROGUARDed. (Or don't deploy it to test until it's been PROGUARDed
I suppose?) Then there's the support issue and "How long, after a new
version of Java, is it before Proguard has a version that supports it?". But
that's any software/freeware I guess, and if your deliberately using old
Java versions then what does it matter?

Still, it also shrinks the JAR size down then this could well be worth
persuing - Thanks again!

Cheers Richard Maher

PS. I'll read the website testimonials, but if anyone here has had bad
experiences then please let me know.

Arne Vajhøj said:
Richard said:
I appreciate that this has been discussed at length previously and there is
some useful stuff to be found on the net but can I please just ask someone
to confirm that there's not a whole lot one can do to stop an enthusiastic
(let alone dedicated) coder from converting a Java class file back to its
original source format?

My understanding (too strong a word here :) is that a custom class-loader
is probably the best bet but does anyone have a very simple example of one
of these, especially one that would not fall foul of the sandpit and other
requirements of an *unsigned* applet?

Are people routinely paying for "supported" obfuscators or rolling their
own? (And are they much of a deterrant and/or footprint-reduction impact in
the first place?)

Do you have examples of the quality of output one can produce from publicly
available de-compilers?

"All too hard", just rely on copyright protection and those companies who
might use it coughing up?

See below for an example.

I would not start messing around with a decrypting classloader.

Possible run an obfuscator like Proguard.

It ensure that the crackers actually have to do a little
bit of work.

And as a nice side effect it reduces the size of the
jar files a bit which is great for applets.

Arne

================================================

C:\>type Maher.java
public class Maher {
public static void main(String[] args) {
Richard r = new Richard();
r.dosomething();
}
}

class Richard {
public void dosomething() {
for(int i = 0; i < 3; i++) {
print();
}
}
private static void print() {
System.out.println("Ofuscation sucks");
}
}

C:\>javac Maher.java

C:\>java -cp . Maher
Ofuscation sucks
Ofuscation sucks
Ofuscation sucks

C:\>jad -o Maher.class
Parsing Maher.class...The class file version is 50.0 (only 45.3, 46.0
and 47.0 a
re supported)
Generating Maher.jad

C:\>type Maher.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: Maher.java


public class Maher
{

public Maher()
{
}

public static void main(String args[])
{
Richard richard = new Richard();
richard.dosomething();
}
}

C:\>jad -o Richard.class
Parsing Richard.class...The class file version is 50.0 (only 45.3, 46.0
and 47.0
are supported)
Generating Richard.jad

C:\>type Richard.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: Maher.java

import java.io.PrintStream;

class Richard
{

Richard()
{
}

public void dosomething()
{
for(int i = 0; i < 3; i++)
print();

}

private static void print()
{
System.out.println("Ofuscation sucks");
}
}

C:\>jar cvf rm.jar Maher.class Richard.class
added manifest
adding: Maher.class(in = 317) (out= 241)(deflated 23%)
adding: Richard.class(in = 520) (out= 368)(deflated 29%)

C:\>java -cp rm.jar Maher
Ofuscation sucks
Ofuscation sucks
Ofuscation sucks

C:\>type rm.pro
-injars rm.jar
-outjars rmx.jar
-libraryjars <java.home>/lib/rt.jar

-keep public class Maher {
public static void main(java.lang.String[]);
}

C:\>java -jar proguard.jar @rm.pro
ProGuard, version 4.2
Reading program jar [C:\rm.jar]
Reading library jar [C:\SUNJava\jdk1.6.0\jre\lib\rt.jar]
Preparing output jar [C:\rmx.jar]
Copying resources from program jar [C:\rm.jar]

C:\>java -cp rmx.jar Maher
Ofuscation sucks
Ofuscation sucks
Ofuscation sucks

C:\>jar xvf rmx.jar
inflated: META-INF/MANIFEST.MF
inflated: Maher.class
inflated: a.class

C:\>jad -o Maher.class
Parsing Maher.class...The class file version is 50.0 (only 45.3, 46.0
and 47.0 a
re supported)
Generating Maher.jad

C:\>type Maher.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)


public class Maher
{

public Maher()
{
}

public static void main(String args[])
{
new a();
a.a();
}
}

C:\>jad -o a.class
Parsing a.class...The class file version is 50.0 (only 45.3, 46.0 and
47.0 are s
upported)
Generating a.jad

C:\>type a.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)

import java.io.PrintStream;

final class a
{

a()
{
}

public static void a()
{
for(int i = 0; i < 3; i++)
System.out.println("Ofuscation sucks");

}
}

C:\>
 
Q

Qu0ll

[...]
I do like the look of that Proguard though (especially being able to
"keep"
the Applet or Main class) so I will read up on it (licensing etc).

I guess one downside of this method is having to re-test all your code
after
it's been PROGUARDed. (Or don't deploy it to test until it's been
PROGUARDed
I suppose?) Then there's the support issue and "How long, after a new
version of Java, is it before Proguard has a version that supports it?".
But
that's any software/freeware I guess, and if your deliberately using old
Java versions then what does it matter?

Still, it also shrinks the JAR size down then this could well be worth
persuing - Thanks again!

Cheers Richard Maher

PS. I'll read the website testimonials, but if anyone here has had bad
experiences then please let me know.

My Java development focuses on applets and I simply could not imagine life
without ProGuard. It's an awesome tool and I rely on it heavily. So far it
has proven to be extremely safe and only occasionally have I encountered any
kind of issue with it and, even then, Eric Lafortune whom maintains it has
been quick to patch to fix. You'll find it removes heaps of dead code you
never knew you had and shrink your applet considerably.

Yes, you certainly do need to re-test your code because there are some
things that will be removed when you don't want them to be or some things
which relied on non-obfuscated class names etc. but all of these things can
be fixed by correct configuration. ProGuard even optimises your code so it
will run faster!

Anyway Eric, you have my email address, I will be expecting a small reward
for this otherwise unpaid endorsement!

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
(e-mail address removed)
[Replace the "SixFour" with numbers to email me]
 
R

Roedy Green

I appreciate that this has been discussed at length previously and there is
some useful stuff to be found on the net but can I please just ask someone
to confirm that there's not a whole lot one can do to stop an enthusiastic
(let alone dedicated) coder from converting a Java class file back to its
original source format?

See http://mindprod.com/jgloss/obfuscator.html
http://mindprod.com/jgloss/decompiler.html
http://mindprod.com/jgloss/disassembler.html

You are right, it is very easy to decompile/disassemble a source file.

Most of the time you flatter yourself if you think any one module
contains some great secret. It is only the app as a whole you want to
discourage from piracy.

The most serious approach is native optimised compilation. See
http://mindprod.com/jgloss/nativecompiler.html

My own preferred approach needs an Internet connection, frequent
downloads of crucial pieces of code, with sanity checks, or even
running small parts of the app on a server where the hacker can't even
look at them.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Perfect reusable components are not obtained at the first shot."
~ Bertrand Meyer (born: 1950 age: 59) 1989, creator of design by contract and the Eiffel language.
 
J

Joshua Cranmer

That JAD looks pretty scary! Even preserves/provides indentation.
Source-code on demand - How easy was that :-(

The last I checked, JAD could not decompile the Java 5-specific stuff.
In fact, to my knowledge, only one fully-functioning decompiler exists
that can do it.
 
A

Arne Vajhøj

Richard said:
Wrote lots of good stuff with examples (see below for details)

Thanks very much for the great info and examples!

That JAD looks pretty scary! Even preserves/provides indentation.
Source-code on demand - How easy was that :-(

It does not preserve, but it tries to write the code as readable as
possible.
I do like the look of that Proguard though (especially being able to "keep"
the Applet or Main class) so I will read up on it (licensing etc).

ProGuard is GPL with some exceptions.

But they explicit state that it does not have any impact on
the input or output code.

http://proguard.sourceforge.net/license.html

ProGuard is free. You can use it freely for processing your
applications, commercial or not. Your code obviously remains yours after
having been processed, and its license can remain the same.
I guess one downside of this method is having to re-test all your code after
it's been PROGUARDed. (Or don't deploy it to test until it's been PROGUARDed
I suppose?)
Yes.

Then there's the support issue and "How long, after a new
version of Java, is it before Proguard has a version that supports it?". But
that's any software/freeware I guess, and if your deliberately using old
Java versions then what does it matter?

If you study the download section at:
http://sourceforge.net/projects/proguard/files/
then it seems rather actively maintained.

Obviously no guarantee for the future.

Arne
 
R

Roedy Green

The last I checked, JAD could not decompile the Java 5-specific stuff.
In fact, to my knowledge, only one fully-functioning decompiler exists
that can do it.

It decompiles it, but not into idiomatic java with enums and generics.
However, if all you want to do is figure out how the program works, it
tell you all you need to know. I have some sample decompiles posted
at http://mindprod.com/jgloss/enum.html

They helped me figure out how enums worked under the hood.

--
Roedy Green Canadian Mind Products
http://mindprod.com

"Perfect reusable components are not obtained at the first shot."
~ Bertrand Meyer (born: 1950 age: 59) 1989, creator of design by contract and the Eiffel language.
 
R

Roedy Green

It does not preserve, but it tries to write the code as readable as
possible.

Indentation and local variable names are not normally included in the
class files. However, a decompiler can reconstruct them with quite
plausible code. For example, a local variable of the Sample class it
can call "sample".

--
Roedy Green Canadian Mind Products
http://mindprod.com

"Perfect reusable components are not obtained at the first shot."
~ Bertrand Meyer (born: 1950 age: 59) 1989, creator of design by contract and the Eiffel language.
 
M

Mike Amling

Qu0ll said:
My Java development focuses on applets and I simply could not imagine
life without ProGuard. It's an awesome tool and I rely on it heavily.
So far it has proven to be extremely safe and only occasionally have I
encountered any kind of issue with it and, even then, Eric Lafortune
whom maintains it has been quick to patch to fix. You'll find it
removes heaps of dead code you never knew you had and shrink your applet
considerably.

Yes, you certainly do need to re-test your code because there are some
things that will be removed when you don't want them to be or some
things which relied on non-obfuscated class names etc. but all of these
things can be fixed by correct configuration. ProGuard even optimises
your code so it will run faster!

The last time I tested ProGuard, and it has been a while, it caused
this construct

class Foo {
static final String CLASS_NAME=Foo.class.getName();
}

to fail after Foo was renamed. It looks like "Foo.class" uses a String
literal that ProGuard did not alter to the new name. Any idea if that's
still broken?

I will admit that
static final String CLASS_NAME=new Foo().getClass().getName();
does work even after ProGuard renames Foo.

--Mike Amling
 
J

Joshua Cranmer

The last time I tested ProGuard, and it has been a while, it caused this
construct

class Foo {
static final String CLASS_NAME=Foo.class.getName();
}

to fail after Foo was renamed. It looks like "Foo.class" uses a String
literal that ProGuard did not alter to the new name. Any idea if that's
still broken?

Java 5 and later directly uses a ldc on the class item from the constant
pool for class literals, instead of the synthetic check-and-set. If
ProGuard is merely changing the names in the constant pool, it shouldn't
break with any code compiled (and targeted!) with Java 5 or newer compilers.
 
R

Richard Maher

Hi Qu0ll,

Qu0ll said:
My Java development focuses on applets and I simply could not imagine life
without ProGuard.

But how did you go with your previously declared home-grown Logger utility
and the, now induced, inability to interrogate the Stack for caller class id
and line-number etc? Would it not be defeating the purposes of the
obfuscation to introduce code that passes around the "real" class-names to
your logging methods?

Do you still have logging/verbosity levels that perhaps include DEBUG? Or is
it a simple case of System.out.println("Doh! called from " +
appletWideUniqueErrorId)
It's an awesome tool and I rely on it heavily. So far it
has proven to be extremely safe and only occasionally have I encountered any
kind of issue with it and, even then, Eric Lafortune whom maintains it has
been quick to patch to fix. You'll find it removes heaps of dead code you
never knew you had and shrink your applet considerably.

Sounds great.
Yes, you certainly do need to re-test your code because there are some
things that will be removed when you don't want them to be or some things
which relied on non-obfuscated class names etc. but all of these things can
be fixed by correct configuration. ProGuard even optimises your code so it
will run faster!

It would be churlish to not at least give it a try

Cheers Richard Maher
 
R

Richard Maher

Hi Roedy,

Roedy Green said:

I had glanced through your web-site originally some time ago about this.
(Well done with the Java service you're providing btw)
You are right, it is very easy to decompile/disassemble a source file.

Most of the time you flatter yourself if you think any one module
contains some great secret. It is only the app as a whole you want to
discourage from piracy.

You're probably right, and it wouldn't be the first time I was found-out
flattering myself, but what the code does certainly impresses the hell out
of me! Add to that the fact that there's *nothing* out there doing the same
thing, as well as my heart-flet desire to delay the HTTP hordes from trying
to stuff yet another huge, ugly, replicant of a pig's-ear into the glass
slipper and, hey, it's worth a shot.
The most serious approach is native optimised compilation. See
http://mindprod.com/jgloss/nativecompiler.html

My own preferred approach needs an Internet connection, frequent
downloads of crucial pieces of code, with sanity checks, or even
running small parts of the app on a server where the hacker can't even
look at them.

Cheers Richard Maher
 
Q

Qu0ll

Hi Richard,
But how did you go with your previously declared home-grown Logger utility
and the, now induced, inability to interrogate the Stack for caller class
id
and line-number etc? Would it not be defeating the purposes of the
obfuscation to introduce code that passes around the "real" class-names to
your logging methods?

Do you still have logging/verbosity levels that perhaps include DEBUG? Or
is
it a simple case of System.out.println("Doh! called from " +
appletWideUniqueErrorId)

I haven't been using logging which identifies the class name and line of
code beyond the debugging stage i.e. I only use it before using ProGuard.
After that my logging framework simply displays informative messages with a
timestamp and thread information which is still very useful. It is still
possible to determine the class name in the logging but it will be the
obfuscated class name.

ProGuard has a retrace facility that allows you to decode obfuscated stack
traces and convert them into their original class names and line numbers.

--
And loving it,

-Qu0ll (Rare, not extinct)
_________________________________________________
(e-mail address removed)
[Replace the "SixFour" with numbers to email me]
 
G

Gilbert

Joshua said:
One method I have demonstrated (or rather, I first saw demonstrated), is
to replace java.lang.ClassLoader with a slightly modified version,
namely one that dumps the bytecodes out passed through the bottleneck
defineClass methods. I first saw this method online somewhere, but I
really have no clue as to how to find it.

And, of course, once you have the bytecode, you can run all the
decompilers and other tools you want on it as if it were a regular
classpath.
Another technique I've read about (but never tried) is to pad your class
file with a random byte(s) on the end, and then use a custom class loader
that drops the last byte(s) when reading the bytecode.

Regards
 
J

Joshua Cranmer

Another technique I've read about (but never tried) is to pad your class
file with a random byte(s) on the end, and then use a custom class loader
that drops the last byte(s) when reading the bytecode.

That still won't defeat the method I describe. Essentially, it captures
the bytecode at the level where the information is passed from the Java
methods to the native definition. I think even if you use JNI, it's
/still/ captured at that point, so there is no way to have Java run on
anything other than your own custom VM and still avoid being captured at
that point.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,054
Latest member
LucyCarper

Latest Threads

Top