godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.98k stars 21.16k forks source link

PCK files include human-readable script code #24716

Closed miskatonicstudio closed 3 years ago

miskatonicstudio commented 5 years ago

Godot version:

3.0.6

OS/device including version:

Linux Pop!_OS 17.10 (Artful Aardvark)

Issue description:

One of the people playing our game noticed that the source code is available in the .pck file downloaded by Steam. The game (Intrepid) is an escape room and the source code contains all the codes (answers to puzzles) used in the game. The game was released for free, so this is not a problem for now (only this one person found out the solutions this way) but we'd like to use Godot for future games too, and for that we need to be sure that crucial details will not be available by investigating the .pck file.

Steps to reproduce:

Example: screenshot from 2019-01-02 15-01-13

Minimal reproduction project:

girng commented 5 years ago

good discussion in #19790 as well?

Zireael07 commented 5 years ago

.pck can be opened? I tried doing it when I found exported a test project that I later mistakenly deleted the source of... and couldn't...

Calinou commented 5 years ago

@Zireael07 It's a custom binary format, opening it in a text or hex editor can reveal some data directly as text (as shown above).

There's also third-party tools which can "parse" custom binary formats and extract resources out of them, without any prior knowledge of the format. These tools rely on common patterns found in binary files such as PNGs to extract data.

Lastly, it would be fairly easy to write a PCK extraction tool (either as part of Godot itself, or as a standalone tool).

bojidar-bg commented 5 years ago

Maybe we can encrypt the .pck similar to how .gde files are encrypted? Or alternatively, encrypt each file separately with keys derived from a key given at export.

girng commented 5 years ago

would https://github.com/godotengine/godot/pull/24582 be a solution to this issue? (the "compiled" option under the script tab)

bruvzg commented 5 years ago

.pck can be opened? I tried doing it when I found exported a test project that I later mistakenly deleted the source of... and couldn't...

In case it might be useful here's my old PCK extraction tool (AFIAK PCK format was not changed ever) or you can find everything necessary for extraction in core/io/file_access_pack.cpp. It's quite simple format, basically list of file names, sizes and offsets and raw content.

girng commented 5 years ago

@bruvzg okay very cool. thank you so much for sharing that.

i found that godot does still create .gdc files, however, the raw text of the gdscript is still visible inside the .pck file itself. i initially thought if we could see the raw gds in the .pck, we could then extract the .pck and then look at all the gdscript files. that's not the case. they get extracted as .gdc.

now that i think of it, this seems like sorcery

bruvzg commented 5 years ago

Compiled .gdc actually stores all original identifier names XORed with 0xB6, so it should be possible to decompile .gdc into readable code.

girng commented 5 years ago

@bruvzg would that still be possible even if exporting with encryption enabled for scripts? (using a AES key)?

bruvzg commented 5 years ago

@bruvzg would that still be possible even if exporting with encryption enabled for scripts? (using a AES key)?

  1. Search this github repo for "encryption"
  2. Take a look at modules/gdscript/gdscript.cpp#L730-L803 (second non thirdparty search result)
  3. Open exported executable in the disassembler of your choice.
  4. Search for "GDScript::load_byte_code" and "gde" string references (strings literals used in function from step 2).
  5. Search in between and you'll find encryption key in a 10 seconds (even if you do not understand assembler at all, there are only 4 addresses to try).
  6. PROFIT!!!

Encryption won't help much, it's just 5 minute delay.

girng commented 5 years ago

dang @bruvzg. thanks. very interesting. since the extracted .pck shows the compiled gdscript files (.gdc), it does work, but just not when editing the .pck file itself with a text editor (raw gds code is displayed).

i wonder if it's possible so the .pck file doesn't show raw gds, but the compiled gds instead?

bruvzg commented 5 years ago

Decompiling gdscript turns out easier than I expect, here's proof-of-concept gdc decompiler, PCK extractor and binary <-> text resource converter: https://github.com/bruvzg/gdsdecomp

Clone into Godot's modules subfolder and rebuild engine.

vnen commented 5 years ago

Any encryption in the exported game will not avoid a persistent person who wants to get the contents. That is because not matter what you do, the encryption key must be somewhere in the binaries.

Also note that the PCK is essentially a file system, with the ideal of being easy and fast to seek to any specific file without having to extract the PCK itself. We couldn't encrypt the whole PCK just because it would require extracting the contents somewhere (which then could be looked by any person anyway). Encrypting each individual file is possible, but still the key needs to be somewhere, and the things are decrypted in memory, so anyone with CheatEngine or the likes of it could check it out.

Compiled GDScripts are not really "compiled", they are just the tokenized form written in a binary format.

vnen commented 5 years ago

If you really need to avoid people from peeking, the only solution is to host the data on your own server.

girng commented 5 years ago

Compiled GDScripts are not really "compiled", they are just the tokenized form written in a binary format.

i see. very interesting, thanks! edit: @bruvzg wow, starred. definitely following that

miskatonicstudio commented 5 years ago

The initial idea (mentioned in the title of this issue) is not to encrypt the files (that would not stop anyone, just delay them, as many people here already mentioned), but to obfuscate the files. While the names of variables seem to be hidden in the .pck file, the string content is very much visible. Is there a way to hide it somehow from the people who simply open the .pck file in Vim ?

girng commented 5 years ago

While the names of variables seem to be hidden in the .pck file, the string content is very much visible.

i tested it. opening a .pck in a text editor shows "uncompiled" gds (even variable names, etc)

miskatonicstudio commented 5 years ago

That seems like a serious issue for someone who wants to make bigger, professional games using Godot.

girng commented 5 years ago

@miskatonicstudio yeah, even now the hacker will prob stumble upon gdsdecomp 🗡 but, it's impossible to protect 100%. i also agree with vnen. i also think it shouldn't be that easy to see the source in .pck. in my opinion at least

JohnSilverLong commented 5 years ago

I have been working with C# and i also found it strange when the project.dll is add to pck the classes itself also have to be add to pck for resources that have reference to those classes.

Been working on a custom packer (for mono) that does 3 steps compile than obfuscate the project.dll and after that collect all stuff what should be packed into the pck. For the script files i create temp empty dummy files and than pack it all with the godot PCK script seems to work so far but i did not found a way to make the resources itself less readable.

ArdaE commented 5 years ago

@vnen Do you not put locks on your house doors, because anyone who's willing enough will find a way in? Or not lock your bike because anyone who's determined enough will steal it anyway? Just because you cannot prevent the most determined people does not mean we shouldn't provide any protection.

girng commented 5 years ago

i think vnen was just saying that to make a point that it can never really be hack proof. there will always be some way for a naughty person to get what they want. whether it's using ollydbg, gdscript decompiler, etc.

ArdaE commented 5 years ago

@girng I have the utmost respect for the core developers for their contributions to Godot. But @vnen closed another, more inclusive issue (#19790) after stating "... a false sense of security. Obfuscation is not really security." So he's not "just saying that to make a point"; he used that line of argument to dismiss a similar, earlier issue raised by others. I am thankful to him for all his contributions, but I wholeheartedly disagree with him on his stance on this topic.

P.S. I used to hack games when I was a kid (for single-player games, long before the multi-player games existed). So take it from someone who knows how things can be made harder to hack. We're not protecting national secrets here, and a little protection goes a long way.

girng commented 5 years ago

@ArdaE yes, i understand. he's not wrong though, since it's a open source project, it's gonna be impossible to protect because all algorithms will be found in the repo.

however, IMO, i do believe raw gdscript should not be available in the .pck (would solve the OP's issue too), but i don't know if that is possible because my knowledge is limited.

ArdaE commented 5 years ago

There seems to be great misunderstanding of what obfuscation means here. It doesn't matter if someone knows the algorithm used to obfuscate script files. Obfuscation is a one-way process; when done right, you can't get back to the original scripts, ever, nor does Godot need to do so to run the scripts. For those who seem to confuse it with encryption, please look up .NET obfuscators.

Further, as I've stated, "impossible" is not a reason to not provide any protection (at the end of the day, nothing short of quantum encryption is impossible to break). The idea is simply to make things difficult. If you don't need protection, that's fine, but I ask you to please not dilute and dismiss the discussion for those of us who care for it.

volzhs commented 5 years ago

someone is working for compiling gdscript to gdnative. http://blog.moblcade.com/?p=1 yeah. it looks awesome. this will solve the issue for projecting source code once it's done.

I hope he makes PR someday.

related issue here #11068

akien-mga commented 5 years ago

To clarify, the use case shown in the OP needs to be solved. End users should not be able to access human readable source code (scripts, scenes) by opening the .pck file in a text/hex editor, nor by extracting the contents of the .pck somehow.

This is easy to do, scripts and scenes need to be converted to binary formats on export (and we're supposed to have an option to do exactly that already - but maybe it's not working as expected?).

Further obfuscation to prevent crackers from getting access to resources and binary code is not planned. It's well established by now that even by spending millions on DRM and anti-cracking measures, AAA studios can only win a few days at most. It's not Godot's job to fight that (and I'd argue that it's pointless to even try).

There's a PR to restore the script encryption feature. As mentioned above, it's not particularly efficient, but if it makes some users feel more confident that their code is "harder" to crack, it doesn't hurt.

To further on the "door lock" analogy, sure, it's good to lock your door to prevent the neighbour's kid to enter and snatch your Switch. That's what should be done by preventing scripts and scenes to be human-readable in .pck files. But you can put 15 locks on a heavy duty door, it's no use against determined robbers if all it takes to get in is to break a window.

There seems to be great misunderstanding of what obfuscation means here. It doesn't matter if someone knows the algorithm used to obfuscate script files. Obfuscation is a one-way process; when done right, you can't get back to the original scripts, ever, nor does Godot need to do so to run the scripts. For those who seem to confuse it with encryption, please look up .NET obfuscators.

While this is true, obfuscation is not planned for Godot scenes nor GDScript. This issue is just badly titled, what it asks for is just to make scenes and code non human-readable.

bruvzg commented 5 years ago

There's Project Settings->Editor->Convert Text Resources To Binary On Export option (disabled by default) which seems to solve most of the plain text scenes/scripts problems in the .pck:

bruvzg commented 5 years ago

Currently export settings are spread across Editor Settings (adb, jarsigner, rcedit, wine, android keystone), Project Settings (convert to binary) and actual export dialog, android keystone options are duplicated in Editor Settings and export dialog.

It's gonna be much better to have all this stuff in the export dialog (moved or duplicated).

Calinou commented 5 years ago

Currently export settings are spread across Editor Settings (adb, jarsigner, rcedit, wine, android keystone),

Paths to various programs should probably stay in the Editor Settings, as these will vary from system to system. The same goes for the debugging Android keystore, as you typically want to set it up only once to use it in many projects. In contrast, the release keystore is defined in the Export preset, since it's far more likely to vary from project to project.

ArdaE commented 5 years ago

To further on the "door lock" analogy, sure, it's good to lock your door to prevent the neighbour's kid to enter and snatch your Switch. That's what should be done by preventing scripts and scenes to be human-readable in .pck files. But you can put 15 locks on a heavy duty door, it's no use against determined robbers if all it takes to get in is to break a window.

Exactly my point. Some basic protection is what's needed. The fact that people can get in anyway should not be used as a reason not to provide basic protection. And I don't see anyone here asking for 15 locks and a heavy duty door.

To clarify, the use case shown in the OP needs to be solved. End users should not be able to access human readable source code (scripts, scenes) by opening the .pck file in a text/hex editor, nor by extracting the contents of the .pck somehow.

This is easy to do, scripts and scenes need to be converted to binary formats on export (and we're supposed to have an option to do exactly that already - but maybe it's not working as expected?).

My understanding is that the binary format still includes all the function and variable names as is. Although this should be fine against those who peek into .pck files (as the code instructions will be binary encoded and hence unintelligible), it is an issue for people like me who write self-documenting code (with very descriptive class, function, and variable names), who don't want all of that to be available to anyone with a debugger (and hence the ability to step through the code while also seeing all the symbols names).

Further obfuscation to prevent crackers from getting access to resources and binary code is not planned. It's well established by now that even by spending millions on DRM and anti-cracking measures, AAA studios can only win a few days at most. It's not Godot's job to fight that (and I'd argue that it's pointless to even try).

Again DRM and obfuscation should not be addressed in the same context. I personally hate overdone DRM, as it makes things harder for paying users while not preventing theft (though I wouldn't get involved in the discussions of others wanting to implement it). Obfuscation is not DRM, does not require millions in spending, and actually makes code significantly more difficult to reverse engineer. The goal of obfuscation is not to prevent piracy of executables; it's to prevent easy piracy of source code and key algorithms. (Easy piracy = piracy by people who are not capable of writing said algorithms themselves in the first place).

There's a PR to restore the script encryption feature. As mentioned above, it's not particularly efficient, but if it makes some users feel more confident that their code is "harder" to crack, it doesn't hurt.

I don't care for encryption of source code personally. Unless you come up with some ingenious way of executing encrypted code without first decrypting it, anyone with a basic debugger can see the decrypted content in memory, without knowing your encryption key. There are mentions above of people easily finding your encryption key and using it to decrypt your code; I would say why even bother with that? I can see your code without knowing anything about Godot or your encryption algorithm or key, in a fraction of the time by doing a simple text search after loading your game in memory. In any case, that's not a discussion I want to get involved in, as others may care for it for their own reasons.

While this is true, obfuscation is not planned for Godot scenes nor GDScript. This issue is just badly titled, what it asks for is just to make scenes and code non human-readable.

I was thinking I might add that feature to Godot, but without the buy-in from core developers, I wouldn't risk spending all that time for a generic solution, only to get my PR rejected. I'll implement something simple for my own projects; others can do the same.

The better issue to leave open was #19790 (though it could have been split into two: one for script files and one for other resources such as 3D models, 2D images, audio files, etc.). Virtually all sites that sell 3D models, audio files, etc. only allow the use of their content in software products if their assets are "reasonably" protected. This is an important and real legal requirement that anyone releasing apps built with Godot needs to meet (anyone who uses such licensed/purchased content). I will provide such protection myself if Godot doesn't provide it, but one would think the Godot developer community should care about this.

P.S. Obfuscation has one more advantage in addition to providing protection: performance. In a dynamic language like GDScript, properly obfuscated code should run faster than non-obfuscated code in virtually all cases, as almost all symbol names would be shorter than their originals, resulting in faster look ups.

vnen commented 5 years ago

Obfuscation is quite hard to do in a dynamic language that relies on duck-typing. In particular with GDScript where scripts are not aware of each other. We pretty much can't change the names of functions or any class-level members for that matter. Only local variables inside functions are safe to change, and while that can help it's not enough I'd say. Maybe analyzing all scripts at once and replace all equal names with the same thing might be possible, but honestly I don't know if such complexity is worth it, since it's bug-prone and hard to maintain.

Unless we rely on the typed statements, where we can actually make the scripts aware of each other. Though still the obfuscation process would need to take all scripts into account at once, especially in the cases where the dependency graph has cycles (it's technically not possible to have cycles with current GDScript, but it should be in the future).

IMO to get around this we need to store GDScript actually compiled to byte code. Then we get the best of both worlds since it'll be harder to decompile scripts and we don't need to use the parser in the exported game, making the loading process a tad faster.

vnen commented 5 years ago

Also, AFAIK it's possible to make an obfuscator plugin if you're willing to, maybe even hook up with an EditorExportPlugin to trigger automatically on export.

vnen commented 5 years ago

And to clarify: my main point is that people seem to think that a lock is enough to keep everyone out, while it's not. I don't think the code should be visible in plain text (but I also don't think is such a big deal).

Honestly I wouldn't put puzzle answers in code anyway, I would use some sort of data storage for this, and by doing so I could even encrypt the file with a special key, since Godot has functions for dealing with encrypted files already (the key would need to be in the code, but compilation should be enough to hide it from plain sight, since it's all you want to do).

ArdaE commented 5 years ago

I'm not sure if I understand why obfuscation is difficult; I may be missing something. I was thinking the compiler, after/as it parses the script files, would convert any encountered name that doesn't exist in Godot's list of API bindings or in a user-provided safe list to an automatically generated name. It would also maintain a table (dictionary) of already converted names. If a name already exists in the table, the existing conversion would be used; otherwise a new one would be created. The automatically generated names would use a banned/untypeable single character prefix or suffix to prevent conflict with any existing symbol name. The rest of each name would be constructed deterministically, starting with single letter words, getting longer as all the possible combinations for the current word length get used up.

The user provided list would be there for special use cases where a developer uses runtime constructed strings to access some of their own code elements (e.g. to dynamically call a function of theirs using a constructed string) (the developer would know exactly what range of symbol names are accessed via dynamically constructed strings, and can provide the list). It might help to make this list support wildcards, or regular expressions if one is willing to get fancy. Alternatively (or in addition), a simple reserved prefix can be used to denote safe names that won't be converted (e.g. "SAFE_MyFunction") to prevent the need for the user to provide a table.

I can't currently think of any case where this would fail; please correct me if I'm missing something. It's an approach that won't convert names that match any name that exists anywhere in the Godot APIs, but obfuscation does not need everything to be converted to be effective. Developers who want everything to be converted can use a different naming convention than Godot's naming convention, and most everything would get converted for them.

This can only safely be done by the GDScript compiler/parser. An external tool cannot do it safely, as it would be very difficult to keep its implementation in sync with Godot's parser, version after version, to perfectly match Godot when it comes to identifying symbol names in the code. I'm not sure if Godot provides any hooks for plug-ins for compiler/parser stages; if it does, only then this could be implemented as a plug-in.

Obfuscation would only be done on export, when all the scripts are being processed. The obfuscation dictionary can be created at the beginning of the export process, and built up until the end of the export. Scripts don't need to be aware of each other for this to work.

girng commented 5 years ago

i was thinking about something last night, after reminiscing about @bruvzg's decompiler and the XORed with 0xB6 statement

could that be modified before compiling the engine? to make the "hacker's life" a lot harder? or would that not work? was just thinking of an idea

bojidar-bg commented 5 years ago

I can't currently think of any case where this would fail

I think I can think of a few cases:

  1. When you have multiple .pck files (already a possibility), they will have to be exported with full knowledge the previous ones. Alternatively, all methods of scripts in other .pck-s will have to be in the safe list, and renamed methods will have to include the .pck they are in (to prevent clashes).
  2. All calls to has_method, get_method_list, and call are dangerous. While some of them might be transformed, there will always be some that are too dynamic to obfuscate safely.
    • AnimationPlayer, Tween, InstancePlaceholder, and other nodes refer to names of properties and methods as part of their business. Either scenes are obfuscated as well, or everything used in a scene has to be on the safe list.
    • This has to include instantiations of such nodes through script.
  3. Existing games will break upon being exported, as they have no safe list.
  4. The added complexity will, quite likely, result in bugs, and they will be hard to find.
  5. Difference between exported and edited versions will cause incompatibility between the two. This might not sound like a big deal, but debugging an exported game is hard.
  6. GDNative, PluginScript, C#, and VisualScript scripts will also need to have their identifiers replaced, unless all of them are supposed to go into the safe list, at which point, obfuscation becomes useless for developers using those technologies.

Unless a solution manages to fix points 2 and 6 automatically, it will likely not succeed. Such a solution will, by necessity, include changing how scripting currently works. Unless it covers point 3 as well, it will have to wait for a major Godot version, probably one that has a massive refactoring and breaking of compatibility.

A proposal, collapsed so it won't take as much vertical space The simplest way to make it work is to ban all things which might cause a string to be used as an identifier (such as `call(string)` and `set(string, value)`, maybe even Node names for a good measure). That way, points 2, 5 and 6 will magically disappear, since there will be no way for them to occur. (1 and 4 are easier to fix anyway) At the same time, an `Identifier`/`Symbol` type (which exists as `StringName` currently) will have to be added, and all scripts forced to use it when they want to call something. Additionally, PluginScripts and GDNative scripts will need to know about this new type in order to be able to do anything. Every Symbol will have some information about its underlying string, but it will not be accessible except for debug purposes. At runtime, the Symbol will be just an integer and nothing more. At that point, obfuscation would be just a hash function which transforms all identifiers' integers into other integers, effectively shuffling the list. As identifiers will be an integral part of the engine, everything should run the same in the editor, the played version, and the final, exported, version. Honestly, while a Symbol type is pretty cool IMO, this is a lot work, which will conflict with nearly everything else once it is merged in. I would estimate around a month of for refactoring everything, all for no added features and a very slight performance benefit. All of which will potentially be a waste, if it isn't merged in the end.
bojidar-bg commented 5 years ago

@girng Well, xoring is a reversible operation which is quite similar to addition, so this would qualify as a cipher quite similar to the Caesar cipher. It is going to be very weak, because if you happen to know just one piece of plaintext (for example, "has_method" or "show" or "player", etc.), you can immediately match a few target locations in the enciphered block of text, and proceed from there. Or even simpler, you can just test all 256 values of the constant in parallel, and use the match which looks the most like human-written text.

At any rate, we can just use AES and sleep sound knowing it is hard to break if you can't find the key.

bruvzg commented 5 years ago

could that be modified before compiling the engine? to make the "hacker's life" a lot harder? or would that not work? was just thinking of an idea

AES encryption + make exported executable difficult to analyze and extract key (like cover it with Denuvo/VMProtect/some other nasty stuff) would make the "hacker's life" a lot harder (for a few days).

girng commented 5 years ago

@bojidar-bg

Click to view

very interesting thanks for the info. regarding @bruvzg's comment above about finding the AES key, that seems like it would be just as easy as finding the xor key? but i mean at that point, if the "person" is being naughty looking at code and finding the key in enciphered blocks of text.. there is not much we can do, right? the hacker is gonna hack i was just thinking of additional layers to make the process harder. if the xor key is in the master repo, they can just use gdsdecomp instead of finding the xor key themselves. then once they do that, they'd have to re-compile the gdsdecomp, etc. i'm in the process of re-compiling godot with a diff xor key right now. then, gonna test the original .gdc (from master branch) with gdsdecomp to see if it'll work. if it does NOT, that's something i'll probably continue to do. and use the AES key. i think that might be enough layers?

__

edit: from what i've read so far, finding the xor and AES key is not difficult. there has to be something else the developer can do, unless i'm underestimating the process of finding the keys? i mean, this sounds like something I could even do, and i'm not smart.

bruvzg commented 5 years ago

from what i've read so far, finding the xor and AES key is not difficult.

Finding XOR key Here's relevant part of `GDScriptTokenizerBuffer::set_code_buffer`: ```c++ ERR_FAIL_COND_V(len > total_len, ERR_INVALID_DATA); b += 4; Vector cs; cs.resize(len); for (int j = 0; j < len; j++) { cs.write[j] = b[j] ^ 0xb6; } ``` Like with the AES key you can quickly find it by searching for error message string used by `ERR_FAIL_COND_V`, and from there it's pretty easy to compare code with assembly and get XOR constant: ![screenshot 2019-01-04 at 15 12 27](https://user-images.githubusercontent.com/7645683/50690625-b015ae00-1036-11e9-9780-55e3e008e131.png) With source code available it's zero effort task.
girng commented 5 years ago

FFFFFFB6 oh wow lol

ArdaE commented 5 years ago
  1. When you have multiple .pck files (already a possibility), they will have to be exported with full knowledge the previous ones. Alternatively, all methods of scripts in other .pck-s will have to be in the safe list, and renamed methods will have to include the .pck they are in (to prevent clashes).

I wasn't aware of multiple .pck's being a possibility, but I don't understand how that is really an issue. If all .pck files are created at the same time, then the conversion (obfuscation) table would be generated as the packages are being created, no different than the generation of a single pck. If Godot does/will support generation of different .pck files that make up a project at different times, then the solution would be to simply save the project-wide conversion table to disk for future .pck generation, with the option to delete it for a clean start (when the user wants to clean up the obfuscation table).

  1. All calls to has_method, get_method_list, and call are dangerous. While some of them might be transformed, there will always be some that are too dynamic to obfuscate safely.

This is what the safe list (with wildcard or regular expression) patterns and the safe prefix are for. Also keep in mind that we're not touching any name that exists anywhere within the Godot APIs, so all animations etc. accessing positions, etc. are inherently safe. Further, I always thought of obfuscation as an opted-in feature (I can't imagine it being the default), and I don't see any problem with developers who enable it having to go through a few extra steps.

  1. Existing games will break upon being exported, as they have no safe list.

Why are existing games being obfuscated? Again, I foresee all types of obfuscation being an optional feature.

  1. The added complexity will, quite likely, result in bugs, and they will be hard to find.

If a developer forgets to add a word/pattern to their safe list, yes, they will have a bug, they will debug their code, find the issue, and fix it. I don't see how this is different than countless other features that bring with them new possible ways of failing.

  1. Difference between exported and edited versions will cause incompatibility between the two. This might not sound like a big deal, but debugging an exported game is hard.

There seems to be the assumption that obfuscation will be the default, de facto generator of Godot packages. I foresee obfuscation as an optional feature, only to be enabled by developers who want to use it. Add a warning next to the option if you will (that, if not used correctly, obfuscation may break the exported code and will make debugging of exported code hard).

  1. GDNative, PluginScript, C#, and VisualScript scripts will also need to have their identifiers replaced, unless all of them are supposed to go into the safe list, at which point, obfuscation becomes useless for developers using those technologies.

Good point. Safe prefix and/or safe list with pattern matching to the rescue! If it feels like too much to bother with, don't enable obfuscation.

Unless a solution manages to fix points 2 and 6 automatically, it will likely not succeed. Such a solution will, by necessity, include changing how scripting currently works. Unless it covers point 3 as well, it will have to wait for a major Godot version, probably one that has a massive refactoring and breaking of compatibility.

Please see my comments for 2, 6, and 3 above.

I don't know Godot's internals, and I understand some of your concerns above, but I still don't see why this is such a big deal or needs to be complicated. Obfuscation is for developers who want to protect some key parts of their code, and they will have to deal with the added complexities. All Godot needs is have some very basic/simple support for it.

I don't see how any of the above would take a month to implement, but here's an even easier proposal to implement:

ArdaE commented 5 years ago

At any rate, we can just use AES and sleep sound knowing it is hard to break if you can't find the key.

@bojidar-bg How is encryption any type of protection for code that needs to be loaded into memory? I'll simply let your code load and decrypt itself nicely using whatever advanced algorithm and key you have devised, and then peek into its memory space using a debugger. (Mind you, I guess it would address the title of the issue, and provide some false sense of security).

akien-mga commented 5 years ago

How is encryption any type of protection for code that needs to be loaded into memory? I'll simply let your code load and decrypt itself nicely using whatever advanced algorithm and key you have devised, and then peek into its memory space using a debugger.

Well, that's your "locked door". Experienced robbers can always break your lock or find another way in, but that's good enough to prevent most unwanted visitors.

ArdaE commented 5 years ago

Well, that's your "locked door". Experienced robbers can always break your lock or find another way in, but that's good enough to prevent most unwanted visitors.

Touché.

akien-mga commented 5 years ago

To be clear, I think most users will be perfectly happy with this kind of "protection" offered by non-human readable binary files and optionally, some encryption. Sure, it can be broken, and quite easily if you know what you're doing, but it's still good enough for 99.9% of their legit users who have nothing to do in this code (and likely no interest to look into it beyond curiosity).

A real obfuscation feature as discussed above could be interesting for the users who really want this kind of protection, but I'm not sure the additional complexity is worth it for the engine out of the box. Might be worth exploring this possibility as a C++ module, and let interested users compile it in themselves. If it turns out not to make things too complex and a very popular module, we could consider merging it in the core.

girng commented 5 years ago

Might be worth exploring this possibility as a C++ module, and let interested users compile it in themselves. If it turns out not to make things too complex and a very popular module, we could consider merging it in the core.

Your time to shine, ArdaE 💯. I'll be the first one to test it out too, please lmk.

Darkinggq commented 5 years ago

https://www.youtube.com/watch?v=FdNXTFD59Tw

it's very sad bad hacking file open pck (Images, Music, 3D Models)

n3xxt commented 4 years ago

As someone who was planning to use Godot for production and who has supported it via Patreon during the past 4 months, I have found this issue a real no-go deal breaker with the following irreversible takeaways:

(AA) It is disturbing to see comments from the core GoDot contributors @vnen such as the following

If you really need to avoid people from peeking, the only solution is to host the data on your own server.

Even more so frustrating is the amount and names of upvoters to this.

(BB) The obfuscation / encryption idea / suggestion / concept is here because GoDot is actually a cross-platform self contained interpreter of GdScript, and why GDScript is not even being compiled into GDNative in export / publish is a mistery;

not so much of a mystery anymore considering that core contributors are of the following opinion:

vnen commented on Jan 3, 2019 ...the PCK is essentially a file system, with the ideal of being easy and fast to seek to any specific file without having to extract the PCK itself ... Compiled GDScripts are not really "compiled", they are just the tokenized form written in a binary format.

(CC) closing open issues without actually resolving them:

(#19790) opened Jun 26, 2018 [closed, unresolved] "... a false sense of security. Obfuscation is not really security."

I'm closing this since DRM won't be added and conversion to binary is already tracked by #12452 https://github.com/godotengine/godot/issues/19790

(#12452) opened Oct 28, 2017 vnen commented on Jun 30, 2018 https://github.com/godotengine/godot/issues/12452

(DD) The only 3rd-party seemingly active in producing the expected result [compiling GDScript into C/GDNative] has abandoned their project

http://blog.moblcade.com/?p=1

(EE) Redirecting the issue towards "others have this, too"

bruvzg commented on Mar 12, 2019

Do other game engines have any built-it "assets protection"? Nop, Unity and Unreal forums are full of the similar "Protect game resources" topics, with the exactly same answer: "it's pointless". (And asset stores are full of third-party snake-oil tools).

https://github.com/godotengine/godot/issues/19790

And that comment has 5 upvotes.

Both Unreal and Unity do not contain source of the either Blueprints / C# code; Unity has a popular 5-star obfuscator in the asset store plus an ati-hack solution, whereas Unreal actually compiles Blueprint and the end result is ahead of time compiled binary.

(FF)

akien-mga commented on Jan 4, 2019 A real obfuscation feature as discussed above could be interesting for the users who really want this kind of protection, but I'm not sure the additional complexity is worth it for the engine out of the box. Might be worth exploring this possibility as a C++ module, and let interested users compile it in themselves. If it turns out not to make things too complex and a very popular module, we could consider merging it in the core.

Sounds promising but has not been delivered ever since.

(GG)

reduz commented on Jun 28, 2018 3.1 will have an experimental option to convert all text resources to binary on export https://github.com/godotengine/godot/issues/19790 yet, akien-mga commented on Dec 16, 2018 We ran out of time to implement new features for 3.1, so it will have to wait for 3.2. If it's implemented during 3.2 development, it might still be cherry-picked to a 3.1.x release though.

But this issue is pretty vague, and since the feature apparently exists already (albeit opt-in), the most useful would be to have users testing it and report bugs if they experience any. https://github.com/godotengine/godot/issues/12452

"apparently exists already"

apparently, it is buggy:

[editor] convert_text_resources_to_binary_on_export=true reduz commented on Oct 30, 2018 It will work with (maybe) bugs https://github.com/godotengine/godot/issues/12452

(HH) ...and all this is happening ever since the initial feature request dated back to Oct 4, 2016 (today is Apr 28, 2020) https://github.com/godotengine/godot/issues/6709 closed and "merged" to https://github.com/godotengine/godot/issues/12452

reduz commented on Nov 26, 2017 No, no time, will be pushed for 3.1

akien-mga commented on Dec 16, 2018 We ran out of time to implement new features for 3.1, so it will have to wait for 3.2. https://github.com/godotengine/godot/issues/12452

To conclude, it seems that Godot project and their maintainers are rather interested in achieving academic goals than preparing itself for a heavy commercial AAA production.

With all due respect, I am afraid this direction and approach are not sustainable for the real world application use case.

Please tell me, why a person with commercial goals would want to continue supporting this project with further voluntary contributions - directly monetary via Patreon and indirectly with knowledge / product / title releases, while witnessing all this negative attitude towards the real world needs of a commercial publisher/developer/entity?

This is a rhetorical question, mind you.

ref

https://github.com/godotengine/godot/issues/6709 https://github.com/godotengine/godot/issues/12452 https://github.com/godotengine/godot/issues/19790 https://github.com/godotengine/godot/issues/37669 https://github.com/godotengine/godot/pull/33228 https://github.com/godotengine/godot/pull/24582 https://github.com/godotengine/godot/issues/24716