Introduction
In the rapidly evolving landscape of online gaming, the integrity of game environments is paramount. Easy Anti-Cheat (EAC), developed by EOS, stands as a formidable bulwark against the myriad of exploits and cheats that threaten this integrity. This technical write-up delves deep into the inner workings of EAC, particularly focusing on its sophisticated module streaming mechanism and how I was able to reverse engineering EAC's stream buffer, eventually engineering a tool to do it for me.
Understanding EAC's Driver Streaming
This study primarily centers on the game Rust, yet the underlying concepts are likely relevant to other contemporary games.
First, let's delve into the methodology behind EAC's process of writing its driver onto the disk. This can occur through one of two possible avenues: the driver might be embedded within EAC's Bootstrapper, or alternatively, it might be delivered through streaming.
To determine which approach is used, we can block EAC's internet access and observe the results.
When launching an EAC-protected title without internet access, we can observe that EAC is unable to create the driver on disk, indicating to us that the driver is indeed streamed.
Writing the Driver to Disk
Now with this information that the driver is indeed streamed, our next step is to understand how exactly EAC streams the driver.
We begin by identifying the process responsible for writing the driver to disk, using a tool like Process Monitor to monitor process operations.
As you can see, EAC's driver is written to disk from EasyAntiCheat_EOS.exe+0x1b255
.
Illustration #1 - Writing Driver to Disk
Although this routine is extensive, it includes the creation and writing of EasyAntiCheat_EOS.sys
from a buffer, as illustrated below:
...
HANDLE fdriver = CreateFileW(path, 0x40000000, 0, 0, 2, 0x80, 0);
if (fdriver != INVALID_HANDLE_VALUE) {
SIZE_T bytes = 0;
// WRITE DRIVER DATA
WriteFile(fdriver, g_Buffer->data, g_Buffer->size, &bytes, 0);
// CLOSE HANDLE
CloseHandle(fdriver);
} else ThrowError("CreateFile failed with %i.", GetLastError());
...
Reversing EAC's Stream Buffer and Decoding
Now that we know where the file gets written, it's time to see where the buffer comes from.
g_Buffer
is what gets written to the disk by EasyAntiCheat_EOS.exe+0x1b255
.
The caller of this function is another routine that looks like a ServiceHandler, which we will call SvcMain
.
Within SvcMain
we can see where g_Buffer
points to:
...
g_Buffer = (StreamBuffer_t*)CreateFileMappingW(
GetCurrentProcess(),
&map_attributes,
4,
0,
0x2000000,
L"Global\\EasyAntiCheat_EOSBin"
);
...
Now, we can assume that the StreamBuffer structure looks something similar to the following:
typedef struct {
uint32_t unk0;
uint32_t unk1;
uint32_t unk2;
uint32_t unk3;
uint32_t process_id;
uint32_t unk4;
uint32_t data_size;
uint8_t data[1];
} StreamBuffer_t;
Right before the data gets written to the file, we can see some sort of decoding of data.
// all very simplified
uint8_t* block = g_DriverBuffer->data;
block[size - 1] += 3 - 3 * size;
size_t i = size - 2;
do {
block[i] +- -3 * i - block[i + 1];
} while (--i > 0);
block[0 -= block[1];
Developing a Tool to Extract the Driver
Armed with the insights we've gathered, it's time to develop a tool to harness this information. I will be using C as my programming language.
First, let's brainstorm on how we are going to extract the driver. Knowing that Rust.exe
will write the encoded data to a mapping called Global\\EasyAntiCheat_EOSBin
,
we'll try to hook the NT API ZwMapViewOfSection.
I used the MinHook hooking library for my example.
Additionally, in my proof-of-concept, I create a thread, section_watcher
, that calculates each map's checksum and comparing it with the old one to see if the map was modified.
To prevent the dumping of every mapping, I added a check to only whitelist dumps if they contain a PE header. I do this by checking if the first two bytes of decoded data are 'MZ'.
Notes
A finished proof-of-concept may be found on this project's repository, here.
This project offered me valuable insights into the workings of anti-cheat mechanisms, enabling the development of tools such as an EAC update detector that can signal changes in the anti-cheat system for analysis and adaptation. However, it's crucial to note the potential risks associated with such software, including ethical considerations and the possibility of misuse for circumventing security measures in games and applications.