Obfuscation, Failed due to exception from the main class

Hello,

I am attempting to obfuscate my project. I have enabled obfuscation in the project settings, and everything appears to obfuscate correctly.

ZIP file builds correctly, etc, etc.

When I try and run the EXE file though, I get this error:

Running the jar with a .bat file, shows that the error is as following:

 `D:\JME3\PlaneStorm\dist>java -jar PlaneStorm.jar
  Exception in thread "main" java.lang.NullPointerException
    at java.util.EnumMap.<init>(EnumMap.java:138)
    at com.jme3.system.l.<init>(Unknown Source)
    at com.jme3.system.JmeDesktopSystem.<init>(Unknown Source)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstruct
orAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingC
onstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at java.lang.Class.newInstance(Class.java:379)
    at com.jme3.system.j.b(Unknown Source)
    at com.jme3.system.j.e(Unknown Source)
    at com.jme3.system.j.a(Unknown Source)
    at com.jme3.app.SimpleApplication.start(Unknown Source)
    at mygame.Main.main(Unknown Source)

D:\JME3\PlaneStorm\dist>PAUSE
Press any key to continue . . .`

Unticking the ā€œobfuscateā€ option results in the build running perfectly, without any issues.

I really have to ask. Why Obfuscate?

And for what looks wrong. Class names are changed. Refelction that uses a class name string is not changed and it will typically not find it. Even worse the obfuscator my decided the class is not used and remove it. You need to mark all such classes to remain untouched. Such lists are often very long and time consuming to create.

At the moment, as the game is in very early alpha, the server trusts the client. Entirely. This means that I would, for now, like to make the game as hard to modify as possible.

Even if I keep the same class names (-keep public class mygame.*), it still has the same issue.

Iā€™m a bit lost here, so any pointers would be appreciated.

I hack such stuff sometimes for the lol, trust me it is at most a bit annoying.

Do clean serverside validation of all input. Thats it.

1 Like

Maybe exclude the jmonkey libs from obfustication?

Wrong! Donā€™t tell me that later youā€™ll write proper tests for all your incoming dataā€¦
You should do such things from the very beginning, it should be tested with all other code.

In my opinion obfuscation is ok, it will prevent kids to dig into your code, why to show them anything? Professionals donā€™t need to ā€˜stealā€™ any ideas, they would like to, eventually, write some hacking utilities for kids. Proper tests on server side would make it impossible.

2 Likes

This is probably what I will do. At the end of the day, full hack blockage is impossible, but it can be good to at least try.

Byte code is easy to read and hack. Very easy in fact. Easier that x86 asm, and hacking is not that hard either. Obfuscation adds nothing. Just donā€™t bother.

Just like to add on top of it fully trusting the client is the worst possible thing you could ever do period even in just a toss together product. One such example was the big PSN hack way back a few years ago. Sonyā€™s network trusted the console fully and it lead to a massive data breach. Even if you are storing no payment info it can badly expose a users account data causing their stuff to be taken or whatever. Rule 101 of a networked product is to never ever trust the client. You should always validate 100% of incoming data no matter what. BTW Obfuscation will not protect a networked product from being hacked especially if the server trusts the client all they have to do is modify the packets leaving their system and they can force the server to think the client is sending good data.

Alright, alrightā€¦ Iā€™ll just stop arguing and not bother with obfuscation.

That said, I donā€™t agree that it adds no security, as in my experience, it provides a lot of security.

My understanding is that minecraft was original obfuscated and still people managed to write all kinds of plugins from it.

Having reverse-engineered obfuscated code before to debug problems with third party libraries, it was only a minor nuisance. Stepping through it in a debugger is generally enough to follow along for any reasonably competent software engineer. Yeah, it slows them down but not much.

On the other hand, it will make problems harder to debug. (see above)

2 Likes

I actually write an Anti-Hacking plugin for Minecraft, and in my experience, obfuscating the plugin does a very good job of stopping people from either learning how it works, or pirating it for free to others (it is a paid plugin).

That said, youā€™re correct that because the Minecraft server trusts the clients so much, it is necessary for Anti-Hacking plugins, which should not be the case.

Also, I donā€™t think people reverse-enginnered it. I thought that dinnerbone (or was it grumm) released MCP for every Minecraft update, allowing it to be modded.

Minecraft survives on mods. Mods are what makes it popular. So perhaps youā€™re right. Perhaps I should add server-side checks, make the game un-obfuscated (or even open source?), and then call the job done.

Thank you for the advice.

Edit: Also, I am, technically speaking, earning money from Mojangā€™s incompetence. Interesitng. :stuck_out_tongue:

1 Like

Itā€™s not incompetence, itā€™s acceptance. And interest in working on something else, rather than plug holes that are being drilled faster than they are being fixed. They want to write a game, not spend 95% of their time stopping hackers, because thatā€™s what it would amount to.

2 Likes

From what I got, minecraft was single player at first and then itā€™s then only developer kinda hacked-in a multiplayer part. Been made a lot better since then though. I wouldnā€™t call either itā€™s original developer or the developers since then incompetent (I mean, they more competent than Iā€™ll ever be :blush), but congratz in making a an anti-hack modā€¦ lots of people must have been looking for such a mod. But yah, they were focusing on refactoring, bugs and moving to new platforms, one-client supporting the different releases and so on, mostly.

My opinion is that obfuscation is kinda like your door needing a keyā€¦ gazillion ways to bypass that, but still, it helps.
Although while I strongly suggest having a lock on your entrance doorā€¦ obfuscation is more on a case to case basis.
Iā€™d even understand people wanting to obfuscate just to avoid unasked for advice on coding.

Iā€™ve been having a look at this, as I too plan to obfuscate my game when the time comes. It turns out I get exactly the same exception as you. In fact, if you create a new BasicGame project and build it with obfuscation, youā€™ll get the same exception.

It seems that any enums, even ones you add to your own code, cause this exception. After looking at the ProGuard Usage webpage, and quite a lot of trial and error, Iā€™ve found that this setting fixes it:

-keep enum * {
    public static **[] values();
}

This basically means donā€™t obfuscate any enums. Unfortunately, although it does obfuscate the enum membersā€™ names, the String values of those members remain the same, so, people will be able to see what the enum member names originally were.

The next exception I get with BasicGame is this:

Exception in thread "LWJGL Renderer Thread" java.lang.NoSuchMethodError: getPointer
        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary0(Unknown Source)
        at java.lang.ClassLoader.loadLibrary(Unknown Source)
        at java.lang.Runtime.load0(Unknown Source)
        at java.lang.System.load(Unknown Source)
        at org.a.q.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.a.p.a(Unknown Source)
        at org.a.p.<clinit>(Unknown Source)
        at com.jme3.system.a.a.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

I really have no idea what the problem here is, exactly, but, a simple fix is to add this:

-keep class org.lwjgl.** {*;}

Thatā€™s enough to get an obfuscated BasicGame to work.

Iā€™m also using annotations, which also cause NullPointerExceptions. The fix for this is just to add this setting:

-keepattributes *Annotation*

Donā€™t know why that gets highlighted in pinkā€¦ :confused:

The other exception I get is because Iā€™m using the Oto model.

java.lang.ClassNotFoundException: com.jme3.scene.Node
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Unknown Source)
        at com.jme3.export.d.a(Unknown Source)
        at com.jme3.export.d.a(Unknown Source)
        at com.jme3.export.binary.BinaryImporter.readObject(Unknown Source)
        at com.jme3.export.binary.BinaryImporter.load$64a6d5d3(Unknown Source)
        at com.jme3.export.binary.BinaryImporter.load(Unknown Source)
        at com.jme3.export.binary.BinaryImporter.load(Unknown Source)
        at com.jme3.asset.l.a(Unknown Source)
        at com.jme3.asset.l.a(Unknown Source)
        at com.jme3.asset.l.c(Unknown Source)
        at botwar.l.g(Unknown Source)
        at botwar.a.a(Unknown Source)
        at com.jme3.app.a.c.a(Unknown Source)
        at com.jme3.app.SimpleApplication.update(Unknown Source)
        at com.jme3.system.a.a.l(Unknown Source)
        at com.jme3.system.a.g.l(Unknown Source)
        at com.jme3.system.a.a.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

Apr 20, 2016 7:42:11 PM com.jme3.app.b handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
com.jme3.asset.d: Error occured while loading asset "Models/Oto/Oto.mesh.j3o" using BinaryImporter
        at com.jme3.asset.l.a(Unknown Source)
        at com.jme3.asset.l.a(Unknown Source)
        at com.jme3.asset.l.c(Unknown Source)
        at botwar.l.g(Unknown Source)
        at botwar.a.a(Unknown Source)
        at com.jme3.app.a.c.a(Unknown Source)
        at com.jme3.app.SimpleApplication.update(Unknown Source)
        at com.jme3.system.a.a.l(Unknown Source)
        at com.jme3.system.a.g.l(Unknown Source)
        at com.jme3.system.a.a.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

Looking at the j3o files that come with jMonkeyPlatform, they all have references to lots of non-obfuscated JME3 classes. Iā€™m not sure whether this is always necessarily the case with j3o files though, as I havenā€™t got around to creating my own models and turning them into j3o files yet. If it is always the case, then it makes obfuscation harder.

The best solution I can come up with to add each of the classes in the j3o as -keep options, which for Oto.mesh.j3o is as follows:

-keep class com.jme3.animation.BoneTrack
-keep class com.jme3.math.ColorRGBA
-keep class com.jme3.animation.AnimControl
-keep class com.jme3.animation.CompactQuaternionArray
-keep class com.jme3.material.MatParam
-keep class com.jme3.animation.Bone
-keep class com.jme3.material.MatParamTexture
-keep class com.jme3.math.Vector3f
-keep class com.jme3.math.Quaternion
-keep class com.jme3.material.Material
-keep class com.jme3.scene.VertexBuffer
-keep class com.jme3.animation.Skeleton
-keep class com.jme3.animation.CompactVector3Array
-keep class com.jme3.animation.Animation
-keep class com.jme3.bounding.BoundingBox
-keep class com.jme3.math.Transform
-keep class com.jme3.light.LightList
-keep class com.jme3.asset.TextureKey
-keep class com.jme3.scene.Mesh
-keep class com.jme3.animation.SkeletonControl
-keep class com.jme3.texture.Texture2D
-keep class com.jme3.scene.Geometry
-keep class com.jme3.scene.Node

This obfuscates the contents of those classes, but not the class names or packages.

2 Likes

All classes that implement the Savable interface must not have their names obfuscated. jME serialization stores the names of the classes so that it can create them during deserialization.

Basically by the time you have all the correct exceptions you donā€™t have any obfuscation. And really it doesnā€™t do what you think. The only people that are going to run a decompiler on your source to hack are also the people that will hack byte code.

Your solving the wrong problem. Your problem right now is you donā€™t have any customers or people playing your game. Worry about hack if/when you get popular enough for anyone to bother.

If I were you, I would disable class name mangling for libraries like jME and turn on dead code elimination only. jME3 is a bit bloated at times and it would help reduce file size a lot getting rid of features that your game isnā€™t using.

1 Like

Oh yea i in fact have in the past used progruad to compact my libs. That is dead or unused code elimination and make one single jar. This however isnā€™t really Obfuscation.