THE FINALS a new f2p arena game

Posted on Dec 23, 2023


Without regurgitating too much about this game, THE FINALS is a new free-to-play arena shooter that was released about two weeks ago on Steam.

Previously I had taken a look at this game during the multiple beta releases earlier this year but now that it’s finally released lets talk about it’s state.

BETA releases

There were a few beta releases of this game and I only participated in the last one. Initially, the game appeared to be packed, leading me to suspect it used something akin to VMP. However, it soon became clear that it was utilizing a different form of protection. I’v come across this this before in The Cycle: Frontier after [Byfron] was acquired by Roblox. The later stages of that game before it died horribly they switched to another protection solution which the community dubbed Walmart Byfron. this was that.

The security/anti-tamper solution Theia from my understanding comes from a company called ZeroItLab based in Hungary. I will talk more about this protection in subsequent posts.

The beta I played also seemed to introduce custom builds for the game per user. This would trigger when you ran the launcher from Steam. It would begin by connecting to:

to retrieve a build.tar.zst file. Once you run that through ZStandard the output would be the game files that get replaced on launch.

They seem to flip-flop between multiple versions of the EmbarkBootstrapper (launcher). One version of the launcher is a compact, 269KB variant that simply executes the main game file, without attempting to download a build from their servers. This change was implemented when they discontinued the use of unique builds during the later stages of the beta.

Public release

The game releases and some notable changes are made. Firstly they change the unique builds to now have encrypted payloads unlike the beta. The anti-tamper security implementation Theia also receives improvements including now encrypting more memory pages at runtime and a bunch of other enhancements.

For this post I will discuss what is going on in the launcher.

Launcher Protection

The launcher doesn’t appear packed however it utilizes the same control flow obfuscation and junk as the game executable.

It contains a bunch of integrity check mechanisms which I’m not 100% sure but I think was written by their internal team because it’s really poor, outdated and to be frank useless.

Tooling checks

The launcher will attempt to locate certain common cheating tools.

  • ida64
  • cheatengine
  • reclass

It does this by using the API CreateToolhelp32Snapshot which is called with TH32CS_SNAPPROCESS, this creates a snapshot of all processes in the system.

It then enters a loop using subsequent kernel32 APIs Process32FirstW and Process32NextW, iterating over each process in the snapshot comparing it’s name to the ones listed above.

If it finds a match you will get a message warning such as:

[Cheat Engine] was detected. 
This is a violation of our code of conduct, 
continued use will lead to account suspension or 
other action in accordance with our user terms.

IDA specific detection

IDA is also additionally detected through it’s creation of Mutext Objects entries while running.

IDA creates two mutex entries:

  • \Sessions\1\BaseNamedObjects\$ IDA registry mutex $
  • \Sessions\1\BaseNamedObjects\$ IDA trusted_idbs

The launcher will try query only the first one by doing:

OpenMutexW(1u, 0, L"$ IDA registry mutex $");

if this returned value is not NULL you are screwed.

Debugger Checks

The launcher attempts to detect a debugger by leveraging a few techniques.

  • The first and most useless technique is grabbing the current PEB and checking the ‘BeingDebugged’ flag. 🤦‍♂️
pPeb = NtCurrentPeb();
if (pPeb->BeingDebugged)
  • The second check calls CheckRemoteDebuggerPresent
pbDebuggerPresent[0] = 0;
v23 = GetCurrentProcess();
CheckRemoteDebuggerPresent(v23, pbDebuggerPresent);
  • Third check utilizes the QueryInformationProcess function inside ntdll. (Simplified logic below as there is too much crap in the disassembly)
HANDLE currentProcess = GetCurrentProcess();
int debugFlags = 0;
NTSTATUS status = NtQueryInformationProcess(
    ProcessDebugFlags,     // 31 = querying for debug flags

if (NT_SUCCESS(status)) 
    //Check Debug Flags

It seems only the following information classes are queried at present.

  • ProcessDebugPort (7)
  • ProcessDebugObjectHandle (30)
  • ProcessDebugFlags (31)

After patching/hooking all these you are free to attach a debugger.

The game executable & packer

I will talk about this in the next post.