mati
Senior Newbie 
|
 |
«
Posted
2011-04-06 18:12:59 » |
|
Is there a way to protect Java class files from decompilation or at least make decompilation more difficult?
|
|
|
|
woogley
|
 |
«
Reply #1 - Posted
2011-04-06 18:22:49 » |
|
You'll never prevent it, as decompilation is literally just recreating source code from the bytecode instruction stack. So, if a VM can run the code, that same code can be decompiled. The best thing you can do is make your resources/variables as ugly and meaningless as possible. AKA obfuscation
|
|
|
|
kappa
|
 |
«
Reply #2 - Posted
2011-04-06 18:29:17 » |
|
Also why are you trying to protect your source code?
If the reason is that you don't want other stealing / copying your code, then you shouldn't bother, code is cheap and easy to write, if there is someone capable of decompiling your code, its highly likely it'll be easier for them just to write code that does the same thing without even looking at your code.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Riven
|
 |
«
Reply #3 - Posted
2011-04-06 18:31:34 » |
|
code is cheap and easy to write
Interesting statement.
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
kappa
|
 |
«
Reply #4 - Posted
2011-04-06 18:46:07 » |
|
well saying that mainly in comparison to art assets, as there is tons of free source code available compared to free game art/sprites.
|
|
|
|
princec
|
 |
«
Reply #5 - Posted
2011-04-06 19:38:33 » |
|
code is cheap and easy to write
Interesting statement. Well, it is, really. Maybe not massively cheap or massively easy but certainly not the valuable scarce resource programmers like to pretend it is. Cas 
|
|
|
|
Riven
|
 |
«
Reply #6 - Posted
2011-04-06 19:49:19 » |
|
code is cheap and easy to write
Interesting statement. Well, it is, really. Maybe not massively cheap or massively easy but certainly not the valuable scarce resource programmers like to pretend it is. IMHO it's like saying "products are cheap", making no distinction among products whatsoever. Sure, most code is cheap and easy to write. There is code that is extremely hard and extremely expensive, because very few people can write such code, demanding lots of investigation and/or high salaries, or simply because lots of programmers with regular salaries did it (slightly) wrong before. Oh well, we're getting offtopic 
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
avm1979
|
 |
«
Reply #7 - Posted
2011-04-06 20:35:39 » |
|
Take a look at yGuard. It's an obfuscator that's comparatively easy to use, and it's free. A fun feature is that it can produce bytecode, that when decompiled, doesn't compile back. Class names like "for (int = 0; ..." etc. Interesting that the JVM can actually handle a lot worse than what the compiler allows. Get ready for totally meaningless stack traces, though  Really, it's one of those "if you have to ask, don't worry about it" types of things. It's a good bit of trouble to go through.
|
|
|
|
pjt33
|
 |
«
Reply #8 - Posted
2011-04-06 21:43:18 » |
|
A fun feature is that it can produce bytecode, that when decompiled, doesn't compile back. Class names like "for (int = 0; ..." etc. Interesting that the JVM can actually handle a lot worse than what the compiler allows.
The compiler actually exploits that extra flexibility in the VM spec for inner classes. But any decent decompiler renames identifiers.
|
|
|
|
avm1979
|
 |
«
Reply #9 - Posted
2011-04-07 02:52:42 » |
|
But any decent decompiler renames identifiers. Right. Was just interesting to me that reserved keywords and the like were ok as class names as far as the JVM is concerned. I suppose inner classes are in part why that extra flexibility is there?
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ReBirth
|
 |
«
Reply #10 - Posted
2011-04-07 11:19:08 » |
|
I believe that bad named variabels are enough to make your code unreadable 
|
|
|
|
pjt33
|
 |
«
Reply #11 - Posted
2011-04-07 12:14:42 » |
|
But any decent decompiler renames identifiers. Right. Was just interesting to me that reserved keywords and the like were ok as class names as far as the JVM is concerned. I suppose inner classes are in part why that extra flexibility is there? I suspect it's actually because there's no need to limit identifiers in the VM spec. In the language spec you have to worry about parsing ambiguities, but in a class file the identifiers are all stored in the string table, IIRC as Pascal-style strings (character count followed by characters).
|
|
|
|
avm1979
|
 |
«
Reply #12 - Posted
2011-04-07 13:53:17 » |
|
Ah, that would make sense.
|
|
|
|
delt0r
|
 |
«
Reply #13 - Posted
2011-04-07 14:20:57 » |
|
Don't forget that quite a few of us can read byte code and assembly as well. I really wouldn't bother with "protecting" the source other than basic variable renaming. I don't do this for decompiling protection, but because it makes the jar quite a bit smaller and i even notice a small speedup in startup time. Since it costs nothing....
However i do concern myself with it just a little. Not because someone could "steal" my code. Hell i intend to release it GPL later anyways. But for cheaters. Pirates and co don't matter much. But cheating can really ruin the ability of a game to do well.
Problem is that even i can write cheats easy enough just from the byte code, or from some live mem dump tools. So I am not even sure it can be done without active measures.
|
I have no special talents. I am only passionately curious.--Albert Einstein
|
|
|
Riven
|
 |
«
Reply #14 - Posted
2011-04-07 16:56:12 » |
|
If you want to 'protect' your integers from being found by a mem-dump analyzer, use this wicked class: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
import java.util.Random;
public class RazzleDazzleInteger extends Number { public static void main(String[] args) { RazzleDazzleInteger i = new RazzleDazzleInteger();
System.out.println(i + " => " + i.get()); System.out.println(i + " => " + i.get()); i.set(1337); System.out.println(i + " => " + i.get()); System.out.println(i + " => " + i.get()); }
private static final Random XOR_SOURCE = new Random();
private int stored; private int xor1; private int xor2;
public RazzleDazzleInteger() { this(0); }
public RazzleDazzleInteger(int value) { this.xor1 = XOR_SOURCE.nextInt(); this.xor2 = XOR_SOURCE.nextInt(); this.set(value); }
public int set(int value) { this.barrelshift(); this.stored = this.xor(value); return value; }
public int get() { return this.set(this.xor(this.stored)); }
@Override public String toString() { return RazzleDazzleInteger.class.getSimpleName() + "[value=" + this.get() + ", stored=" + this.stored + "]"; }
@Override public double doubleValue() { return this.get(); }
@Override public float floatValue() { return this.get(); }
@Override public int intValue() { return this.get(); }
@Override public long longValue() { return this.get(); }
private final int xor(int value) { return value ^ this.xor1 ^ this.xor2; }
private final void barrelshift() { int shift;
shift = 3; this.xor1 = (this.xor1 << shift) | ((this.xor1 >> (32 - shift)) & 0x07);
shift = 1; this.xor2 = (this.xor2 << shift) | ((this.xor2 >> (32 - shift)) & 0x01); } }
|
Because one modifying XOR key is not enough! 
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
Eli Delventhal
|
 |
«
Reply #15 - Posted
2011-04-07 17:47:17 » |
|
I think the big problem with doing something like this is (as mentioned) that your stack traces become totally borked. I for one find stack traces incredibly important. You can maybe do something that basically creates a dsym file and something that can translate for you, but it all seems like it's more trouble than it's worth. Whether or not code is cheap, you're the one who wrote it and so you are by far the best one to improve and add to it. I could get your code and make my own changes to it, but it wouldn't be your code anymore, it would be a mod. 
|
|
|
|
DzzD
|
 |
«
Reply #16 - Posted
2011-04-07 17:52:39 » |
|
If you want to 'protect' your integers from being found by a mem-dump analyzer, use this wicked class:
@OP: but once again the first thing that will be do is to replace those encrypter class (decompile/modyfing/recompile)... definitly nothing really safe you can do client side
|
|
|
|
avm1979
|
 |
«
Reply #17 - Posted
2011-04-07 18:04:31 » |
|
You can maybe do something that basically creates a dsym file and something that can translate for you, but it all seems like it's more trouble than it's worth.
yGuard provides a pretty handy utility that lets you paste obfuscated stack traces into a console and get back readable ones, provided you keep around the file with the mappings. It's still a big pain, though.
|
|
|
|
delt0r
|
 |
«
Reply #18 - Posted
2011-04-07 20:16:45 » |
|
The xor trick does kinda work. Quite a few games do it, so folks look for it (your xor fields tend to be next to the relevant field). But probably not double XOR power!! 
|
I have no special talents. I am only passionately curious.--Albert Einstein
|
|
|
oNyx
|
 |
«
Reply #19 - Posted
2011-04-07 21:26:20 » |
|
code is cheap and easy to write
Interesting statement. Well, it is, really. Maybe not massively cheap or massively easy but certainly not the valuable scarce resource programmers like to pretend it is. IMHO it's like saying "products are cheap", making no distinction among products whatsoever. Sure, most code is cheap and easy to write. There is code that is extremely hard and extremely expensive, because very few people can write such code, demanding lots of investigation and/or high salaries, or simply because lots of programmers with regular salaries did it (slightly) wrong before. Well, the code of one game is only good for making that one game. I'm also only aware of one case where 2 Flash games were illegally reskinned. Typically complete games get stolen, because... y'know... reskinning requires some actual work. Reusing parts of some code also doesn't look very feasible. Media is probably more useful, but that stuff is typically only used as placeholder or it's used for some tiny hobby project. No real damage there.
|
|
|
|
Riven
|
 |
«
Reply #20 - Posted
2011-04-07 21:43:46 » |
|
I've seen very little of anything being reused among projects. 
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
kappa
|
 |
«
Reply #21 - Posted
2011-04-07 21:50:49 » |
|
|
|
|
|
Dx4
|
 |
«
Reply #22 - Posted
2011-04-25 11:48:23 » |
|
I'm currently attempting to make a Java bytecode encrypter, that uses a custom classloader to load encrypted classes at runtime. So far it's been able to protect against decompilers (unreadable class files) and JVMTI (instrumentation, javaagents) an example of a javaagent that is able to dump the source of encrypted class files is the following: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class TestAttacker implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { FileOutputStream fos = new FileOutputStream(className.replace("/", ".").replace("\\", ".") + "#" + this.hashCode() + ".class"); fos.write(classfileBuffer); fos.close(); } catch (IOException e) { e.printStackTrace(); } return null; }
public static void premain(String paramString, Instrumentation paramInstrumentation) { System.out.println("TestAttacker init"); paramInstrumentation.addTransformer(new TestAttacker()); }
} |
I'll post a demo later to see if anyone can actually crack it.
|
|
|
|
Roquen
|
 |
«
Reply #23 - Posted
2011-04-25 12:03:39 » |
|
All you need to know is the key and the method.
|
|
|
|
Riven
|
 |
«
Reply #24 - Posted
2011-04-25 12:11:07 » |
|
The JVM itself at some point always loads regular bytecode, no matter how fancy your classloader is. You can alter the JVM itself and intercept the byte[] of the classes that are just about to be loaded. You don't even need the key.
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings!
|
|
|
|
Roquen
|
 |
«
Reply #26 - Posted
2011-04-25 12:21:24 » |
|
@Riven: That's certainly true. I was thinking just decompile the "plaintext" classes, modifiy the classloader(s) to spit out plaintext....cause that's less work.
@Dx4: I'm too lazy. The point is that nothing you do on the client side is safe. Ever.
|
|
|
|
Dx4
|
 |
«
Reply #27 - Posted
2011-04-25 12:34:09 » |
|
@Riven: That's certainly true. I was thinking just decompile the "plaintext" classes, modifiy the classloader(s) to spit out plaintext....cause that's less work.
@Dx4: I'm too lazy. The point is that nothing you do on the client side is safe. Ever.
I don't think modifying the classloader will work to crack my classloader as the plaintext class is never in java memory.
|
|
|
|
delt0r
|
 |
«
Reply #28 - Posted
2011-04-25 12:43:59 » |
|
At some point the code *must* be plain text bytecode in the JVM. You can just intercept it there.
You are not the first to try, but what you are doing doesn't work. It doesn't work because the untrusted party must have the "key" in order to be able to use the code. As far as cryptography is concerned, its game over.
Seriously why are you so worried about decompilation? And why do you think it matters more than readable byte code anyway? We have been hacking hardware and software for a long time, and only one thing stays constant. It gets hacked. See mame, ACC, CSS, PS2 etc.
|
I have no special talents. I am only passionately curious.--Albert Einstein
|
|
|
Roquen
|
 |
«
Reply #29 - Posted
2011-04-25 12:49:32 » |
|
Hehe: Just for fun I downloaded your jar. It won't run on my 64-bit version of hotspot (The DLL barfs). That's one way to protect the info. 
|
|
|
|
|