Desktop - Debugger - Detector (Pro)
Debuggers let an attacker pause your game, inspect memory, change values, and step through your code. There are two flavours: user-mode debuggers attached to your process (e.g. Visual Studio, dnSpy, x64dbg, OllyDbg, JetBrains debugger) and kernel-mode debuggers attached to the system (e.g. WinDbg in /KD mode, Syser, SoftICE). Use the 'DebuggerDetector' to detect both and react accordingly.
Detector
The 'DebuggerDetector' does not require any monitor. On demand, it queries multiple debugger sources and aggregates the results:
Managed debugger: Reads 'System.Diagnostics.Debugger.IsAttached' to detect a managed debugger like the Unity Editor debugger or the Visual Studio managed debugger.
User-mode debugger: Asks the platform-specific 'IPlatformProbe.IsUserModeDebuggerPresent'. On Windows this combines 'kernel32!IsDebuggerPresent', 'kernel32!CheckRemoteDebuggerPresent', and 'ntdll!NtQueryInformationProcess' against 'ProcessDebugPort', 'ProcessDebugObjectHandle', and 'ProcessDebugFlags'. On macOS it inspects the 'P_TRACED' flag returned by 'sysctl' with 'KERN_PROC_PID'. On Linux it parses 'TracerPid' from '/proc/self/status'.
Kernel-mode debugger: Asks the platform-specific 'IPlatformProbe.IsKernelModeDebuggerPresent'. On Windows this calls 'ntdll!NtQuerySystemInformation' with 'SystemKernelDebuggerInformation' and reports a kernel debugger that is enabled and present. On macOS and Linux, kernel-mode debugger detection is currently a no-op and reserved for a future native plugin probe.
Observed Subject
The detector does not observe any monitor. It runs an on-demand scan when 'ManualScan()' is invoked or, if enabled, automatically during 'Start' and on a configurable interval.
Status
When a debugger is found, the detector notifies its observers with a DesktopCheatingDetectionStatus, which implements IDesktopCheatingDetectionStatus (and therefore IDetectorStatus):
public struct DesktopCheatingDetectionStatus : IDesktopCheatingDetectionStatus
{
// Probability that the detection is a false positive, in the range [0.0, 1.0].
public float PossibilityOfFalsePositive { get; }
// The threat rating reported with this detection.
public uint ThreatRating { get; }
// The type of cheating detected on the desktop platform.
public EDesktopCheatingType DesktopCheatingType { get; }
// A short, human-readable string describing what triggered the detection.
public string Evidence { get; }
}
- Evidence: For example
IsDebuggerPresent,ProcessDebugPort=0x...,KernelDebuggerEnabled, orDebugger.IsAttached.
For this detector, DesktopCheatingType can be:
public enum EDesktopCheatingType : byte
{
DEBUGGER_USER_MODE = 20, // A user-mode debugger is attached to the process.
DEBUGGER_KERNEL_MODE = 21, // A kernel-mode debugger is active on the system.
DEBUGGER_REMOTE = 22 // A remote debugger is attached / a debug port is assigned.
}
Threat rating and false positives
User mode and kernel mode evidence carry separate ratings, because a kernel debugger on a player machine is far more suspicious than a managed debugger attached during development. ThreatRating reports the larger of the two configured ratings.
- Possibility Of False Positive User Mode: default
0.05(range 0-1). - Possibility Of False Positive Kernel Mode: default
0.001(range 0-1). - Threat Rating User Mode: default
400(recommended 400). - Threat Rating Kernel Mode: default
750(recommended 750).
Each kind (user mode / kernel mode) is reported only once per game session to avoid spamming the punisher chain.
Configuration
- Is Active (
isActive, bool, default true) - whether the detector is active and watching. - Possibility Of False Positive User Mode (
possibilityOfFalsePositiveUserMode, float, default 0.05, range 0-1). - Possibility Of False Positive Kernel Mode (
possibilityOfFalsePositiveKernelMode, float, default 0.001, range 0-1). - Threat Rating User Mode (
threatRatingUserMode, uint, default 400). - Threat Rating Kernel Mode (
threatRatingKernelMode, uint, default 750). - On Cheating Detection Event (
OnCheatingDetectionEvent) - a UnityEvent raised on every detection. - Check Only On Game Start (
CheckOnlyOnGameStart, bool, default false) - run the check only once on start; disable to also run a periodic recheck. Recommended false, because a debugger can attach at any time. - Recheck Interval For Possible Cheating (
RecheckIntervalForPossibleCheating, float, default 5, range 0.1-600) - interval in seconds between checks.
The individual user-mode / kernel-mode toggles and the "report managed-only" option are configured in the global project settings (see 'Configure Desktop Settings' below).
Supported Platforms
The detector is available on Windows, macOS, and Linux Standalone players.
- User-mode debugger detection is implemented on all three platforms.
- Kernel-mode debugger detection is currently implemented on Windows only; on macOS and Linux the kernel-mode probe returns false and is reserved for a future native plugin.
Requirements
There are no native requirements; the detector uses managed APIs and platform P/Invokes provided by the package. In the Unity Editor and in Development Builds, the detector only runs when 'Desktop_Enable_Development' is enabled in the global AntiCheat settings - this is important because the Unity Editor itself counts as a managed debugger.
How To Use
The usage is straightforward: attach a 'DebuggerDetector' to a child GameObject of the 'AntiCheat-Monitor', configure the global Desktop settings, and define a reaction to detected cheating.
Requirements
There are none. No additional monitor is required.
Add Detector Component
Manual
Add the 'DebuggerDetector' MonoBehavior from the 'GUPS.AntiCheat.Detector.Desktop' namespace to your 'AntiCheat-Monitor' GameObject, or better, to a child GameObject.

Add the 'DebuggerDetector' as a Component.
Settings
After attaching the 'DebuggerDetector' MonoBehavior to a GameObject, you will see the following in the inspector:

The settings of the 'DebuggerDetector' Component (shown together with the 'VirtualEnvironmentDetector').
- General Settings: Define here whether the detector should be active.
- Threat Rating Settings: Define here the severity of the detected cheating (separate user-mode and kernel-mode ratings).
- Observable Settings: Add here callbacks invoked when cheating is detected.
- Debugger Settings: Set whether the scan runs once on Start and/or repeats on a configurable interval.
Runtime
On Start (and on the configured interval), the detector queries the managed and native debugger sources and notifies observers if a debugger is found. You can also trigger 'ManualScan()' yourself.
Configure Desktop Settings
Open 'Edit -> Project Settings -> GuardingPearSoftware -> AntiCheat' and switch to the 'Desktop' tab.

In the AntiCheat Project Settings, configure the Desktop debugger detection.
Use the following entries to control this detector:
- Enable in Development: 'Desktop_Enable_Development'. Set to true to allow detection inside the Unity Editor and Development Builds. Off by default - keep this off in production-like testing or you will permanently report a debugger.
- Detect User-Mode Debugger: 'Desktop_DetectUserModeDebugger'. Master switch for the user-mode probe. On by default.
- Detect Kernel-Mode Debugger: 'Desktop_DetectKernelModeDebugger'. Master switch for the kernel-mode probe. On by default; effective only on Windows for now.
- Report Managed Debugger Only: 'Desktop_Debugger_ReportManagedOnly'. When true, the detector only reports if 'Debugger.IsAttached' is true and ignores the native probes. Useful when shipping a Development Build to your QA team.
Consume the detection in code
Besides the inspector event, you can subscribe your own observer. Every detector derives from ADetector and exposes Subscribe(IObserver<IDetectorStatus>), which returns an IDisposable you can dispose to unsubscribe. Cast the status to DesktopCheatingDetectionStatus to read the desktop-specific fields:
using System;
using GUPS.AntiCheat;
using GUPS.AntiCheat.Core.Detector;
using GUPS.AntiCheat.Detector.Desktop;
using UnityEngine;
public class DebuggerDetectionLogger : MonoBehaviour, IObserver<IDetectorStatus>
{
private void Start()
{
var detector = AntiCheatMonitor.Instance.GetDetector<DebuggerDetector>();
detector.Subscribe(this);
}
public void OnNext(IDetectorStatus status)
{
if (status is DesktopCheatingDetectionStatus desktopStatus)
{
Debug.LogWarning($"Debugger detected: {desktopStatus.DesktopCheatingType} " +
$"(threat={desktopStatus.ThreatRating}, evidence={desktopStatus.Evidence}).");
}
}
public void OnError(Exception error) { }
public void OnCompleted() { }
}
React On Cheating
When the detector is set up, you surely want to react to detected cheating.
Punisher
In general, any cheat detected is forwarded to the 'AntiCheat-Monitor', which calculates an overall threat level. Based on the threat level, you can apply punishments by using Punisher components added to a child GameObject of the 'AntiCheat-Monitor'. There are some built-in punishers that you can find here as prefabs:

The location of the built-in Punisher prefabs.
Inspector
You can set a callback in the Unity Inspector view of the detector. This callback is invoked as soon as the specific cheating is detected.
Code
If you would like to write a custom listener for the detector, you can attach an observer:
// Get the detector.
var detector = AntiCheatMonitor.Instance
.GetDetector<DebuggerDetector>();
// Subscribe as observer and get notified on inconsistency.
detector.Subscribe(myObserver);
The detector also has an inherited property 'PossibleCheatingDetected' which is set to true once cheating has been detected.