Skip to content

Team assignments are net synced but team selections are not which can be problematic #102

Open
@xezon

Description

@xezon

Team assignments are net synced but team selections are not which can be problematic. This behavior can be exploited with game breaking consequences. GenTool fixes this issue by preventing the selection of newly assigned teams until the assignment is completed.

For game.dat

Inject naked function CC_AssignTeamInUI at address 0x615BE0 taking 5 bytes.
Inject naked function CC_SelectTeamInUI at address 0x615C55 taking 5 bytes.

CC_AssignTeamInUI will just save a state and then continue code execution normally.

CC_SelectTeamInUI will check when team was assigned, and if it was less frames ago than the match latency (10-64), then it will skip the user team selection action.

// When assigning a team to an object it takes at least 10 frames till the job is done
// Meanwhile team selection happens instantly - this is problematic and abusable
// We need to make sure that a team cannot be selected when it was just assigned earlier

//////////////////////////////////////////////////////////////////////////////////////

DWORD ccAssignTeamInUiRet;
DWORD ccSelectTeamInUiRet;
uint32 ccTeamNumber;

__declspec(naked) void CC_AssignTeamInUI()
{
	__asm pop [ccAssignTeamInUiRet]
	__asm ADD EAX,-0x2E
	__asm mov ccTeamNumber,eax
	__asm pushad

	CGameAccess::Instance.OnAssignTeamInUI(ccTeamNumber);

	__asm popad
	__asm CMP EAX,EBX
	__asm push [ccAssignTeamInUiRet]
	__asm ret
}
__declspec(naked) void CC_SelectTeamInUI()
{
	__asm pop [ccSelectTeamInUiRet]
	__asm ADD EAX,-0x38
	__asm mov ccTeamNumber,eax
	__asm pushad

	if (CGameAccess::Instance.GroupingWasExploited(ccTeamNumber))
	{
		__asm popad
		__asm mov eax,-1
	}
	else
	{
		__asm popad
	}
	__asm CMP EAX,EBX
	__asm push [ccSelectTeamInUiRet]
	__asm ret
}

Here is high level logic: In OnAssignTeamInUI function we just remember at which frame a team was assigned to something.

void CGameAccess::OnAssignTeamInUI(uint32 teamNumber)
{
	if (teamNumber < 10)
	{
		Hack_GetFrameCount(m_teamAssignmentFrameId[teamNumber]);
	}
}

And in GroupingWasExploited we check if we passed the latency time we should wait between Team assignment and Team selection. If enough frames passed, then it is good to continue as usual. If not enough frames passed, we return false and team selection is aborted. User can try to select team later again.

bool CGameAccess::GroupingWasExploited(uint32 teamNumber)
{
	if (teamNumber < 10)
	{
		uint32 currentFrameId = 0;
		uint32 latencyFrameCount;

		Hack_GetFrameCount(currentFrameId);
		if (Hack_GetLatency(latencyFrameCount))
		{
			// This will not hit in Single Player, because there is no latency
			latencyFrameCount += 1; // Add a little lean time just to make sure
			if (currentFrameId - m_teamAssignmentFrameId[teamNumber] <= latencyFrameCount)
			{
				return true;
			}
		}
	}
	return false;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething is not working right, typically is user facingCriticalSeverity: Minor < Major < Critical < BlockerGenToolRelates to GenToolZHRelates to Zero Hour

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions