And fundamentally, the anti-cheat software is fighting a loosing game because of some quirks of x86:
- hardware breakpoints on memory latch to logical, not physical addresses
- one can map the same area of physical memory to different logical addresses thus allowing arbitrary memory reads
- simulating inputs through the PnP stack can be made indetectible with polymorphic code doing the injections
- detecting the aimbot's core code can be prevented via at least two methods: triggering (and capturing) page faults on memory hosting the bot or, again, with polymorphic code generation
One could create a fully open source cheat engine relying on memory reads and input injection via the pnp stavk and it would be undetectable deterministically (with heuristics, sure).
Games - unless streamed - need to know a bit more about the world they display than the player is allowed to see. Some engines I analysed (years ago) tried to limit propagating data to the local client to only a portion of the map and close proximity (the more recent battlefield games, if memory serves), while lots still have all enemy coordinates at all times in memory, some even with debug symbols to help the poor aimbot community reverse memory structures that more easily.
Its hopeless. The only winning move is not to play :-)
I suppose the memory being mapped twice could be detected by anti-cheat though. You can then also make more mitigations to prevent detection of the mapping (e.g. hooking the syscall to check the active mappings), but it’s always a cat and mouse game.
You are right on the first point, but I don't think you are right on the syscall part - a kernel level module can just read the PT directly without resorting to a syscall, no? You get access to CR3, and besides kernel-level PTs have a fixed logical (and if memory serves, physical - though maybe just on windows) address.
When in the non-PAE mode, I think one can still practically trigger page faults on attempted reads on the PDEs mapped by a kernel-level aimbot, force flushing of TLBs when anti-cheat tries to read the PT, and effectively conceal the cloning (although if the anti-cheat is doing this often enough, the performance impact might be too much?).
When in PAE mode, I do not know of a practical way to do it, but I haven't been researching such exploits for a few years now.
I think at this point, the most practical way to implement an open-source, undetectable aimbot proof-of-concept would be to perform static reversing of the game engine to get the network protocol, peform a MITM to listen in and recreate state on a separate process or machine, do a PnP input injection via a real or fake mouse/keyboard.
Reversing the code (as opposed to memory structures) is very hard these days, though, and not because of anti-cheat software, but because of the high-end anti-piracy runtimes and layers upon layers of abstractions which are annoying to analyze in assembly. (But sure, not impossible, and I am sure people are doing this considering the crazy amounts people are willing to pay for private aimbots).
For a system programming geek its all very interesting and intellectually stimulating, but boy does it ruin the fun of multiplayer gaming :-( I think the best way to protect against cheaters would be to run streaming-only servers where all the processing happens server-side.
- hardware breakpoints on memory latch to logical, not physical addresses - one can map the same area of physical memory to different logical addresses thus allowing arbitrary memory reads - simulating inputs through the PnP stack can be made indetectible with polymorphic code doing the injections - detecting the aimbot's core code can be prevented via at least two methods: triggering (and capturing) page faults on memory hosting the bot or, again, with polymorphic code generation
One could create a fully open source cheat engine relying on memory reads and input injection via the pnp stavk and it would be undetectable deterministically (with heuristics, sure).
Games - unless streamed - need to know a bit more about the world they display than the player is allowed to see. Some engines I analysed (years ago) tried to limit propagating data to the local client to only a portion of the map and close proximity (the more recent battlefield games, if memory serves), while lots still have all enemy coordinates at all times in memory, some even with debug symbols to help the poor aimbot community reverse memory structures that more easily.
Its hopeless. The only winning move is not to play :-)