Client>Server Communication
There is no singular function that is responsible for this task. In Apex, we rather have multiple of those working together.
Let's get started with the most common function, R5AC::PushViolation:
void __fastcall R5AC::PushViolation(
const __m128i *pszIdentifierStr,
char Severity,
__int64 ExtraDataPtr,
__int64 ExtraDataLen);
In case of client-side abnormalities being detected, it will be invoked like this:
LBL_ON_ABNORMALITY_FOUND:
v119 = v116();
v120 = 0;
v121 = 0i64;
do
{
v122 = *(_BYTE *)(v121 + 41489128); // these are just data and key, and the RVA can be computed with analysis of a runtime dump.
++v120;
v123 = *(_BYTE *)(v121 + 27928337);
v188[++v121 + 15] = v123 ^ v122;
}
while ( v120 < 0xC ); // C-String encryption using simple xor
sprintf_s_2(Buffer, 0x104ui64, Format, v119);
}
}
R5AC::PushViolation(v200, 1, v177, (__int64)Buffer);
It's purpose is to enqueue a new violation record into a list that is fetched and emptied by numerous callers, all originating from r5apex_dx12.exe. These are to be considered slaves because they simply check if there is any messages pending, use CLC_AntiCheat virtual method table to setup a new netmessage in source engine, and then puts the data of the anti-cheat violation/message into the netmsg and sends it to the game server.
_BYTE *__fastcall R5::BuildAnticheatMsg3(__int64 a1)
{
_BYTE *result; // rax
unsigned int v3; // ebx
__int64 v4; // rbp
int v5; // edi
__int64 v6; // r8
char v7; // al
const char *v8; // rax
__int64 v9; // rcx
char v10; // dl
int v11; // eax
_BYTE *v12; // rax
char v13[16]; // [rsp+20h] [rbp-858h] BYREF
__int64 (__fastcall **v14)(); // [rsp+30h] [rbp-848h] BYREF
int v15; // [rsp+38h] [rbp-840h]
char v16; // [rsp+3Ch] [rbp-83Ch]
__int64 v17; // [rsp+40h] [rbp-838h]
__int16 *v18; // [rsp+50h] [rbp-828h]
int v19; // [rsp+58h] [rbp-820h]
__int16 v20[512]; // [rsp+460h] [rbp-418h] BYREF
int i; // [rsp+880h] [rbp+8h] BYREF
int v22; // [rsp+888h] [rbp+10h] BYREFresult = *(_BYTE **)a1;
if ( !*(_QWORD *)a1 || !*result )
return result;
v3 = 0;
v4 = gpNetChan;
if ( gpNetChan )
{
v14 = vft::CLC_AntiCheatMsg;
v15 = 0;
v17 = 0i64;
v5 = 5;
v16 = 1;
// send all of them in bulk
for ( i = 0; (unsigned __int8)R5AC::PopAnticheatMsg(v20, &i); --v5 )
{
if ( !v5 )
break;
v18 = v20;
v19 = i;
C_NetChan::SendNetMsg(v4, &v14, 0, 0);
C_NetChan::SendDatagram(v4, 0i64);
}
}
if ( dword_3C3EF18 == 1 )
{
v6 = 0i64;
if ( dword_57D5F0C )
{
v3 = dword_57D5F0C;
v6 = (unsigned int)dword_3C3EF18;
v7 = 0;
goto LABEL_28;
}
if ( !byte_57D5EF1 )
{
v7 = 0;
v6 = 2i64;
goto LABEL_28;
}
if ( !qword_57D5F10 )
{
v7 = 0;
v6 = 3i64;
goto LABEL_28;
}
if ( !byte_57D5EF6 )
{
v7 = 0;
v6 = 4i64;
goto LABEL_28;
}
if ( !byte_57D92E0 )
{
v7 = 0;
v6 = 5i64;
goto LABEL_28;
}
if ( !byte_57D93E0 )
{
v6 = 6i64;
v7 = 0;
goto LABEL_28;
}
}
else
{
if ( dword_3C3EF18 != 2 )
goto LABEL_35;
v6 = 0i64;
if ( !byte_57E609C )
{
v7 = 0;
v6 = 1i64;
goto LABEL_28;
}
if ( !qword_57E5D30 )
{
v7 = 0;
v6 = 2i64;
goto LABEL_28;
}
if ( !byte_57E4CC0 )
{
v6 = 3i64;
v7 = 0;
goto LABEL_28;
}
}
v7 = 1;
LABEL_28:
if ( !v7 )
{
if ( dword_3C3EF18 == 1 )
{
sub_21E720((unsigned int)dword_3C3EF18, "#ORIGIN_R