uberheartbeat - festivaldev/Paradise GitHub Wiki

uberheartbeat

Unfortunately, not much is known about uberheartbeat. Supposedly, it's some kind of anti-cheat implemented into UberStrike by Cmune. However, thanks to the findings of daniel_crime on the Paradise Discord Server, we know there are 4 main functions (each called by the game) and a lot of weird stuff going on in the background.

For full disclosure, the disassembled pseudocode for uberheartbeat.dll is included at https://github.com/festivaldev/Paradise/tree/new-paradise/uberheartbeat. It's almost not human-readable at all, but it's there if someone more experienced than us wants to have a look at it.

"I" Function

The "I" function initializes a thread

int32_t I(void) {
    int32_t threadHandle = (int32_t)CreateThread(NULL, 0, (int32_t (*)(int32_t *))0x10001030, NULL, 0, NULL); // 0x10009152
    g12 = threadHandle;
    return threadHandle;
}

"S" Function

The "S" function checks if a .NET Named Pipe under \\.\pipe\cemonodc_pid{PID} ({PID} being the process ID of UberStrike) is opened by trying to open a new pipe with the same name. This corresponds to Cheat Engine opening such a pipe for each process it has been attached to. It then tries to create a HANDLE on that pipe and send a 0, which corresponds to Cheat Engine's "INITMONO" command (see https://github.com/imgits/cheat-engine/blob/master/Cheat%20Engine/MonoDataCollector/MonoDataCollector/PipeServer.h). If that is successful and Cheat Engine reports Mono as initialized, the function returns 0, otherwise 1. The game then sets an internal variable called m_MonoInitialized to either true or false respectively, depending on the return value. This variable controls if the "D" or "C" functions are called by the game at a later point.

int32_t S(void) {
    int32_t processId = GetCurrentProcessId();
    function_10001460((int32_t)&g15, 256, L"\\\\.\\pipe\\cemonodc_pid%d", processId);
    int32_t * hFile = CreateFileW((int16_t *)&g15, -0x40000000, 3, NULL, 3, 0, NULL); // Create a HANDLE on the .NET Pipe
    int32_t v1 = (int32_t)hFile; // If (int32_t)hFile > 0, the HANDLE is ready
    g14 = v1;
    int32_t result = 1;
    switch (v1) {
        default: {
            char lpBuffer = 0; // MONOCMD_INITMONO
            int32_t lpNumberOfBytesWritten;
            WriteFile(hFile, (int32_t *)&lpBuffer, 1, &lpNumberOfBytesWritten, NULL); // Write the buffer into the pipe
            result = (function_100088d0() | v1) == 0; // Read pipe buffer and check if return value is 0 (error if > 0)
        }
        case -1: {
        }
        case 0: {
            return result;
        }
    }
}

"D" Function

The "D" function is called by the game when it is about to quit (see Unity's MonoBehaviour.OnApplicationQuit). It writes Cheat Engine's "TERMINATE" command to the pipe (if it's open). According to daniel_crime's tests, it caused the CE pipe to hang indefinitely.

D - Tries to write to cemonodc pipe which causes it to indefinitely hang (According to docs it waits until it gets a connection it can write to) which explains why everything broke when I called it
– daniel_crime, April 04 2023

Even though it is included in the code, the function will not return 0 (or anything else) due to it constantly waiting for a connection.

int32_t D(void) {
    int32_t result = 1;
    if (g14 >= 1) {
        char lpBuffer = 22; // MONOCMD_TERMINATE
        int32_t lpNumberOfBytesWritten;
        WriteFile((int32_t *)g14, (int32_t *)&lpBuffer, 1, &lpNumberOfBytesWritten, NULL);
        result = 0;
    }
    
    return result;
}

"C" Function

Note: This section in particular is incomplete due to the reverse-engineered pseudocode being filled with a huge amount of junk code. Cleaning this mess will probably take a long time, and as this process moves on, more and more about the functionality of uberheartbeat is uncovered.

The "C" function does some very weird stuff. According to daniel_crime, it iterates over each open window and checks their names. It also lists each assembly loaded into the main UberStrike process, and then concats each name into a long string which is then used to create a hash that is sent to the Game server a player is currently connected to.

If the previously mentioned Cheat Engine pipe is open, window titles match a certain (still unknown) pattern or Mono isn't loaded, uberheartbeat generates a static hash that is considered by the Realtime server as a "Junk" hash. If such a hash is sent to the server, the player's connection is probably being terminated or the game is force-closed by the server.
Additionally, attaching a debugger to UberStrike while uberheartbeat is active, it will cause the game to either hang or exit.