Age of Empires 2 DE: Anti-Tampering Bypass

Recently a friend bought me his favorite 1999 title Age of Empires II which was remade (again), but this time much better as Definitive Edition. So far, it’s a really great game and adds a lot of quality of life fixes to the original in addition to a few civilizations.

But I’m not here to discuss the quality of the game. What I wanted to know was how hard it was to cheat in it. Yeah, that’s right I want cheat in a wholesome video game from 1999. It goes without saying the job search is not going very well and this how I spend some of my free time.

If you try to do static analysis on the aoe2de_s.exe binary that ships with the game you won’t have much luck since it uses a loader/un-packer like thing to load most of the game’s data files. I spent around 10 hours on-and-off trying to figure out how it worked, and while I got fairly far it’s a waste of time since using process-dump to dump it once it was loaded works fine.

Bypassing anti-tampering

The first thing you’ll notice when you attach a debugger to the game or modify code is a “tampering detected” message which disables all the game’s functionality and shows a popup. I found out how to bypass this fairly quickly by looking for the string IDS_TAMPERING_DETECTED_MESSAGE. I would like to say more about this, but if you look at this function call which I sort of guessed at showing the message you can disable the entire if-branch very easily

I found FUN_7ff6342aded0 (aoe2de_s.exe + 72ded0) is a thiscall which refers to a member variable offset 0x114 bytes from the vtable in ECX (a boolean). I couldn’t find the RTTI information for what I assumed was a class, though.

I also figured out what the DrawButton call was, but this was just through referencing the other strings in the function calls. When I made FUN_7ff6342aded0 return 0, I was allowed to tamper with the game by modifying code successfully. At least, it seems to be that easy. FUN_7ff6342aded0 is basically the tampering_flag function and gets called by all of the game’s anti-cheat mechanisms, but when you attach a debugger some popup continuously appears telling you “A running process” is interfering with the game. This is because the game does isDebuggerPresent checks and UnhandledException stuff to detect debuggers (some of which I am on my way to breaking but just haven’t tried modifying yet).

It doesn’t interfere with anything else as far as I know so you can still debug while using this bypass, but it would be nice to get rid of the pop-up which is something I’m working on. I believe we can bypass this by patching specific anti-debugging measures.

I’ve found the code that is hidden statically by exploring the callstack of tampering_flag calls which pops up an annoying pop-up if tampering_flag is set to 0. Maybe this call is triggered by a signature check on this function?

Conclusion

With this bypass we can modify any code section and get away with it AFAIK, and we didn’t just modify rendering code but the flag that gets set when the game is tampered with. All that is left to do is bypass debugger checks which should be trivial. I found a lot of Microsoft’s anti-debugging stuff can be found in this resource for anti-debugging, particularly the exception handling ones.

I learned a valuable lesson though–don’t make your life harder by trying to unpack a complex program if you don’t need to. Try what your intuition says could work first. The hardest part about finding a bypass like this is simply getting a dumped executable to run through static analysis on.

Back