Motivation
This project has been created several years ago, where I firstly started messing around with VMP 2.X. During that time, I used the BattlEye launcher as my target executable to reinterpret VM instructions. By that time, I figured out that BEDaisy does not strip the process handle created by the launcher. That information let my imagination go wild and find out ways to grab the handle. So I slowly started to reproduce different parts of the launcher. After painting all parts to the big picture, I finally connected all parts of the puzzle and rebuilt a new launcher for that purpose.
Overview
BattlEye is a German anti-cheat developed by Bastian Heiko Suter. It offers game publishers easily integrated anti-cheat solutions, using the newest mechanisms and game-specific detections to provide the best security. BattlEye consists of multiple organs that work together to catch and prevent cheaters. The anti-cheat is packed and virtualized using VMProtect 3.X.
The four main pieces of BattlEye are:
- BEService
- Windows NT-Service that communicates with BEDaisy, which reports detections through a named-pipe to the BEClient.
- BEDaisy
- Windows kernel driver that uses callbacks and minifilters to prevent cheater from touching the memory.
- BEClient
- Windows dynamic link libary that contains the most detection routines. It is mostly injected after game initialization.
- BEServer
- Backend-server owned by the game publisher used to collect information and take actions against cheaters.
BattlEye Launcher
The BattlEye launcher is reponsible for initiating the protection of BattlEye. It creates BEService, starts it and sends necessary information to it. In addition, it also starts the main game and this is the part where FakeEye starts to shine.
Installation of BEService
The first action the BEService does is installing the service. It copies the specific game service into the path C:\Program Files (x86)\Common Files\BattlEye. After that, it starts the service and waits until it the service itself states that it is SERVICE_RUNNING
Initialization of BEService
When the BattlEye service first starts, it expects the launcher to send configuration to it. For that, BEService opens a named pipe called \\.\pipe\BattlEye. In order to do that, the launcher reads the configuration BELauncher.ini found in the BattlEye folder. When opening it, you might find the following:
1
2
3
4
5
6
[Launcher]
GameID=unturned
BasePort=27038
32BitExe=Unturned.exe
SilentInstall=0
BEArg=-BattlEye
GameID is used to identify the game. BasePort is neccessary for the communication. 32BitExe or 64BitExe is required to launch the correct game executable. Silentinstall specifies whether the GUI of the BattlEye launcher should be displayed or not. BEArg tells the launcher the argument required to launch BattlEye.
The launcher puts the GameID, Exe32/Exe64 and BasePort into a packet and sends it through the mentioned pipe to the service. For that, it expects the packet-id to be 0.
Execution of the protected game
BattlEye launcher 2 means the restarted instance of the BattlEye launcher
BattlEye has constructed a way to prevent attacker from abusing the handles. When it comes to launching the protected game, the launcher will restart itself to do it. This allows BEDaisy to protect it from attacker by stripping handle access.
Once it finished the execution, the launcher will send the process-id of the protected game to the BEService in order to exit according to the game.
FakeEye
FakeEye emulates the BattlEye launcher. It reads the configuration file of BattlEye and processes it like the real launcher does. But unlike the original launcher, it does not let the second instance of itself start the game. FakeEye starts the protected game itself and abuses the handles provided by the manual process creation. The complete source code can be found here.