20 Jul 2012 @ 9:13 PM 

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 [] :

  1.  
  2. public static byte []  TypeValueToBytes<P>(P valueget)
  3. {
  4.     if (typeof(P).IsValueType)
  5.     {
  6.         //convert the given to bytes.
  7.         int size = Marshal.SizeOf(valueget);
  8.         byte []  arr = new byte [size] ;
  9.         IntPtr ptr = Marshal.AllocHGlobal(size);
  10.         Marshal.StructureToPtr(valueget, ptr, true);
  11.         Marshal.Copy(ptr, arr, 0, size);
  12.         Marshal.FreeHGlobal(ptr);
  13.         return arr;
  14.     }
  15.     else //reference type
  16.     {
  17.  
  18.         //otherwise, serialize it to a memorystream and return the stream contents.
  19.         try
  20.         {
  21.             BinaryFormatter bf = new BinaryFormatter();
  22.             using (MemoryStream ms = new MemoryStream())
  23.             {
  24.                 bf.Serialize(ms, valueget);
  25.  
  26.  
  27.                 ms.Seek(0, SeekOrigin.Begin);
  28.                 byte []  retrievebuffer = new byte [ms.Length] ;
  29.                 ms.Read(retrievebuffer, 0, (int)ms.Length);
  30.                 return retrievebuffer;
  31.             }
  32.  
  33.         }
  34.         catch (Exception sex)
  35.         {
  36.             throw new ArgumentException("Failed to create Byte stream from reference type " + typeof(P).Name, sex);
  37.  
  38.  
  39.         }
  40.  
  41.     }
  42.    
  43. }
  44.  

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:

  1.  
  2. public  static P TypeBytesToValue<P>(byte []  contents)
  3. {
  4.     //convert the given bytes to the object.
  5.     //assume presence of default constructor…
  6.    
  7.     Type usetype = typeof(P);
  8.     if (usetype.IsValueType)
  9.     {
  10.  
  11.         P newvalue = default(P);
  12.  
  13.         int size = Marshal.SizeOf(newvalue);
  14.         IntPtr ptr = Marshal.AllocHGlobal(size);
  15.         Marshal.Copy(contents, 0, ptr, size);
  16.         newvalue = (P)Marshal.PtrToStructure(ptr, usetype);
  17.         Marshal.FreeHGlobal(ptr);
  18.         return newvalue;
  19.     }
  20.     else
  21.     {
  22.         //otherwise, write the bytes to a memory stream and deserialize to an object.
  23.         try
  24.         {
  25.             BinaryFormatter bf = new BinaryFormatter();
  26.             using (MemoryStream ms = new MemoryStream())
  27.             {
  28.  
  29.                 ms.Write(contents, 0, contents.Length);
  30.                 ms.Seek(0, SeekOrigin.Begin);
  31.                 return (P)bf.Deserialize(ms);
  32.  
  33.  
  34.             }
  35.         }
  36.         catch (Exception exx)
  37.         {
  38.             throw new ArgumentException("Failed to retrieve reference value of type " + typeof(P).Name, exx);
  39.  
  40.  
  41.         }
  42.  
  43.     }
  44.  
  45.    
  46.  
  47. }
  48.  

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

718 total views, 4 views today

Posted By: BC_Programming
Last Edit: 20 Jul 2012 @ 09:13 PM

EmailPermalinkComments (0)
Tags
Tags: , , ,
Categories: .NET, C#, C/C++, Programming
 20 Jul 2012 @ 2:47 AM 

This is a old blog post that I seem to have forgotten to publish when I originally wrote it.
-BC_Programming

When you write a computer program, you are providing the computer with instructions on how it should work with values in memory using the Processor to perform a task. managing the allocation and deallocation of blocks of memory is memory management.

With some programming languages, the burden of implementation is on the programmer. For example, in C, most non-trivial applications are going to need to allocate and free blocks of memory. These are done by the now ubiquitous malloc() and free() functions, present in the C standard Library. What makes this interesting is that it breeds a pattern of memory usage, whereby— with the exception of bugs — memory is only allocated when it is being used by the program; the idea is to deallocate memory blocks as soon as they are no longer going to be used. This has an advantage in that it is ideal for reducing the memory footprint of a program, which is essential if that program runs on an embedded device or otherwise needs to keep a close eye on what it’s allocated. However, there is a tiny drawback with this approach- freeing memory, of course, takes processor time away from other tasks. A negligible amount, but it does; particularly when you perform a bunch of free() calls on smaller memory blocks as opposed to freeing the entire thing a single time.

In any case, with this pattern, there was of course a lot of repetition- Every allocation needs a corresponding free- and only one, otherwise you end up with bugs from freeing the same block of memory twice. This bred Design patterns- basically, constructs both within the language as well as via frameworks that made this task more automatic, so that developers could focus on their goal. With the advent of C++ and Object oriented constructs, there came RAII, or “Resource Acquisition Is Initialization”; the basic idea is that resources are allocated in the constructor of objects, and deallocated in the corresponding destructor; since destructors are guaranteed to run when an error occurs (well, with the exception of using balls-up hardware or a power failure or something) this generally guarantees that the memory is reclaimed. But, on the other hand, if an error occurs, the program will probably be left in an inconsistent state, to the point where it ought to be restarted; and once a process exists, all major operating systems will deallocate the process memory. (that is, leaks cannot last past the lifetime of the application leaking), so it’s questionable whether it is all that important. Also, all it really does is move the semantics; now instead of initializing and deallocating variables, you are initializating and deallocating class instances and calling members of those instances that correspond to the values you would have allocated as variables. Generally speaking, the concept is to manage the larger data structures in your application in a fashion that means destructors will deallocate it if anything goes wrong.

Garbage Collection

PCs have, for quite a number of years, had plenty of memory; even “low-end” machines like a Pentium 2 with 256MB of RAM don’t need to have program that use the absolute minimum amount of memory at all times; there is quite a bit of “leeway”. As a result, methods of trying to deal with the allocation and more specifically the deallocation of memory so that there is less worry on the programmers side as to whether they free’d a variable, should  free a variable, or may have forgotten to free a variable, as well as allowing a slight speedup from not forcibly deallocating everything at the first opportunity. The use of a “Garbage Collector” typifies the implementation of this sort of technique.

Contrary to what some might believe, Garbage Collection is not tied to your language; you can use a conservative Garbage Collector in a language like C or C++ if you wanted to. However, typically, there are two things people are arguing against when they argue against the use of a Garbage Collector:

  • the Microsoft .NET CLR (Common Language Runtime)
  • The Java Virtual Machine

Sometimes, they bring up the point to argue against any sort of language that doesn’t leave clean-up in the programmer’s hands, such as Python or even D. These are the two most common, though. Both of these employ a Garbage Collector for memory management. Neither has a clear way to explicitly deallocate a class instance you created; you generally just allow variables and instances to go out of scope and become inaccessible at which point the Garbage Collector will determine it can clear it and will do so.

The arguments “Against” garbage collection generally come in the form of something like “it makes programmers lazy” or “it’s not REAL programming” or “it’s slow/wasteful”.

All of these, however, are false. It doesn’t make programmer’s lazy, programmers are lazy by definition, that’s why we use functions and subroutines rather then duplicating that code all over; that’s why even in C and C++ design patterns have sprung up to make it easier to deal with manual memory management. Having to manage memory manually doesn’t mean a programmer is lazy; and anybody who thinks managing memory manually is somehow “better” is simply stubborn; especially since they are already using predefined routines for allocation and deallocation anyway (malloc()/free()) what they are usually arguing about is deterministic memory usage; with manual memory management (malloc/free) you can practically tell how much memory your program is using by simply keeping track of what you allocate and deallocate. With Garbage collection, you don’t actually deallocate anything, and when that memory is actually deallocated is not deterministic. This results in two things:

People using System.gc() to force the garbage collector to run, and people complaining about the “jumpy” nature that the allocated memory looks like in a graph. One should never run the garbage collector manually unless they have a good reason; running the garbage collector takes time, and that time is almost always better spent doing other things in your application. The Garbage collector will run on it’s own when needed. The second is overanalysis- the overall footprint of memory usage remains the same, the only thing that changes is how much of that memory is actively holding “active” data. eg. A game written in C++, assuming no memory leaks, might appear to only use more memory during some scenes or intense action, then quickly go back down after that scene is over. A Java or C# Game may instead appear to have it’s memory balloon and stay there for some time. This is simply because they are different; C++ programming typically employs the RAII pattern- (Resource Allocation Is Initialization)- which will result in unused memory instantly being deallocated/destroyed. C# and Java’s Managed memory model puts that task in the hands of the Garbage Collector, which cleans up in a generational fashion. Eventually, the memory is freed. The real question is, Do you really need that memory? Worst case scenario is it get’s swapped out due to other memory demands, but by that time the GC will have kicked in. And even if it does get swapped out, deallocation by the GC will not “touch” the page so it won’t actually need to be swapped back in to be deleted unless something needs to be read from it.

346 total views, no views today

Posted By: BC_Programming
Last Edit: 20 Jul 2012 @ 02:49 AM

EmailPermalinkComments (0)
Tags
Categories: Programming
 20 Jul 2012 @ 2:32 AM 

The next version of BASeBlock, which I have dubbed version 2.5 since that seems like a sensible update from 2.4- will use the .NET framework 4.0 and will be compiled with C# 4.0. Previously, all work was done in Visual Studio 2008, which of course doesn’t work with anything past Framework 4. After working in VS2010 some with BCDodger and starting to shift to it for general programming, I decided it was time to at the very least upgrade BASeBlock so I can enjoy the new features of VS2010. After doing so, I figured- in for a penny, in for a pound- and upgraded the targeted .NET framework to 4.0.

Some big advantages from this move, aside from having a few more language features at my disposal, include the DLR (Dynamic Language Runtime) which should allow the relatively easy addition of scripting capabilities much like I have for C# and VB.NET for languages like Python And Ruby. Another advantage that I wasn’t expecting was the improvements to the CLR which actually give the game another +20 frames per second on average just for the debug build.

Another nice thing is that this upgrade does not affect Mono compatibility- though it doesn’t work there because I use some windows specific platform/invoke in a few locations. Replacing those with appropriate platform specific equivalents as needed would fix those issues.

Open Sourcing

The idea for BASeBlock was to have it Open Source. The problem with that is that my connection is no longer uber awesome like it used to be, meaning that even uploading the binaries can take upwards of an hour. The source files would take significantly more time. THe Source for earlier versions is still available on the main downloads page entry for BASeBlock . When I get the ability to do so I will either upload the source separately or have it as part of the same installer package (optional feature).

The source will probably be licensed under the BSD license. Note however that this will only extend, at least for now, through the actual BASeBlock program. It uses a few satellite assemblies, such as “BASeCamp Update Library” Which will probably remain closed for the time being.

Currently, I am trying to get Polygon blocks working properly with the GameCharacter. Naturally, this is not that easy since a lot of the code with collision detection on the Gamecharacter is reliant on the fact that all blocks are rectangular. I have something that half-works so far, with a few errant issues that I need to fix; if I can’t I will simply revert it to the old detection and declare Polygon blocks and gamecharacters incompatible for the time being.

254 total views, no views today

Posted By: BC_Programming
Last Edit: 20 Jul 2012 @ 02:32 AM

EmailPermalinkComments Off
Tags
Categories: Programming

 Last 50 Posts
 Back
Change Theme...
  • Users » 856
  • Posts/Pages » 191
  • Comments » 67
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

PP



    No Child Pages.

Windows optimization tips



    No Child Pages.