Online game file check for tampering and up to date

Started by
51 comments, last by hplus0603 12 years, 3 months ago

You are not the first GDNet'er to go down this particular rabbit hole, by the way. Ysaneya beat you to it by 6 years, and the debate there would be well worth your time to read.

[quote name='wodinoneeye' timestamp='1328304241' post='4909320']
How many ordinary users know how to set those things up let alone make them work in an automated fashion for even the simplest parts of my solution (changing things frequently enough that the hackers have to constantly rebuild their hack mechanisms)

You are suggesting that your software will download a small module each time, and this module will perform the checks and authenticate the results with the server, right? That way you can change the module regularly, to outdate older hacks.

So my hack would also download the module, and run it, just like your software does, and let it authenticate with your server. How will that work with a patched executable? Because I will be running your module in a sandbox, and giving it the original executable to work with, instead of my patched one.

This method of hacking is completely impossible to defend against (well, excepting TPM, but nobody wants that), because it works by showing the security/DRM checker exactly what it wants to see - and there is no way to detect this kind of spoofing (again, except for TPM).
[/quote]

Yes one or more modules (binary code snippets) would get downloaded via the normal message transfer between server and client, would insert into the game executable and be run as part of the clients packet decryption scheme (actually I would see a window FIFO buffer list of these modules and the window would slide over as new modules are added/confirmed - but thats to cover the chicken/egg issue and also makes it a little more complex/obscufated - different packets call for use of packet selected modules or even cascade thru more than one)

Those encryption modules when executing reference bytes (via offsets) of the actual FULL game executable binary (not just the small encryption modules) as a cypher -- so they cannot run outside independantly without being mutated to fulfill the same functionality/results.
.
I have already figured in that your hack would attempt to use a reference image ('pristine') it maintains in sync -- of course the hack would now have to activate thru that image in order to execute the EXACT encryption scheme (your hack has to how to get in and out of this while executing - the cypher would be wrong now in this case). You HAD to change some of the adjacent code somehow to implement any hack functionality (ie - code to pull out the decrypted inbound packets and later insert outbound ones).

OR
You are running your Sandbox image with those new modules MUTATED to carry out those bothersome executable cypher fetches and the exactly the original algorithm (your solution needs to mutated its code to indirectly fetch EXACTLY the required cypher data from your pristine client image. CAN you make a PROGRAM that reengineers those modules ???

Like I said -- several components all have to work in concert for the whole to function securely and that includes measures that make 'sandbox' execution extrememly difficult. The server side that parallels all this can have whatever code solution it needs for the new modules to encrpt/decrypt there (part of the rebuilding there builds it to match correctly but only sends the client part to the client (and to your hack will get).

So you cannot just run the sent code snippets directly in your sandbox without changing them to run outside their intended context - they continually check that context in scrambled ways (any hack PROGRAM has to deal with lots of new variants constantly) . You HAVE TO programatically auto-mutate them and THAT is what Im betting on cannot be done by a program -- could be done manually by hand (the constant changing modules keep the scheme well ahead of that - it has to be done in a timely fashion).

The reengineering process -- disassemble, figure out EXACTLY what the code does, rebuilt it to work outside of context (emulate the cypher fetches which are random per packet), each module WOULD have different algorythms of how it mutates that key data. The rebuilt (hacked) code has to be inserted back into its place (the same binary slot - same size of code -- BTW I would pack the snippets into the module buffer - and THEY lots of mem space offsets built into it to foil your attempts to reengineer/rebuild)

I think I mentioned these modules are changed on-the-fly not just once on startup for the full solution. Even if its locked in and only changed with a executable DL once each time the game is played it would still be still designed with many countermeasures to prevent them running in a sandbox without your hack being required to be reengineered&rebuilt.

Another test is the server would expect an immediate response validation once the new module installation is achieved and if this takes too long (your whole hack rebuild/restart will take some time) the server can detect THAT and if it happens too often your user is put on an 'investigate for hack' list for human investigation.

Im not saying this whole scheme (or parts of it) doesnt require some clever programming and some added overhead on client and server.
Having the server side component match the functionality of the client (using a per client unique client executable as its cypher) adds to server side complexity.

And as I said before some existing or future OS might make the tricks that would need to be done impossible (ie - segment rwx permisssions).

------------------------------------------------------------------------------

OK assume we ONLY do some simplest countermeasures - daily rebuild of the client -- that client has the critical internal workings forced in different positions in the binary each rebuild and some of the encrypt/decrypt modules are programatically mutated/substituted each day. It should (of course) be built with minimum clues inside the binary itself. The client binary will now change frequently as run on the players machine. What does your hack rig have to do to try to realign itself and function when the client program binary changes like this ??? Can it do it ALL programatically (hands off) - 'automagically'???

Do you think an 'automagical' solution -- selfinstall/autorun -- can be created for brainless script kiddees thats it is NOT too much a 'complex rig' for them ??

Even YOU providing a 'hack of the day' DL: to match the ever changing client binaries adds extra work for any other cheaters you distribute a solution to.

Cutting out 99+% of the cheaters - isnt that a pretty good partial solution ???
--------------------------------------------[size="1"]Ratings are Opinion, not Fact
Advertisement

So you cannot just run the sent code snippets directly in your sandbox without changing them to run outside their intended context - they continually check that context in scrambled ways (any hack PROGRAM has to deal with lots of new variants constantly).

Think about what 'intended context' actually means: it means that the program's address space must contain the correct data at correct offsets, and any files on the hard drive must have the correct name and contents.

How do we make sure that the sandbox's address space holds the correct data/offsets? We load a vanilla (unpatched) copy of the program into it. How do we make sure the files have the right names/contents? We hook the low-level file API to return the original (unpatched) data files.

So as far as all your modules are concerned, they *are* running in their intended context. They never see the patches and hack mechanisms, because those are all in the address space of the patched executable, rather than the vanilla copy in the sandbox.

Unless you have a TPM to guarantee that your program is the only such code executing on the system, there is no way to ensure that you aren't being sandboxed.



OK assume we ONLY do some simplest countermeasures - daily rebuild of the client -- that client has the critical internal workings forced in different positions in the binary each rebuild and some of the encrypt/decrypt modules are programatically mutated/substituted each day.

This might be a much more effective solution (provided you completely change your network protocols every time). However, it's also a maintenance, QA and financial nightmare - you make your users download a multi-megabyte executable every day, you risk introducing subtle bugs in each rebuild, and you need to dedicate significant manpower to scrambling your executable in imaginative ways (if you are scrambling automatically, much easier to automatically account for).

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Yes one or more modules (binary code snippets) would get downloaded via the normal message transfer between server and client, would insert into the game executable and be run as part of the clients packet decryption scheme (actually I would see a window FIFO buffer list of these modules and the window would slide over as new modules are added/confirmed - but thats to cover the chicken/egg issue and also makes it a little more complex/obscufated - different packets call for use of packet selected modules or even cascade thru more than one)[/quote]

There are two problems with this approach:
- having code like that would make every malware scanner on the planet light up like a christmas tree
- how do you do QA? Adding dynamic checksum is tricky enough, modifying raw binaries is just suicide.

As for defeating such a system, it's somewhat trivial.

Intercept code loading mechanism and inject memory access hooks. To keep QA managable, these modules will need to be based on some abstractions. Patching assembly directly, especially on a daily basis is suicide. These checks will also be auto-generated, unless you want to have a human in charge, greatly increasing risk of failure, so there will be abstractions and simplifications.

Once patched, make a diff between clean and modified image. At best, it will be a few bytes. Injecting code only requires patching some jump, after which I'm free to roam around a DLL or arbitrary code, something such code in unaware of.

If memory access hooks run across this patched section, they feed in correct bytes.

Another way, via sandboxing/VM or some other, perhaps memory page hook (trickier) trick doesn't require injecting anything. To mask patched bytes, I monitor read access to that part of memory. When it happens, I perform a check of IP register. If that IP is close to that of patch, then the code is being executed. If it's not, it's the DRM and I feed it correct bytes. This might be doable via debugger techniques, but I'm not sure of the performance impact.

-----

But here's an important question. The above would give me several hours of entertainment. How many hours would your game provide? Is there even incentive for me to crack it?


[quote name='wodinoneeye' timestamp='1328358903' post='4909495']
So you cannot just run the sent code snippets directly in your sandbox without changing them to run outside their intended context - they continually check that context in scrambled ways (any hack PROGRAM has to deal with lots of new variants constantly).


Think about what 'intended context' actually means: it means that the program's address space must contain the correct data at correct offsets, and any files on the hard drive must have the correct name and contents.
How do we make sure that the sandbox's address space holds the correct data/offsets? We load a vanilla (unpatched) copy of the program into it. How do we make sure the files have the right names/contents? We hook the low-level file API to return the original (unpatched) data files.
So as far as all your modules are concerned, they *are* running in their intended context. They never see the patches and hack mechanisms, because those are all in the address space of the patched executable, rather than the vanilla copy in the sandbox.
Unless you have a TPM to guarantee that your program is the only such code executing on the system, there is no way to ensure that you aren't being sandboxed.
[/quote]

"We load a vanilla (unpatched) copy of the program into it"

where you insert and execute the new snippets so they can carry out the same operations on the same data (cypher of very same exe binary)

Except that binary is a running entity and you have to tap into it to extract the DECODED packets now in memory buffers -- to do something with the data and create your modified outbound packets which will be injected into the sandbox's outbuffers to be re-ENCODED properly. While it is executing those very same snippets can be checking every single byte (or rather a random sampling) of the executable segments in memory and forwarding them to the server..

How are you going to hide you taps into that program ?? You will have to have them somewhere inserted into that 'sandbox' binary.

The sampling checks send their results back to the server for validation against ITS cypher image and it will eventually turn up any differences.

Thats what I meant by 'intended context' -- the executable binary itself is part of that checked context and if any part of it changes or shifts in position BOOM!!


Some of those snippets may echo a response immediately back to the server. I would assume your sandbox rig will stop outgoing packets because you want to modify them and replace them with your own (probably back thru those snippets that do both DECODEING and ENCODING in constantly changing ways. With the snippets constantly changing in your sandbox do you know which packets to block and which to let thru ??
If it was all static the expert hacker could figure it out and build a static hack for it. But can an automated hacking program do that ??


Maybe you can tell me that when a program runs its memory space s get scrambled and my testing offsets wont work (binary executable segments I thought are locked down in their relative content and tests of exact offsets (byte contents) in those segments should be recreateable.



I still think my strongest argument is that you wont be able to automate your hacking system to adapt to constant changes in the game executable.
--------------------------------------------[size="1"]Ratings are Opinion, not Fact

I still think my strongest argument is that you wont be able to automate your hacking system to adapt to constant changes in the game executable.


mprotect().

I will patch the executable, then watch access to memory pages. When I detect a read, I'll attempt to determine whether it's legitimate code or DRM, perhaps by examining the stack traces of active threads or thread that triggered the fault. Depending on that, I'll feed either patched or original image.

It's not trivial, but it is transparent and oblivious to changes in DRM.

Methods like this are not necessarily trivial, nor will I claim it's a 5 minute solution. It merely serves to show that anything clientside can be defeated.

Such method doesn't cover anything, it cannot cover for certain types of changes, but it will render external validation universally useless.

How are you going to hide you taps into that program ?? You will have to have them somewhere inserted into that 'sandbox' binary.[/quote]

All I need is a single jmp instruction to be inserted somewhere by overwriting code at that position (moving rewritten parts at jmp address). Such insertion is hidden by method noted above, meaning the DRM process will not know a change was made and process image will appear intact.


Which brings us back at the beginning. Instead of spending so much time trying to make sure client is intact, just validate the *results* of client on server. Then instead of worrying about how client did something, you measure whether they are misbehaving. Of course, mismatched results could be caused by flaky hardware or other bugs.


[quote name='wodinoneeye' timestamp='1328358903' post='4909495']
OK assume we ONLY do some simplest countermeasures - daily rebuild of the client -- that client has the critical internal workings forced in different positions in the binary each rebuild and some of the encrypt/decrypt modules are programatically mutated/substituted each day.


This might be a much more effective solution (provided you completely change your network protocols every time). However, it's also a maintenance, QA and financial nightmare - you make your users download a multi-megabyte executable every day, you risk introducing subtle bugs in each rebuild, and you need to dedicate significant manpower to scrambling your executable in imaginative ways (if you are scrambling automatically, much easier to automatically account for).
[/quote]

I did say it would take some clever programming (which includes code that actually works consistantly)

Break it down into components (divide and conquer...)

A substitution system (lets assume daily and not on-the-fly over-the-network snippets)

- How about an ordinal driven jump table to packet/message handlers that gets replaced. (a table driven msg dispatch that can have the indexes randomized). This might even be able to be done without rebuild (patch the binary substituting just the fixed sized table via a hex editor)

- How about some imbedded cypher keys to make the raw packets pretty much scrambled (simple constant substitution in built code)

- How about a makefile rebuilder that changes the build order of code routines - that have no build order dependancies ( to rearrange binary ordering within segments (and maybe the segments themsellves ----- loader ordering Im not sure of)

Obviosusly scrubbing any subroutine names and other useful clues from the binaries (that might give an autohack reference point to make use of)

- Extras (more Dev+QA work) have a rotating set of static packet encryption/decryption routines that can be substitured in any build (server will already have the complementary set - all of them) . Session establishes which set is used by the version (which only sticks around for about a day)

Over time additional coding modules can be added (recombination of coding sub-functions and QA can largely be be automated)
This requires server executeable rebuild (or partial rebuild -- maybe only a DLL)


If the build for the one client binary can be automated and more than a little confidence in the whole mechanism can be gotten (verification of the whole mechanism can be automated before going out to users).

As additional daily executables are build and proven, nothing says they cannot be reused periodicly -- can the hacker figure it out and make his autohack switch to an old hack it had previously seen/done??? The server might send different binaries from this set to different users so that the 'hack' done by an expert (possibly by hand now since its 'daily') wont nessessarily work for a scriptkiddee using his 'hack of the day'


Do these things mostly sound too hard or risky or even that complicated buildwise to implement??

Would they change things enough to make it too hard to autohack??




All this for a lousy game.... Maybe I need to think of some other more 'high value' use for such security measures who could probably afford your TPM solution anyway.
--------------------------------------------[size="1"]Ratings are Opinion, not Fact
Would they change things enough to make it too hard to autohack??[/quote]

They wouldn't detect the hack. They would always work perfectly and see the image is pristine and unchanged. Add tons of layers, checks, use 4 cores to hammer the image - image hasn't changed. Yet, the attacker is happily forcing modified code to execute.


NaCL uses these observations as basis of formal proof of safety of its sandbox:
- any executable code is parsed and all jumps are bounds-checked
- after code is loaded, it can no longer be modified
These two fairly simple techniques prevent attack outlined above.


Inside a sandbox, these two are sufficient guarantee that third-party attacker cannot do anything malicious, assuming integrity of sandbox hasn't been compromised.

In a compromised sandbox, above rules aren't meaningful anymore. Chrome via NaCL plugin is safe for usual case, where client machine hasn't been compromised and ensures that sanboxed code cannot behave unexpectedly or compromise the sandbox itself. It does not guarantee sandbox integrity, but as repeatedly said, if host machine was compromised, all bets are off.
But here's an important question. The above would give me several hours of entertainment. How many hours would your game provide? Is there even incentive for me to crack it?


The whole reason for this is to block cheaters of Multiplayer games and people obviously cheat or the subject would be moot (maybe there are others who cheat leaderboards on solo games too)

They (experts) also get ego trips hacking in cheats and distributing it to people they think they impress (script kidees) thus multiplying the number of cheaters --- who somehow get an ego trip for 'breaking the system' or someother way they delude themselves into thinking they are better than someone else by cheating or being known to cheat..
--------------------------------------------[size="1"]Ratings are Opinion, not Fact
[quote name='wodinoneeye' timestamp='1328460951' post='4909856'] I still think my strongest argument is that you wont be able to automate your hacking system to adapt to constant changes in the game executable.
mprotect(). I will patch the executable, then watch access to memory pages. When I detect a read, I'll attempt to determine whether it's legitimate code or DRM, perhaps by examining the stack traces of active threads or thread that triggered the fault. Depending on that, I'll feed either patched or original image. It's not trivial, but it is transparent and oblivious to changes in DRM. Methods like this are not necessarily trivial, nor will I claim it's a 5 minute solution. It merely serves to show that anything clientside can be defeated. Such method doesn't cover anything, it cannot cover for certain types of changes, but it will render external validation universally useless.
How are you going to hide you taps into that program ?? You will have to have them somewhere inserted into that 'sandbox' binary.[/quote] All I need is a single jmp instruction to be inserted somewhere by overwriting code at that position (moving rewritten parts at jmp address). Such insertion is hidden by method noted above, meaning the DRM process will not know a change was made and process image will appear intact. Which brings us back at the beginning. Instead of spending so much time trying to make sure client is intact, just validate the *results* of client on server. Then instead of worrying about how client did something, you measure whether they are misbehaving. Of course, mismatched results could be caused by flaky hardware or other bugs. [/quote]


What kind of knowhow is needed for something like this (I assume the tools are avaiable but they require alot of knowledge to use them sometimes)

Again can this be ALL automated with a download/install and run auto-magically for a mind numbed script kiddee (or others even lower on the food chain) ???

If it cannot (or takes WAY too much effort to manage), the effect will be to eliminate the majority of the cheaters.
--------------------------------------------[size="1"]Ratings are Opinion, not Fact


Again can this be ALL automated with a download/install and run auto-magically for a mind numbed script kiddee (or others even lower on the food chain) ???


Of course, same as any other patch. Write once, run anywhere. Cheater downloads a patch/trainer and that's it.

General idea behind the technique is how to avoid integrity checks, just like how to bypass int 3 blocks or similar.

The rest, actual hack, depends on what you want to do, which is no different from the way hacks work these days. But seeing crackers break through all DRM, even polymorphic versions sometimes even before the official version is available, I don't see any of the above as particularly "complicated". I don't even remotely follow the field on such kinds of exploits, so it's likely there are much simpler or more effective methods.

This topic is closed to new replies.

Advertisement