Notifications
Clear all

[Closed] Protecting encrypted maxscripts

If an encrypted maxscript generates an error during evaluation, this error is printed to the listener.
This affects private functions inside of data structures as well (if they are accessed by public functions). For example:

fn thisBreaks = (box.theGrak=undefined); thisBreaks()

This code will print the following error when evaluated as plain or encrypted maxscript:

-- Error occurred in thisBreaks(); filename: C:\Users\Garrick\Desktop\maxscripts	hisBreaks.ms; position: 43; line: 2
   --  Frame:
   --   called in anonymous codeblock; filename: C:\Users\Garrick\Desktop\maxscripts	hisBreaks.ms; position: 58; line: 2
   --  Frame:
   --   thisBreaks: thisBreaks()
   -- Unknown property: "theGrak" in Box

And here is an example printing errors generated by private functions inside of data structures:

(	--can print error from private fn called from public fn
   	struct myStruct (
   		private fn thisBreaks = (box.theGrak=undefined),
   		public fn tryBreak = thisBreaks()
   	)
   	mS = myStruct()
   	mS.tryBreak()
   )

This code will generate the same error as plain text or encrypted maxscript.

So, if you’re releasing encrypted maxscripts for commercial use – be aware that your maxscript is decrypted to plaintext before it’s evaluated in max, and can therefore be recovered and interrogated in various ways.

Also, I’ve read on different forums/boards that we aren’t supposed to discuss vulnerabilities such as these, but at the same time – doesn’t it make sense to inform maxscript developers of such vulnerabilities so they can release more secure code? All it takes is a try() and catch() and the error is no longer printed to the listener, but adding try() and catch() slows down the evaluation time, and reads as sloppy code to other programmers.

So what about a patch:
If a user is running a .mse, and that .mse generates an error during evaluation, please print/report a ‘general error’ message to the listener, not decrypted code.

If a user is running a .mse then they aren’t developing code, so why would they need to receive a detailed error message? And handling the error within the script itself via an error log or email seems to be a better alternative since most users won’t forward the error to the developers anyway. Thoughts?

2 Replies

hi garrick,
i was always under the assumption that if you don’t have any code within the catch brackets it isn’t significantly slower. I’m sure someone will be able to benchmark how many milliseconds faster it is without, but you can probably avoid having to use try/catch anyway with reasonable planning. as for looking sloppy, its encrypted, so if someone is reading that you’ve used a try/catch then they’ve hacked your code anyway!
i don’t tend to use it that much, as i generally want to see exceptions and look out for them in order to make my code better and understand the circumstances it might be failing. much of our pipeline is encrypted, which is fine until there’s a problem. there’s still not enough information going to the listener that anyone could make sense of. that’s why i have set up a system so i can swap, on the fly to an unencrypted development pipeline for debugging and testing.

@Lonerobot: that setup and pipeline you’re describing sounds pretty amazing. But what I’m trying to convey is that the private methods of a struct shouldn’t dump errors according to the autodesk 3dsmax 2012 documentation. Specifically section 114, “Private and Public Members in Structure Definitions”:

When defining members (variables and functions) in a struct, the qualifiers public and private can be used to control the member’s visibility to users and the Debugger. Public members can be accessed by outside code. If no qualifier is specified, members are considered public by default. In releases prior to 3ds Max 2010, all members were always public.

                         [i]Private[/i]                 members are accessible only from within the structure instance. Attempting to access a private member will result in a Runtime             error. If the struct is defined in an encrypted script, the member values will not be shown in the Debugger or in error dumps.                       

The last sentence is the most important, because the 2nd script posted above illustrates that a private member will dump errors even if the script is encrypted. I think if it’s encrypted, a general error should be dumped, because otherwise it might spit out information that could compromise your script. For example, lets say I want to check out a global struct that was declared in an encrypted script that I just ran, or lets say I wanted to just “troll” for data structures from an encrypted script. I run the script, then inspect the global variables:

(
  	--collect all the global vars, print their info... warning: this will take a moment to complete!
  	local myGlobals = globalVars.gather(); for i=1 to myGlobals.count do apropos myGlobals[i]
  )

I’ve found that I can recover a great deal of information (which other algorithms can operate on) about any global variable or struct. Then malformed parameters can be passed to those global variables, resulting in errors and thus dumping internal code to the listener. This means that a global variable is much less secure than a local one, and this includes private members in structs. I haven’t found a way to collect local variables, structs, or functions from inside a script, so it seems like local definitions are the most secure way to write maxscripts.

The other important aspect to this that I’m trying to open up discussion about is the general unsecure nature of how 3dsmax handles encrypted maxscripts. Decrypting the entire maxscript into memory opens up attack vectors that could be avoided. As someone who has been working on several unreleased commercial maxscripts, I find it hard to place trust in that kind of environment. Why not decrypt parts of the maxscript on the fly with some “just in time decryption” or write a maxscript compiler that operates on the actual encrypted data? Why decrypt the data in it’s totality and then trust the contents to the operating system? Having ran some basic tests myself, I’ve been able to recover strings defined in encrypted scripts simply by dumping the ram and running a program to extract all the C strings with a null terminator at the end. That’s not secure! And if someone as stupid as me can take 3dsmax.exe apart using a few google searches, it’s scary to think what an intelligent person who actually knows what they are doing could do.