Menu

In-Memory Obfuscation for your data

July 20, 2012 - .NET, C#, Programming

Gamers are an enterprisey bunch. You don’t give them enough X, so they go prodding around your game’s memory to try to give themselves more. Programs that have this purpose are called “Cheat engines”. Usually, how they work is a multi-step process.

  1. The obvious first step is for the cheater to decide what they want. Lives? More Gold? Maybe they want to up their players attack power?
  2. This is usually fairly easy, and you can usually tell the data type just by the amount of screen space reserved for a value. Though sometimes you just have to guess. Many cheat engines can search for values regardless of the actual data type, too.
  3. Now, the cheater looks for every value in the game’s memory that has the current value of the item they want to ‘hack’. The results will usually be collosal.
  4. In order to revise the search parameters, the gamer/cheater will now “change” that value somehow; by perhaps losing a life or getting a new one, getting more score, using a “attack upgrade” pill, or what-have-you. Armed with the new value, they can now tell the cheat engine program to show them all the values that were the old value before that have now taken on the new value. If they are lucky, this will be only one entry, and they can use the cheat engine and change it, and BAM they have the new value they hacked in.

The typical, and perhaps smartest way, to deal with this problem is to ignore it. A well architected game system will have any multiplayer values centralized on a server which means that a cheat engine will only mess around with a client of the game, and there are ways of checking for those hacked clients as well, (because they can give players a minor advantage). However it bears an interesting topic of discussion- how do you prevent this?

With some considerations, I have determined a method to do this- each time a value is assigned, generate a new random value, store that, and then only store a version of the original value that was encrypted. The idea being that the existence of the “actual” value- the value the cheater would be able to identify- is transient and only exists in limited scopes, making it nearly impossible to find the correct value to change, and even if they do find it, the method of encryption/hashing means they would need to know the corresponding algorithm and number in order to turn a new value they wanted and store it in memory so the Obfuscated class to which said value is associated will decode it properly.

The trouble with this method lies in the fact that it is anything but transparent, and requires copius code changes all over the place.

Enter Generics & Templates

Generics and Templates are the obvious solution to this problem. With C++, this sort of class nearly writes itself, actually; since templates are a compile time feature. you could then replace values that are int with something like Obfuscated and not have to change anything else.

Being that I work primarily in C#, however, this was the focus of my attentions. And it is not quite as simple, though thankfully the addition of dynamics to the language really helps make the code more concise for this sort of purpose.

Everything seems to work fine initially; you can create a generic class Obfuscated, then define operator methods that can cast a T to an Obfuscated and vice-versa without too many problems. problems start to arise as you realize that the original code is using operators and the implicit casts are not being performed (because there is no reason for the compiler to think that casting the two values from Obfuscated to the type T will make the operation valid). So you define operator overloads. The typical result in C# 3 was rather messy. Since there was no way to define a constraint that said to only allow arithmetic operators, nor is there an interface you could cast to to check if the Type T for which your generic instance was constructed supports arithmetic operators, you were left in the cold. For many types you could use the built-in operator methods themselves, op_Addition, op_Subtraction, etcetera. What you would end up with is a large else-if ladder that checked for all of the primitive types, with an else block that used reflection to call the appropriate operator method that way; and failing that throwing an InvalidOperationException.

Dynamics to the rescue, however. Thanks to C# 4.0’s addition of the dynamic keyword, which introduced late-bound variables, we can actually make the call relatively simple. we can perform operators on dynamic variables and the call will be resolved at run-time, and will be handled appropriately even for the primitive types.

With that out of the way, there was only one question left: the encoding. I decided on a simple interface that allowed to decode and encode a arbitrary set of bytes. I implemented a simple xor encryption and used that for my tests. The tricky portion is of course getting some arbitrary set of bytes representing a variable of your generic type; this isn’t something you can really force with constraints. You really need a Type T that is either a structure or a serializable value. For this purpose I created two general purpose generic methods:

First, the method to convert a given value of a Type P to a array of byte[]:

If it is a ValueType, we use the Marshaller to get the actual in-memory representation of the structure, copy it to a array of bytes of the appropriate size, and then return that. Otherwise, we try to save it to a MemoryStream using a BinaryFormatter, slurp out the contents of that memorystream, and return that array of bytes to the caller. The corresponding function that turns a given array back into the corresponding type is obviously just the reverse of this:

by replacing a variable of a given type T with an Obfuscated, you get almost completely transparent obfuscation of the in-memory representation of that type. Assignments result in the generation of a new random number, encrypt the passed value, and store the encrypted value, and retrieving the value or an implicit cast to the type will deobfuscate the value and return that.

The Full source to my test project which contains and uses this class is attached:
Memory Obfuscation Class

Have something to say about this post? Comment!