godot-proposals
godot-proposals copied to clipboard
Obfuscate GDScript in production export
Describe the project you are working on
Any project which can be released publicly where the developer might not want to have their code or structure implementation easily stolen.
Describe the problem or limitation you are having in your project
Currently Godot supports encryption of the exported files (if you use a custom build of the export templates)
However this is not really good enough. Almost every successful engine will at some point have a decompiler for the exported assets. (see ILSpy).
In-fact, due to the open source nature of Godot, I think it would be relatively simple to write a script-dumper, that uses the encryption to first de-crypt the files and then just dump them to some output folder once they've been loaded into memory.
Many others have also been worried about this issue, quite often with those issues being closed when the discussion goes more towards DRM or encryption.
❗️ This is not a discussion about DRM or Encryption ❗️
https://github.com/godotengine/godot/issues/39115 https://github.com/godotengine/godot/issues/24716 https://github.com/godotengine/godot/issues/19790
Describe the feature / enhancement and how it helps to overcome the problem or limitation
When exporting to production, exported GDscript files can be obfuscated with the names mangled.
In this case, adding encryption would add a layer of security, and if someone does decide to extract the files from the pck, they are left with an unintelligible mess of obfuscated code.
This additional security would put godot at the top end of protecting game assets, and likely bring users to our community.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
An example implementation can be found here
Here is a sample:
const my_variable = 5;
console.log(my_variable);
And obfuscated:
var _cs=["log"]; const _g0 = 5; console[_cs[0]](_g0);
If this enhancement will not be used often, can it be worked around with a few lines of script?
This should probably be core, because it could be part of the standard export pipeline.
Is there a reason why this should be core and not an add-on in the asset library?
I may work on an external plugin for this, but it would require duplicating the repository before every export, as this would mangle all script files.
This is not something which fits with a good export pipeline.
Related to https://github.com/godotengine/godot-proposals/issues/1407.
I think the engine should minify scripts in release mode exports to reduce the PCK size, but obfuscation is much more complex to do correctly. In contrast, minification is much simpler and doesn't risk breaking as often, since it's mostly about removing comments and non-significant whitespace. Obfuscating a language like GDScript is potentially very difficult due to String-based signal connections, Object's set() and get() methods, among other things.
That said, I don't think minification would be relevant by default, since scripts are exported to bytecode already (.gdc files). If you want to make sure about this, export a ZIP file for your game data (instead of PCK) and open the resulting ZIP archive.
Unfortunately breaking both the encryption and the bytecode compilation is already trivial at the time of writing:
So both of these included security features don't actually do anything to protect a games exported scripts or technology.
It took me less than 5 seconds to get access to a standard exported script. If I have to dig for the encryption key, the first time it will take me around 5 minutes and after that also less than 5 seconds.
Here is an example of one of my exported (production export) scripts after decompilation:
Obfuscating a language like GDScript is potentially very difficult due to String-based signal connections, Object's
set()andget()methods, among other things.
I think this is a task which should be taken step by step.
We build a basic framework for obfuscating tokens at export, which uses a script-wide name search.
Tokens such as $NodeNames can be frozen for now, but in future they could be obfuscated also (changing the .tscn files).
A broad whitelist of what to avoid obfuscating would help tremendously (i.e. never _physics_process)
Another way to provide increased security would be to allow customisation of the the location of the encryption key in the exported binary, although perhaps this warrants a separate proposal.
This sounds flat out impossible. At least with the full scope of GDScript. Example:
a.call("%s_%s" % [b, c])
I don't see how you could obfuscate GDScript code without breaking a construct like this.
a.call("%s_%s" % [b, c])
@zinnschlag JS actually doesn't mutate those unless you set the mangle level really high.
For your example, a basic obfuscation might look like:
0_1230a.call("%s_%s" % [0_1243a, 0_1550a])
By default I think a good first level would be obfuscation of func and var names.
Perhaps merging all GDscript files into a single large .gd file first at the time of export would help a lot with the mangling, as you could then operate on one large file instead of multiple separate ones.
So both of these included security features don't actually do anything to protect a games exported scripts or technology.
My goal isn't to "protect" anything; it's just to optimize the export. Remember that Godot already has script encryption (3.x) and PCK encryption (master) support.
My goal isn't to "protect" anything; it's just to optimize the export.
Yep, I understood, this proposal is about protection of assets, and not about performance.
Remember that Godot already has
The script and pck encryption can be easily bypassed as shown above.
By default I think a good first level would be obfuscation of func and var names.
If you obfuscation function names then the example I gave won't work any more, since it constructs a function name dynamically at run time.
If you obfuscation function names then the example I gave won't work any more, since it constructs a function name dynamically at run time.
~The example I wrote would still work correctly, since only the name of the variable is changing, not the contents.~
Ah I see you mean the naming of the function. In this case I recommend having the ability to exclude items from the obfuscation.
Javascript does this with the #no-mangle comment header
So I've been jamming on this idea in Python and I seem to have got at least some progress:
Before, taken from godot-simple-state

After (running without issues):

Currently it runs a system-wide search for things to replace, and supports # no-mangle.
The obfuscation code needs a bit of a cleanup but I think this is at least an example of what we could do in-engine before export.
I pushed the work I made so far here: https://github.com/tavurth/godot-gdscript-obfuscator
So far it's not working on the full repository, as .tscn files would need to be updated too.
At the moment export variables are mangled which causes issues as the names from the .tscn file cannot be found.
I will look into this more when I'm closer to my project release.
I agree this would be very useful. I'm currently creating a puzzle game with procedural puzzle generation, which I've worked on sporadically for several years, and I'd like to protect the generation code as much as possible to prevent clones just ripping off my approach. The type of puzzles I'm creating aren't new, but I believe my generation code is unique and produces much better results than currently available alternatives. Obfuscation seems the perfect way of achieving this.
Is the lack of this feature just a matter of being low priority, are people against it or is there another problem implementing?
Isn't this a major detriment to people making commercial games in Godot?
I did some reading on this but didn't find a clear answer whether decompiled gdc files retain the original identifier names or not? Not that it makes a big difference but if they do then I would love to see obfuscation.
I did some reading on this but didn't find a clear answer whether decompiled gdc files retain the original identifier names or not? Not that it makes a big difference but if they do then I would love to see obfuscation.
You can see my screenshot above, this is what files look like after you decompile them, comments stripped but everything else the same as before:
When I posted this on reddit around 60% of people were leaving extremely negative feedback, with people yelling at me for starting work on it.
I found that a bit confusing, but my conclusion was that a large proportion of godot devs are either:
- Uninformed about why obfuscation can be necessary to protect some games (i.e preventing hacking by using different obfuscation methods for each version)
- Working on creating hobby projects without the idea to release something that could ever need protecting
- Want to actually decompile and read the source code of other godot projects. (Perhaps they already are doing this)
I still feel like this is an extremely necessary part of the godot ecosystem.
We don't have to pay anything to Godot for using this engine in exported games, but creating a cool new game currently can easily be ripped off, changed some way and released on a market where the legal system has no effect. (I'm sure you can imagine such markets).
Is the lack of this feature just a matter of being low priority, are people against it or is there another problem implementing?
The lack of a feature in Godot is 90% of the time caused by a lack of people willing to do it. Also, obfuscation causes some code slowdown, meaning this potential feature should be disabled by default. I think that for a large number of projects, performance is still more important than protection.
Obfuscation is not a very reliable way to protect the code, it's just a way to make it harder to crack. Obfuscation won't help if the cracker has enough desire and deobfuscation tools (which will definitely appear over time).
You can try some third party tools to protect your code (DRM). Creating such tools is a difficult and ethically controversial goal for an open source project. I'm not sure if obfuscation that doesn't have an optimization goal (such as minimizing local variable names, constant folding, function inlining, etc.) is acceptable for an open source project. Although I understand your desire to protect your work and that it is quite common in game development.
Obfuscation is not a very reliable way to protect the code, it's just a way to make it harder to crack. Obfuscation won't help if the cracker has enough desire and deobfuscation tools (which will definitely appear over time).
I guess this is just a problem for all languages that use byte code. Maybe my way of thinking is outdated but it feels wrong that somebody can just run a program and have direct access to the source code to easily modify various parts of the game inside godot engine itself and claim as their own? If that starts to happen enough times the idea of ownership gets very blurry.
Like with people making rom hacks they have to at least put in effort in order to do these things, and they don't have access to the original tools.
I'm not interested in DRM though.
and claim as their own
Thankfully in Europe & most western countries the legal system takes care of this for you. If you are wondering if someone has copied your Godot game you can just decompile their source and find your lines of code directly to use in the lawsuit 🤷
However there are quite a few jurisdictions of the world where your lawsuit would land on deaf ears, or even worse have you labelled as the copier rather than the original owner.
Also, obfuscation causes some code slowdown, meaning this potential feature should be disabled by default
I haven't tested with my project above yet, but since I've reduced the byte size of each individual symbol in the obfuscated script, it would probably work with some small percentage performance increase.
In my opinion, if we can't get obfuscation option in Godot because of various downsides, then minification should be trivial enough. It helps save some of space and make decompilation a little bit trickier with zero trade-offs.
An example of why we need this:
https://www.reddit.com/r/gamedev/comments/ufa7q6/my_game_got_copied_changed_and_uploaded_to_google/
If you are already compiling your own export template (e.g. in order to turn off some unused modules), changing the structure of GDScript byte code might be a good alternative to obfuscation. e.g. You can swap the order of constant count and identifier count fields when dumping and reading GDScript byte code.
Compile an editor and an export template with the modified engine. Export the project with the custom editor and export template. Then your exported project won't be able to be decompiled by a generic tool and is script-kiddie proof.
i dont have knowledge but having both in the default engine as an optional option if possible to exist, would be a unique step than other game engines have. What i meant is first obfuscating the code as tavurth suggested then converting the obfuscated code to bytecode as timothyqiu suggested.
I wish this feature too. Use the Godot RE Tools, my GDScript full exposure in 5 seconds. Although there was other methods to resist this, but all lose GDScript advantage. Encrypt Exported PCK I need complie export template myself. I need C++. I know full avoid cracking was impossible, but use Godot RE Tools, it too much easy. I agree implement full feature was difficult because set get or other something, and I also wish can impliemnt this step by step.
Encrypt Exported PCK I need complie export template myself.
You can think a reverse engineering tool as a special kind of export template that iterates through all the resources instead of executing the game logic. Using a stock export template means the tool does not need to do anything that takes effort, as the export template's logic is open sourced.
You have to compile your own export template in order to hide what it does I think.
I was shocked to see the RE tool exposed everything in my game, except for comments. Best to come to terms with it now than later I guess...
It would be nice to have a basic level of obfuscation for gdscript/tscn, doesn't have to be extreme, just a basic level would thwart most copycats
To be fair, this type of problem already exists in some of popular game engines that use the same kind of build process, such as Unity. The only thing different is that on Unity there is already third party tool that obfuscates code, and even built-in IL2CPP tool that mitigates basic reverse engineering efforts. I have been in some of gaming groups and they indeed also do reverse engineering game files and have exposed its contents regularly. It's so trivial to do already and you only have few options to mitigate it.
In Godot's case (and few of open source game engines) is much more severe since the build process is already been made in public, so anyone can just observe a build process and find a way to reverse it. In fact, even encrypting the game engine and entire PCK file won't help that much (there is already a tool being made to find a key and decrypt game files) Plus, GDScript is also one of the weakest point of entire game engine in terms of protection. It doesn't even get minified, and it isn't a compiled code (although the exported script is a bytecode, but labels are still preserved) . It has some trade-offs especially in performance.
There aren't many things we can do to to mitigate any of reverse engineering efforts with a game engine that has simple build process. Even minification won't help that much. I only need minification feature to save some of disk space, such as internal function labels.
Probably adding obfuscation/minification is not a good solution compared to transpiling?
Example: https://github.com/godotengine/godot-proposals/issues/3069
Imagine you could compile GDScript into C++ for release builds, would that be superior way of tripping up decompilers?
@naturally-intelligent people have already tried using C++ transpilers to make RE harder with tools like unity, but this isn't the point of it at all.
C++ transpiling is a useful way of squeezing extra performance out of a game when it's needed without messing with C++ stuff directly, it's not meant at making RE harder.
@Riteo It might not be the intention of transpiling, sure, but wouldn't it still help preventing reverse engineering?
@naturally-intelligent perhaps. It'd be also definitely more obfuscated than, say, IL2CPP (the unity stuff) since there's no reflection to take into consideration (which basically preserves all symbol information and much more), but there are also very good c++ decompilers.
There's technically also the option of intermediate representation, which would deter RE similarly to transpiling if not even initially better, since there would be the need to build good decompilers.
The point is, though, that both methods aren't optimized at deterring RE per se, and implementing either just for the sake of it isn't a great idea at all IMO.
i think it should really be a priority to prevent godot games from being easily decompiled and recompiled. i mean, i used gdsdecomp full recovery on a steam game, and it was able to successfully unpack and make it importable in godot and make it run. that is really bad.
i know you can't protect assets from being ripped (not even unity), but in unity, you cannot import a decompiled unity project and make it run. having a game easily ripped and repacked (on android especially) hurts the small time devs (godots audience) since they don't have the resources to to fight back. do something for their sake at least.