This is how I protect my 3D models

Hi! This post is intended to help other developers to protect their 3D assets. Many of you are interested in protecting your assets, especially your 3D models as we can see in the forum here:

I was asked to find a solution to protect 3D models. We all know that with web technology, we need to distribute the resources on user devices to get them displayed. So I decide to see if there’s a way to encrypt my 3d models and made them readable only from my own applications (with minified and obfuscated code). Still, my method is not 100% proof, but will require considerable effort to steal my models.

I will share you the idea behind this and some code, but I can’t share you my complete recipe, obviously for security reason.

Thanks to @yaustar and his help about this question: [SOLVED] How to create an Asset from file content stored in variable?. Using this code mean that it is possible to read a GLB file from a variable or even from a database (check the size of your GLB before going there).

So, this also open the possibility to get your GLB from anywhere. In my case, I still store the 3D models in files but not in a GLB, in a custom file extension! Yep, just rename your glb file to anything else. This will hide to others that your are using GLB.

Also, another protection I add on top of that, is by changing the binary of the file, to make it intentionally not usable. You will need some binary comprehension to go there. I did explore and changed the binary of a my new custom glb file using this Free hex editor. Note the position and the value of what you changed in this file, store that somewhere, because you will need that later.

Now, you have a new custom file like this “my3dModel.yourExtension” that is not usable.

At runtime, you need to load this file by using the binaryHandler from the Playcanvas engine.

this.app.loader.load("/my/3d/model.yourExtension", "binary", function (err, data) {

    //Data will be an arrayBuffer 
   //The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. 

});    

If you load your model from a variable, you will not need to do this step. But hey, it is usufull to have models in files.

Now, you have your model in binary! But remember, the binary was changed to make it unusable. Now, it’s time to fix it by playing with binary again. And for that, you will need to use DataView.

The DataView view provides a low-level interface for reading and writing multiple number types in a binary ArrayBuffer.

From there, you will need to use DataView to access the index of the binary you have changed and but the good value.

var self = this;
this.app.loader.load("/my/3d/model.yourExtension", "binary", function (err, data) {

    //Data will be an arrayBuffer 
   //The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. 
   
    //Fixing the binary
    var dataview = new DataView(data);
    dataview.setInt8(98765, 12345);

     var blob = new Blob([data]);
     var data = URL.createObjectURL(blob);
     
     //This must end with ".glb"
     var filename = 'test.glb';

     var file = {
         url: data,
         filename: filename
     };

     var asset = new pc.Asset(filename, 'container', file);

     asset.once('load', function (containerAsset) {
         my_entity.model.asset = containerAsset.resource.model;
     });

     self.app.assets.add(asset);
     self.app.assets.load(asset);
            
});

Et voilĂ ! You can now display your 3D model in your scene. :slight_smile:

3 Likes

There are some tools for PC games that allow ripping models and textures from VRAM. I’m not sure if the same exists for WebGL though.

It is true. We can’t entirely prevent piracy due to the way video cards work. This is true for any process that uses a video card, like games or any other WebGL/WebXR engines.

At least, with my method, my models are not exposed. We can’t just check the console, find the url of the model and download it.

why not encrypting the file instead of just swapping one int inside it?

That is true, the person would have to get the data after the fix up and download it as a file.

This is another possibility. What kind of encryption are you thinking about?

Don’t forget that you will need to decrypt it to make it readable by the engine. It is not like a password, where you can just compare the two encryptions to verify if it’s good.

Oh also, in my example, its the swap of only one int to show how you can do it. In fact, I did something more complex than that. I didn’t reveal my whole recipe here. :wink:

well any encryption that encrypt file and has some library that can decrypt it. The decryption key would have to be stored / downloaded of course, but that’s not any less secure than messing with binary data.

1 Like

This is great work, but for anyone following it’s worth noting that these methods are more obfuscation than protection. It will definitely stop people grabbing assets out of DevTools, but it wouldn’t take long to map some large binary downloads with the your decode function and get the underlying asset. So I’d be cautious for those who need fully secure assets. As @mvaligursky mentioned, ideally you’d want some sort of key encryption on the binary, where the only people who can decode it are those you allow.

1 Like