Dancing With Hackers

Categories Computer Science, Game Engine, Gamedev, Hacking, Security0 Comments
[typed string0=”When I first got started with computers, Morocco was a land that had little legal shops for products…. hence hacking and cracking games/tv was justified ;)” typeSpeed=”40″ startDelay=”0″ backSpeed=”40″ backDelay=”500″]
It wasn’t long after when I reached my teen years, that my mind decided to overly develop my conscience. Slowly the shadow of guilt of breaking into people’s hardwork was keeping me awake (see pre18 work). I’m sure the game development documentaries shown on such epic and still running channels such as GameOne played a huge part in building empathy with my brethren in other continents (a sample; excuse the french 😉)

Respecting the Challenge

Having the experience of hacking games, gives not only a mindset but a respect for hackers that break into games. If we ignore the ethical impact it has on the industry, it seems that our species always keeps itself in check with a masochistic self destruction, greed or just social validation.

Whatever the case may be, when I approach securing my game, I make sure it is a multi-spell solution. A lot of hacking is about reversing the assembly code and tracing jump statements. “If-else” statements in code, directly translate to “jumps” (jmp command) in assembly.

Let’s look at an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Type your code here, or load an example.
int CheckProgramState()
{
    int countHacks = 0;
  
    // Test for count hacks here....
    countHacks += 12; // let's say we found hacks...
  
    if( !countHacks  ) // if '0' then hacks found
    {
      return 1;
    } 

  return 0;
}

so if “if-else” statements cause branching, hackers will start from the point where the program deteriorates or crashes and trace back to what caused that crash. In this minimalist example, at line 7  we observe the variable “countHacks” being populated by the value 12.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
CheckProgramState():
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 0
        add     DWORD PTR [rbp-4], 12
        cmp     DWORD PTR [rbp-4], 0
        jne     .L2
        mov     eax, 1
        jmp     .L3
.L2:
        mov     eax, 0
.L3:
        pop     rbp
        ret

In the assembly representation it’s in line 5. Now we know that, the key value which decides whether a program is hacked or not, “countHacks”, is stored in location (rbp-4) in the CheckProgramState() stack. With this information a hacker can overwrite that memory location during run time for a quick “patch” to circumvent our security checks.

Line 7 in the assembly code, with jne (Jump Not Equal or Jump Not Zero) uses the results in Line 6‘s cmp (compare). This is where our hacker will trace the decision point which we use to cause cascading degradation and eventual closure of the product.

Visualizing the Battle

Since we’re fighting a battle, it is most appropriate to map it:

The assembly code here is just a filler, the point is the code path we follow down after detecting that the product is “cracked”. The more complex these jumps, the harder it is for the hackers to undo our checks. Here’s a little animation, of a hacker’s reverse walk-through of our protection…

Of course this is the most basic form of protection, there are others like honeypot, salting, ciphers and self-policing daemons/brokers etc.. We want to overlay and make each protection inter-dependent. To hide when when we”detect” and where/when we start deteriorating the product. Ideally deterioration should be intertwined with the product’s core logic. So hackers don’t just have a single “patch” (as the “countHacks” variable) or even a few, but a multitude!

I know there are those that are against DRM and such, but just as hackers “enjoy” breaking into products, I enjoy making them dance before they get there….

You’re welcome 😉