First of all, sorry for the amount of text I wrote.
Secondly, I totally agree with the answer to the question you linked to:
Stay away from code-flow-altering "obfuscators".
(I'd call them "scramblers", but that would be a case for English.)
Thirdly, very strictly speaking, pure obfuscation (as in class & member renaming) usually generates much shorter names (see Minecraft with it's a
, b
, ...) than you chose, so because the class files are shorter, loading classes might be just a tiny bit faster, and because it takes less time to compare shorter strings, member lookups will be a tiny bit faster as well, maybe resulting in a tiny performance improvement on non-static method calls.
However, the improvement is most likely going to be negligible, and if the JVM does any form of lookup caching, I wouldn't expect any performance improvement at all.
However, with only class and member renaming, I wouldn't expect the performance to drop either.
As for whether it's gonna stop people from doing evil... maybe a little.
Very lazy programmers and newbies will certainly be scared away.
And then it depends on how much someone can gain by cracking your code.
If a hacker can personally gain something from cracking your game (i.e. speedhack), I'd say there's a much bigger chance of it happening than if it's a paid game that he can make run without a license or something.
And it also depends on how much code there is and how much you need to change.
If you have around 25 classes or less, I think for a somewhat advanced developer, it wouldn't really be hard.
But an application of the size of Minecraft is a different story.
But taking Minecraft as an example, I eventually learned to find my way through the obfuscated code, as the deobfuscation lists would take longer and longer to be generated after every release and I just wanted to keep my mods up-to-date.
Making a bold claim, I'd say for me it wouldn't be much harder to crack an obfuscated java application than to crack it non-obfuscated, and I'm certainly not the only one.
Also, some obfuscators choose names completely randomly, thus releasing an update might have totally different names.
One might think that would set hackers back, but once you have a rough idea of which class stands for what in one release, you can easily find that class again in the next one by searching for strings and imported classes or members of such, and from there you can make the connection to other obfuscated classes.
(For example, in Minecraft I always started with the crafting manager, because it had the unique "###"
Strings, and since it heavily used blocks and items, I could find many class right away from there.)
But you actually have one thing truly on your side: name collision.
Again with Minecraft, I realised that some files couldn't just be compiled again - not due to invalid code generated by the decompiler, but simply because a
was used as a class name and a field name, the field took precedence (otherwise I could've used a
and this.a
- note that this only works if your obfuscator removes the package and places all classes at the top level!), and so there was no way of referencing the class other than by reflection, which was what I ended up doing in some cases. In other cases (where performance was an issue), I created sort of a "fake" class with a different name that I could compile against, and then tampered with the generated bytecode to change the name back.
So while it is still possible, it certainly is a lot of effort to go through.
If I had to work around hundreds of collisions, I would most likely have given up pretty soon.
Also, I learned that, at least with Oracle's Java implementation, versions 6 to 8, "invalid" names in the bytecode don't seem to be a problem, at least not to some extent.
In one of my projects I needed to create bytecode at runtime and I needed the generated class to contain a method with a name that would not collide with any other method that class might contain, so my first try was to use an invalid character (*
) as its name, it so far (it has been out for 2 years) I haven't received any error report about a JVM rejecting it.
I don't know if there's an obfuscator out there that supports invalid names, but with a such, you could certainly generate code that would not only look horrible when decompiled, but which would be not even anywhere near compilable.
I imagine something like
Some thing = field.method().whatever.array[index];
turning into:
! ? = &.%().+.*[/];
Looks neat, doesn't it? And I'm sure the compiler will love it. *evil grin*
(But even if it works, I can't recommend it, because it's just not really good practise.)
At that level, your code will still be crackable, but probably not a great deal more than machine code, so you should be sort of safe.
TL;DR
- Stay away from code-flow-altering cruft.
- Lots of classes = additional layer of obscurity.
- Lots of classes = higher chance for name collision.
- If the reward is high enough, someone will always crack it.