Hacker
Professional
- Messages
- 1,041
- Reaction score
- 852
- Points
- 113
The content of the article
Descriptor protection by driver
Some anti-cheats use their own driver. It allows you to use a wider range of options to protect your application. The days of SSDT hooks are over due to the high likelihood of conflict with other software.
A special function for intercepting some system events has appeared in Windows - ObRegisterCallbacks. The anti-cheat driver trims the rights of the process handle by setting a callback to receive it. When trying to request full access to a protected game, the third ring application will only have access to general information about the process.
There are also in-game checks: the game itself can check whether individual variables or the code as a whole have been modified. A simple example: if there are more cartridges in a clip than the maximum number of cartridges in a clip, then something is wrong.
INFO
In the last article I talked about different types of cheats.
Types of protection against internal cheats
To bypass internal protection, you will have to reverse the code.
Protection: hook function LoadLibrary.
Workaround: ManualMapping.
ManualMappingIs the manual loading of the library into the process address space. It includes parsing headers, allocating memory, writing, manually importing libraries, and calling the library entry point. When executing ManualMapping, we completely simulate the function LoadLibrary, but do not leave information about the loaded library.
Protection: monitoring of active threads and tracing of library addresses.
Finding a thread that is not related to the game process, the anti-cheat tries to verify the digital signature of the library whose code is executing this thread. If this fails, the user is marked as a cheater.
Workaround: hooks and code caving.
Intercepting function calls allows us to embed our code into existing game functions. We don't need to have our own thread to invoke the cheat code. Sooner or later, the game itself will execute the foreign code, and the cheat will do its job.
Code cave is a piece of zeros in the application's memory that is never used by it at runtime. In this section, you can embed the cheat code. After checking if the code belongs to the game's address range, the anti-cheat will skip it.
Protection against external cheats
A driver is used to protect against external cheats.
Protection: monitoring known processes or monitoring all processes and searching for cheating programs by their signatures.
Workaround: obfuscation.
Obfuscation modifies, obfuscates, virtualizes code, alters signatures. Anti-cheat searches only for signatures it knows, and obfuscated versions of the code will be ignored.
INFO
Online games use SSL encryption or proprietary protocols to protect traffic, which can be difficult to reverse.
Anti-cheat from external cheats
Let's write a simple anti-cheat. It will be easy to get around because this is just an example. In reality, anti-cheats are complex applications that monitor many aspects of the system.
We will search for unsigned processes in the system - because cheats rarely sign - get their hashes and compare them with the hashes of known cheats. To search for processes, we will use Process, and for validation, a ready-made wrapper for a function WinVerifyTrustfrom wintrust.dll.
List of cheats known to us:
Let's write a simple function to select all unsigned processes from the system to which we have access.
The function of obtaining the SHA-256 hash of a file by its path:
We iterate over all the processes, get their hash, compare with the list of known cheats:
If the cheat is found, display the message on the screen.
For testing purposes, I created an empty application and listed its hash. We check the work of the anti-cheat.
Success: Cheat Process Found!
Supplementing anti-cheat with protection against internal cheats
To begin with, we will supplement our function for obtaining process paths with code that will also send a list of unsigned modules of our process for verification.
Now we write the previously returned set IEnumerable<string>to a variable prcsAndModules, adding all the unsigned modules of our process to it. Then we compile an empty library, which displays a message about its loading, and add its hash to the list of known cheats.
It is loaded at the anti-cheat entry point using LoadLibraryfrom kernel32.dll.
Success again!
The resulting anti-cheat will be able to find known copies of public cheats.
Welcome to RING 0!
Code privileges within Windows are controlled by the UAC system. The code is divided into rings of protection.
In Windows, only the drivers and the kernel of the system are executed in ring 0, which means that we need to load our driver.
Starting with Windows 7, Microsoft introduced driver signature verification. If you want your code in ring 0 - pay for the signature. This protects anti-cheats, but only partially.
Punching a window into kernel mode
Some cheaters have noticed that even signed drivers are vulnerable. Sometimes cheaters were able to access physical memory and execute code in kernel mode with a legitimate driver.
After that, the era of custom drivers and automatic ones ManualMapperfor them began. Some craftsmen made a handle spoofer that would steal a full access handle from a legitimate system process.
So you can turn the execution of any kernel mode function directly from user mode. The sequence of actions is simple.
INFO
A springboard is an assembler opcode that redirects execution.
Using this method, you can access the virtual memory of a process without having an open handle to it, using a read / write function MmCopyVirtualMemory.
Architecture as anti-cheat
Any code that runs on the client can be modified. Any code that can be ported to the server is best ported to the server.
Let's imagine a multiplayer game of tic-tac-toe. The game does not establish the order of who walks and how. The cheater can replace the data in the packet by telling the server that he played with a cross and won, although he played zero for the whole game. The server will trust the client, and the cheater will win.
To avoid this, the server must determine the order of moves, assign which client to move and by what, and independently decide which client wins.
Examples from the real world
You may be familiar with the Rust game. The player's movement speed and position are sent to the server. The cheat allows you to teleport or move very quickly.
In the CS:GO game, the architecture is thought out better. Only pressed buttons responsible for movement are sent to the server.
The forward movement in the squat will look like this:
Gravity and movement speed are calculated on the server to exclude the possibility of teleportation or changes in movement speed.
Cheating tactics for bad architecture games
Let's consider them using the Source Engine as an example.
Attack # 1: packet spam, or speedhacking. This tactic involves sending a large number of movement packets. This is how speedhack was implemented for CS 1.6 / CS: Source / TF2.
Security: counting packets sent by the client and tracking the sending interval. The fix has been added in newer versions of the Source Engine.
Attack # 2: packet invalidation is a tactic of changing packet parameters so that the server rejects the packet and does not process the tick for this client.
The SE cheats use a parameter tick_count. Its value is set to INT_MAX, forcing the server to ignore the packet, skip the gravity calculation, for example, leaving the player hanging in the air.
Defense: simulation of gravity, lives and other parameters of the player separately from receiving packages.
Attack # 3: packet choke, or lag switch. It delays packets and simultaneously sends them after a certain interval. Causes jerky movement within the game or, in some cases, even teleportation across the entire map.
Protection: introduce a system of reporting and recording games.
Finding a vulnerability is difficult, but fixing it is sometimes too easy. The only problem is the laziness of the developers.
Conclusion
Our little excursion into the world of cheats and the fight against them has come to an end. I hope you learned something new for yourself! Now you at least know what to look for if you want to create a defense for your game or touch someone else's. In the second case, I recommend that you be careful and remember to stay within the legal framework. If you want to dive deeper into the topic, I can recommend the UnKnoWnCheaTs cheater forum.
- Descriptor protection by driver
- Types of protection against internal cheats
- Protection against external cheats
- Anti-cheat from external cheats
- Supplementing anti-cheat with protection against internal cheats
- Welcome to RING 0!
- Punching a window into kernel mode
- Architecture as anti-cheat
- Examples from the real world
- Cheating tactics for bad architecture games
- Conclusion
Descriptor protection by driver
Some anti-cheats use their own driver. It allows you to use a wider range of options to protect your application. The days of SSDT hooks are over due to the high likelihood of conflict with other software.
A special function for intercepting some system events has appeared in Windows - ObRegisterCallbacks. The anti-cheat driver trims the rights of the process handle by setting a callback to receive it. When trying to request full access to a protected game, the third ring application will only have access to general information about the process.
There are also in-game checks: the game itself can check whether individual variables or the code as a whole have been modified. A simple example: if there are more cartridges in a clip than the maximum number of cartridges in a clip, then something is wrong.
INFO
In the last article I talked about different types of cheats.
Types of protection against internal cheats
To bypass internal protection, you will have to reverse the code.
Protection: hook function LoadLibrary.
Workaround: ManualMapping.
ManualMappingIs the manual loading of the library into the process address space. It includes parsing headers, allocating memory, writing, manually importing libraries, and calling the library entry point. When executing ManualMapping, we completely simulate the function LoadLibrary, but do not leave information about the loaded library.
Protection: monitoring of active threads and tracing of library addresses.
Finding a thread that is not related to the game process, the anti-cheat tries to verify the digital signature of the library whose code is executing this thread. If this fails, the user is marked as a cheater.
Workaround: hooks and code caving.
Intercepting function calls allows us to embed our code into existing game functions. We don't need to have our own thread to invoke the cheat code. Sooner or later, the game itself will execute the foreign code, and the cheat will do its job.
Code cave is a piece of zeros in the application's memory that is never used by it at runtime. In this section, you can embed the cheat code. After checking if the code belongs to the game's address range, the anti-cheat will skip it.
Protection against external cheats
A driver is used to protect against external cheats.
Protection: monitoring known processes or monitoring all processes and searching for cheating programs by their signatures.
Workaround: obfuscation.
Obfuscation modifies, obfuscates, virtualizes code, alters signatures. Anti-cheat searches only for signatures it knows, and obfuscated versions of the code will be ignored.
INFO
Online games use SSL encryption or proprietary protocols to protect traffic, which can be difficult to reverse.
Anti-cheat from external cheats
Let's write a simple anti-cheat. It will be easy to get around because this is just an example. In reality, anti-cheats are complex applications that monitor many aspects of the system.
We will search for unsigned processes in the system - because cheats rarely sign - get their hashes and compare them with the hashes of known cheats. To search for processes, we will use Process, and for validation, a ready-made wrapper for a function WinVerifyTrustfrom wintrust.dll.
List of cheats known to us:
Code:
private static readonly string[] CheatHashes =
{
"30BD612FF7FF2D809255364F04B6A9361061BA4E3AA46CD99FDF1FEF0DA04CC0"
};
Let's write a simple function to select all unsigned processes from the system to which we have access.
Code:
private static IEnumerable<string> FindNotSignedProcesses()
{
return Process.GetProcesses()
.Where(prc =>
{
try
{
return !AuthenticodeTools.IsTrusted(prc.MainModule.FileName);
}
catch
{
return false;
}
})
.Select(x => x.MainModule.FileName)
.Distinct();
}
The function of obtaining the SHA-256 hash of a file by its path:
Code:
public static string GetChecksumBuffered(string path)
{
var stream = File.OpenRead(path);
using (var bufferedStream = new BufferedStream(stream, 1024 * 32))
{
var sha = new SHA256Managed();
var checksum = sha.ComputeHash(bufferedStream);
stream.Close();
return BitConverter.ToString(checksum).Replace("-", string.Empty);
}
}
We create a function and look for all processes:
public static void DoWork()
{
Console.WriteLine("Searching for not signed processes..\n");
var prcs = FindNotSignedProcesses ();
We iterate over all the processes, get their hash, compare with the list of known cheats:
Code:
foreach (var process in prcs)
{
Console.WriteLine($"CHECKING: {Path.GetFileName(process)}");
var hash = GetChecksumBuffered(process);
if (CheatHashes.Contains(hash))
{
Console.WriteLine("\nCHEAT DETECTED!");
}
}
}
If the cheat is found, display the message on the screen.
For testing purposes, I created an empty application and listed its hash. We check the work of the anti-cheat.
Success: Cheat Process Found!
Supplementing anti-cheat with protection against internal cheats
To begin with, we will supplement our function for obtaining process paths with code that will also send a list of unsigned modules of our process for verification.
Code:
private static IEnumerable<string> FindNotSignedProcessesAndModules()
{
/ * <old code> * /
var modules = Process.GetCurrentProcess().Modules;
foreach (ProcessModule module in modules)
{
var fn = module.FileName;
if (AuthenticodeTools.IsTrusted(fn))
{
continue;
}
prcsAndModules.Add(fn);
}
return prcsAndModules;
}
Now we write the previously returned set IEnumerable<string>to a variable prcsAndModules, adding all the unsigned modules of our process to it. Then we compile an empty library, which displays a message about its loading, and add its hash to the list of known cheats.
It is loaded at the anti-cheat entry point using LoadLibraryfrom kernel32.dll.
Success again!
The resulting anti-cheat will be able to find known copies of public cheats.
Welcome to RING 0!
Code privileges within Windows are controlled by the UAC system. The code is divided into rings of protection.
- Ring 0 (kernel mode) - supervisor mode, or mode with maximum access to everything and everything up to physical memory. Having achieved the ability to execute his code in ring 0, the cheater can access the game memory without restrictions.
- Ring 3 (user mode) - the ring in which applications are launched. They have a minimal set of rights.
In Windows, only the drivers and the kernel of the system are executed in ring 0, which means that we need to load our driver.
Starting with Windows 7, Microsoft introduced driver signature verification. If you want your code in ring 0 - pay for the signature. This protects anti-cheats, but only partially.
Punching a window into kernel mode
Some cheaters have noticed that even signed drivers are vulnerable. Sometimes cheaters were able to access physical memory and execute code in kernel mode with a legitimate driver.
After that, the era of custom drivers and automatic ones ManualMapperfor them began. Some craftsmen made a handle spoofer that would steal a full access handle from a legitimate system process.
So you can turn the execution of any kernel mode function directly from user mode. The sequence of actions is simple.
- A vulnerable driver is being loaded.
- The address of a very rarely used function, accessible from user mode, but calling a function is found kernelmode.
- The useless kernel function code is saved and replaced with code that will redirect us to the function we need.
- The function is called usermode, redirected to kernel mode.
- Because of the trampoline, execution is redirected to the function we need, it receives all the arguments.
- The memory of the function is kernelmoderestored, the springboard is deleted.
INFO
A springboard is an assembler opcode that redirects execution.
Using this method, you can access the virtual memory of a process without having an open handle to it, using a read / write function MmCopyVirtualMemory.
Architecture as anti-cheat
Any code that runs on the client can be modified. Any code that can be ported to the server is best ported to the server.
Let's imagine a multiplayer game of tic-tac-toe. The game does not establish the order of who walks and how. The cheater can replace the data in the packet by telling the server that he played with a cross and won, although he played zero for the whole game. The server will trust the client, and the cheater will win.
To avoid this, the server must determine the order of moves, assign which client to move and by what, and independently decide which client wins.
Examples from the real world
You may be familiar with the Rust game. The player's movement speed and position are sent to the server. The cheat allows you to teleport or move very quickly.
In the CS:GO game, the architecture is thought out better. Only pressed buttons responsible for movement are sent to the server.
The forward movement in the squat will look like this:
Code:
cmd->buttons = IN_FORWARD | IN_DUCK;
Gravity and movement speed are calculated on the server to exclude the possibility of teleportation or changes in movement speed.
Cheating tactics for bad architecture games
Let's consider them using the Source Engine as an example.
Attack # 1: packet spam, or speedhacking. This tactic involves sending a large number of movement packets. This is how speedhack was implemented for CS 1.6 / CS: Source / TF2.
Security: counting packets sent by the client and tracking the sending interval. The fix has been added in newer versions of the Source Engine.
Attack # 2: packet invalidation is a tactic of changing packet parameters so that the server rejects the packet and does not process the tick for this client.
The SE cheats use a parameter tick_count. Its value is set to INT_MAX, forcing the server to ignore the packet, skip the gravity calculation, for example, leaving the player hanging in the air.
Defense: simulation of gravity, lives and other parameters of the player separately from receiving packages.
Attack # 3: packet choke, or lag switch. It delays packets and simultaneously sends them after a certain interval. Causes jerky movement within the game or, in some cases, even teleportation across the entire map.
Protection: introduce a system of reporting and recording games.
Finding a vulnerability is difficult, but fixing it is sometimes too easy. The only problem is the laziness of the developers.
Conclusion
Our little excursion into the world of cheats and the fight against them has come to an end. I hope you learned something new for yourself! Now you at least know what to look for if you want to create a defense for your game or touch someone else's. In the second case, I recommend that you be careful and remember to stay within the legal framework. If you want to dive deeper into the topic, I can recommend the UnKnoWnCheaTs cheater forum.