> For the complete documentation index, see [llms.txt](https://bible.fairplaylab.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bible.fairplaylab.org/usermode/process_handle.md).

# Process Handles

Process handle detection, hijacking, and defensive triage from usermode.

**Cheat**

**Type**: External usermode

**Goal**: Open, inherit, duplicate, or steal a process handle that can read, write, inject, or manipulate the game.

**AntiCheat**

**Type**: Usermode

**Goal**: Find useful handles to the game, understand who owns them, score the risk, and respond without breaking normal software.

Notes:

External usermode memory tools need access to the game process. Cheat Engine, trainers, simple RPM and WPM tools, and many private external cheats all start with the same boring object: a handle.

Hooking `OpenProcess` sounds tempting, but it is the wrong center of gravity. You would have to hook every process that might call it. A cheat can use native syscalls, duplicate an existing handle, inherit a handle from a launcher, run before your hook exists, or avoid your process entirely. Hooking your own process only tells you who opened handles from inside your own process, which is not the interesting path.

The better usermode approach is handle table sweeping. You ask the system what handles exist, duplicate candidates into the anti cheat process, verify which object they point to, then inspect the owner and access mask.

<figure><img src="https://3105513573-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkjacOMiVk96mDkbgtNqn%2Fuploads%2Fgit-blob-316b855feef26d426224e140b534fef51e0137ae%2Fopen_handle.png?alt=media" alt=""><figcaption><p><a href="https://github.com/0x90sh/fairplaylab_detections/tree/main/usermode/process_handle">https://github.com/0x90sh/fairplaylab_detections/tree/main/usermode/process_handle</a></p></figcaption></figure>

#### Why Handles Matter

A handle is a capability. If another process holds a handle to the game with useful rights, that process can ask the kernel to do work against the game object.

Important process rights:

* `PROCESS_VM_READ` lets an external tool read game memory
* `PROCESS_VM_WRITE` lets it write memory
* `PROCESS_VM_OPERATION` lets it allocate, free, and change page protection
* `PROCESS_CREATE_THREAD` is useful for classic remote thread injection
* `PROCESS_DUP_HANDLE` can turn a trusted holder into a handle source
* `PROCESS_QUERY_INFORMATION` and `PROCESS_QUERY_LIMITED_INFORMATION` help identify the object
* `PROCESS_SUSPEND_RESUME` and `PROCESS_TERMINATE` are useful for disruption and tamper flows

Important thread rights:

* `THREAD_SET_CONTEXT` is useful for thread context hijacking
* `THREAD_SUSPEND_RESUME` supports hijacking and timing attacks
* `THREAD_QUERY_INFORMATION` helps map thread state

The useful distinction is not has a handle versus does not have a handle. The useful distinction is what rights the handle carries, who owns it, why it exists, and when it appeared.

#### Handle Sweep

The usual usermode sweep uses `NtQuerySystemInformation` with `SystemExtendedHandleInformation` or `SystemHandleInformation`. The extended class is preferred on x64 because handle values and object pointers fit the modern layout better. This is native API territory, so the code must be written defensively and tested across Windows versions.

Practical flow:

* query the system handle table
* filter entries by object type when possible
* open the owner process with `PROCESS_DUP_HANDLE`
* duplicate the candidate handle into the anti cheat process
* call `GetProcessId` on the duplicate
* keep only handles that point to the protected game process
* record owner PID, handle value, object type, granted access, and time first seen

The duplicate step matters. A raw handle table entry does not prove the object is your game. Verifying the duplicated handle does.

#### Access Scoring

Do not ban only because a process has a game handle. Windows is noisy.

Low signal:

* query limited information
* synchronize
* handles owned by the game itself
* handles owned by a known launcher during startup

Medium signal:

* query information from an unknown process
* duplicated handle rights
* handle appears after match start
* handle owner has no visible UI or product reason

High signal:

* memory read
* memory write
* memory operation
* create thread
* duplicate handle
* thread set context
* suspend and resume
* all access

The strongest usermode signal is a high risk access mask from an unknown owner that appears after the game is already protected.

#### Trusted Holder Review

A whitelist by PID is weak. PIDs recycle, processes can be injected into, and a cheat can steal from a trusted process.

A better trust check combines:

* full image path
* signer
* parent process chain
* command line
* loaded modules
* integrity level
* session ID
* whether it existed before game launch
* whether it normally ships with the game, platform, overlay, capture tool, or security product
* whether it owns a handle with more rights than it needs

Even trusted holders should be least privilege. A Discord overlay or crash reporter does not need `PROCESS_VM_WRITE`. A platform launcher may need query rights during startup, not memory operation during a match.

#### Handle Hijacking

Handle hijacking means the cheat does not open a new handle to the game. It finds another process that already has one and uses `DuplicateHandle` to copy it.

This is why the owner process is only half the story. The suspicious process may never hold the original game handle for long. It may hold `PROCESS_DUP_HANDLE` to the trusted holder instead.

Useful indicators:

* unknown process opens `PROCESS_DUP_HANDLE` to a trusted holder
* trusted holder owns stronger game access than expected
* duplicate attempts happen shortly before memory reads or writes
* trusted process suddenly loads unknown modules
* a handle disappears right after it is discovered
* the same unknown process repeatedly probes different holder PIDs

Usermode can see some of this by sweeping handles to both the game and high value trusted holders. Kernel mode does it better with object callbacks.

#### Process Dumps And Holder Scans

If a process holds a dangerous handle, the next question is what that process is.

Possible follow up checks:

* module list scan
* memory map scan for private executable regions
* thread start address scan
* image signer check
* parent chain check
* command line check
* optional process dump for offline analysis

Process dumps are invasive. They can capture private data from the holder process. Use them carefully, keep them local unless there is a clear consent and privacy model, and prefer metadata first.

For most anti cheats, a good first response is local triage and game start blocking, not uploading a dump.

#### Closing Handles

The demo closes suspicious source handles with `DUPLICATE_CLOSE_SOURCE`. This is useful for a lab, but production use needs care.

Problems:

* closing a legitimate handle can crash or break another product
* a cheat can reopen the handle
* a cheat can race the sweep
* protected processes and permission boundaries can block inspection
* closing the handle does not undo memory already read or written

Better behavior:

* log the event
* reduce trust score
* warn or block before match start
* require restart into a clean state
* close only clearly malicious or lab controlled handles
* move prevention into a kernel callback when possible

#### Usermode Limits

Usermode handle detection is reactive. It sees handles after the kernel granted them.

Common bypasses:

* duplicate from trusted holder
* open and close between sweeps
* use direct syscalls
* run with higher privilege
* inject into a trusted holder
* use a kernel driver
* use DMA

This does not make usermode handle detection useless. It makes it a signal source. It catches cheap external tools, forces more complexity, and gives context for later injection or memory findings.

#### Kernel Upgrade

The kernel version of this defense uses `ObRegisterCallbacks`. Instead of finding a bad handle after the fact, the driver can strip dangerous rights before the handle is created or duplicated.

That changes the defense from:

* find handle
* duplicate handle
* verify target
* close or log

to:

* intercept requested access
* remove dangerous rights
* record requestor and target
* let harmless access continue

The usermode sweep is still useful as a cross check, because existing handles may predate the driver and trusted holders still need review.

#### Build

```bat
cmake -S . -B build -A x64
cmake --build build --config Release
```

#### Run

```bat
build\Release\anticheat.exe
build\Release\cheat_open_handle.exe <anticheat_pid>
build\Release\cheat_hijack_handle.exe <source_pid> <source_handle_hex> <anticheat_pid>
```

Full source:

<https://github.com/0x90sh/fairplaylab_detections/tree/main/usermode/process_handle>

References:

* [NtQuerySystemInformation](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation)
* [DuplicateHandle](https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle)
* [Process security and access rights](https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights)
* [OpenProcess](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://bible.fairplaylab.org/usermode/process_handle.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
