PareidoliaTriggerbot is a hypervisor-based, external Widowmaker triggerbot which uses the VivienneVMM and MouClassInputInjection projects to bypass the Overwatch Anti-Cheat.
This hack has remained undetected since its initial completion in early 2018.
See the PareidoliaCL README.
PareidoliaTriggerbot is composed of a user mode client application and a kernel mode driver. The client contains the triggerbot logic, and the driver provides support services for the client (e.g., reading process memory without a handle) via a device interface.
The client executes an infinite tick loop to update the triggerbot state machine. The following diagram depicts a simplified overview of the tick loop:
.-----------------------.
| |
v |
+===============================+ |
| Process user input | |
+===============================+ |
| |
v |
.-------------------------------. |
| Is the round context valid? |--No-->+
'-------------------------------' |
| |
Yes |
| |
v |
.-------------------------------. |
| Is the triggerbot enabled? |--No-->+
'-------------------------------' |
| |
Yes |
| |
v |
+===============================+ |
| Read Widowmaker Trace State | |
+===============================+ |
| |
v |
.-------------------------------. |
| Is the player's crosshair |--No-->+
| over an enemy player? | |
'-------------------------------' |
| |
Yes |
| |
v |
+===============================+ |
| Activate trigger | |
+===============================+ |
| |
v |
+===============================+ |
| Trigger cooldown | |
+===============================+ |
| |
'-----------------------'
The Widowmaker trace state is a ULONG-sized variable which has a nonzero value when:
-
There is a Widowmaker player in a match.
-
The Widowmaker player has the Widow's Kiss sniper rifle equipped.
-
The Widowmaker player is scoped (i.e., zoomed in) and the Widow's Kiss is fully charged.
-
The Widowmaker player's crosshair is over an enemy player entity or a dynamic, non-player entity (e.g., the payload, a closed spawn door, or the lid of a trash can).
This variable exists as a field in the trace state object type. The following diagram depicts the trace state elements inside the Overwatch virtual address space:
Low Memory
+====================+
| | Trace State Object
| | ~
| | +=============+
| | | | Trace State
|--------------------| |-------------| ~
| Dynamic Allocation | -----> | Trace State | -----> [0, MAXULONG]
|--------------------| | Variable |
| | |-------------|
| | | |
| | +=============+
| |
| |
| |
| |
| |
+====================+
High Memory
The game engine maintains one trace state object for each Widowmaker player in a match. A trace state object is created each time a non-Widowmaker player swaps to the Widowmaker hero. The object is destroyed when the player swaps to a non-Widowmaker hero, the round ends, or the player leaves the match.
NOTE We do not fully understand the purpose of the trace state variable. We refer to this concept as the 'trace state' because the variable behaves as if it were the hit detection result of the game engine running a trace ray whose origin vector is the Widowmaker player's crosshair.
The trace state mechanic provides all of the functionality required to write a triggerbot. In order to use this mechanic we need to be able to locate the address of our (local player) trace state object inside the remote Overwatch process. This is nontrivial for the following reasons:
-
The address of the target trace state object changes when the object is destroyed and recreated.
-
We cannot hook code in the Overwatch process because the anti-cheat frequently scans for code patches.
-
Overwatch's code and data are significantly obfuscated.
We can reliably recover the address of our trace state object using the VivienneVMM Capture Execution Context Register request. Our target instruction is executed whenever a Widowmaker player presses their 'zoom' keybind. The following is the annotated assembly of the target instruction:
Platform: Windows 7 x64
File Name: Overwatch.exe
Version: 1.41.1.0 - 63372
SHA256:
9d079af7df9ed332f32d303c1eec0aab886f300dc79489019b8bbae682cbdb99
Assembly:
89 87 FC 01 00 00 mov [rdi+1FCh], eax
rdi = Pointer to the base address of a trace state object.
1FC = The field offset of the trace state variable.
eax = The new trace state value.
NOTE We found this instruction by scanning Overwatch's virtual memory for values which changed when the local player was scoped / not scoped.
NOTE We do not fully understand the purpose of the trace state instruction or its containing function.
PareidoliaTriggerbot passively avoids detection using the following strategies:
-
The client interacts with the target Overwatch process using the driver interface. i.e., The client does not open any handles to the target Overwatch process.
-
The client uses the MouClassInputInjection project for stealthy mouse input injection.
-
The driver registers kernel object callbacks to prevent the target Overwatch process from reading the client's virtual address space.
-
The triggerbot simulates realistic mouse clicks by waiting for a dynamic amount of time before injecting the mouse release event. This release delay is a pseudo-random number bounded by parameters in the config file. Users can use the MouHidInputHook project to obtain the average delay for their mouse.
This repository uses the MouClassInputInjection and VivienneVMM projects as git submodules. The client and driver projects in these submodules are configured to produce static libraries. The PareidoliaTriggerbot projects link against these libraries for mouse input injection and capture execution context register requests.
The user mode triggerbot client.
The kernel mode triggerbot driver.
A kernel mode static library which implements mouse input injection. This project is a submodule.
A user mode static library which provides the client interface for mouse input injection. This project is a submodule.
A user mode static library which provides the VivienneVMM interface for Capture Execution Context Register requests. This project is a submodule.
A kernel mode static library which implements the VivienneVMM interface. This project is a submodule.
The projects in this repository use several globally visible names which can potentially be used as a detection vector by anti-cheat software. These names include:
- The symbolic link for the PareidoliaTriggerbot device object.
- The symbolic link for the MouClassInputInjection device object.
- The symbolic link for the VivienneVMM device object.
- The VivienneVMM signature returned by the cpuid instruction.
- The VivienneVMM log file name.
Users should modify these names and values by editing the config file.
The PareidoliaCL.exe and PareidoliaTriggerbot.sys files on disk are subject to signature scans (even with the process access protection module enabled). Users should pack and/or encrypt the PareidoliaCL.exe file and delete the PareidoliaTriggerbot.sys file after the driver is loaded to avoid this detection vector.
The PareidoliaTriggerbot driver does not prevent successive MOUSE_LEFT_BUTTON_DOWN or MOUSE_LEFT_BUTTON_UP mouse input packets. Normally, a physical mouse will never generate two MOUSE_LEFT_BUTTON_DOWN packets or two MOUSE_LEFT_BUTTON_UP packets in a row because each physical click action has a press and release event. Since the PareidoliaTriggerbot driver injects mouse input packets it is possible for the following series of events to occur:
- PareidoliaCL decides to trigger.
- PareidoliaCL sends an IO request to the driver to inject a left-click input packet.
- PareidoliaTriggerbot processes the IO request and injects a MOUSE_LEFT_BUTTON_DOWN packet.
- The user physically presses the left mouse button.
In this scenario, steps (3) and (4) result in two successive MOUSE_LEFT_BUTTON_DOWN packets in the input data stream. Anti-cheat software can potentially use this unnatural series of events as a detection vector by monitoring mouse input events via Windows input hooks.
Users can mitigate this scenario by not clicking while the local player is scoped and the triggerbot is active.
The Process Access Protection module may cause undesirable side effects. e.g., The user will be unable to close the command prompt process that is hosting the client by clicking the red 'X' button. This feature can be disabled by modifying the config file.
The PareidoliaTriggerbot project does not contain a certificate issued by a trusted root authority. Users must enable test signing in order to load the PareidoliaTriggerbot driver.
This project is intended for educational purposes. Use at your own risk.
- All projects in this repository were developed and tested on Windows 7 x64 SP1.
- All binaries are PatchGuard safe on Windows 7.