Skip to content

Commit 971dff4

Browse files
committed
added readme
1 parent a0c3ba4 commit 971dff4

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# RAWM Buffer Patcher
2+
3+
Fixes a ~2 GB memory leak in **RAWMHUB.exe** - a native Windows mouse driver/configurator app (~50 MB) by a Chinese manufacturer. The app is required to run in the system tray for auto-profile switching, but immediately consumes **1.8–2 GB of RAM** on startup.
4+
5+
> [!WARNING]
6+
> Tested on RAWMHUB version **2.0.0.3**. Newer versions should be supported since the patcher uses pattern matching rather than hardcoded offsets, but this is not guaranteed. Always check that the patcher reports **7/7 patch points found** before applying.
7+
8+
## Root cause
9+
10+
On launch, the app pre-allocates a pool of **~225 `UsbClient` objects** - one for every device model in its database, not just the ones actually connected. Each `UsbClient` constructor allocates **three 3 MB buffers** via `operator new(0x300000)`:
11+
12+
| Buffer | Offset | Purpose |
13+
|--------|--------|---------|
14+
| READ | +848 | Incoming data from device (control channel) |
15+
| WRITE | +944 | Outgoing commands to device |
16+
| LOG | +1040 | Intermediate / staging buffer |
17+
18+
These buffers serve a **custom control protocol** (settings, DPI, profiles, battery status, macros, RGB) - not raw HID mouse movement data, which is handled directly by the OS via interrupt endpoints.
19+
20+
```
21+
225 objects × 3 buffers × 3 MB = ~2 GB
22+
```
23+
24+
The buffers are almost entirely empty (filled with zeros). Real throughput on the control channel is **~13 KB/s peak**, making 3 MB per buffer roughly **200–1000× oversized**.
25+
26+
## What the patcher does
27+
28+
Replaces the buffer size constant at **7 code locations** found via assembly pattern matching:
29+
30+
- **3× allocation**: `mov ecx, 0x300000` before `call operator new`
31+
- **3× boundary check**: `cmp eax, 0x300000` in append functions (prevents heap overflow)
32+
- **1× memset size**: `mov r8d, 0x300000` in buffer reset
33+
34+
Default patched value: **0x10000 (64 KB)** - provides a 5× safety margin over worst-case throughput.
35+
36+
```
37+
Before: 225 × 3 × 3 145 728 B ≈ 2 023 MB
38+
After: 225 × 3 × 65 536 B ≈ 43 MB (-97.8%)
39+
```
40+
41+
## Usage
42+
43+
1. Close RAWMHUB if running
44+
2. Run `RAWMPatcher.exe`
45+
3. The patcher auto-detects the executable; if not, click **[...]** to browse
46+
4. Adjust the buffer size if needed (hex, default `10000` = 64 KB)
47+
5. Click **Patch**
48+
49+
A `.bak` backup is created automatically before the first patch. Click **Restore** to revert to the value that was in the binary when it was loaded.
50+
51+
The UI language is detected automatically from Windows regional settings. To override, pass `--lang <LCID>`:
52+
53+
```
54+
RAWMPatcher.exe --lang 0x0409 English
55+
RAWMPatcher.exe --lang 0x0419 Russian
56+
RAWMPatcher.exe --lang 0x0422 Ukrainian
57+
RAWMPatcher.exe --lang 0x0804 Chinese Simplified
58+
RAWMPatcher.exe --lang 0x0404 Chinese Traditional
59+
RAWMPatcher.exe --lang 0x0407 German
60+
RAWMPatcher.exe --lang 0x0416 Portuguese (Brazil)
61+
```
62+
63+
## Building
64+
65+
Open `src/RAWMPatcher.sln` in Visual Studio 2022 and build for **x64** (Release or Debug). No external dependencies.
66+
67+
## How pattern matching works
68+
69+
The patcher does not rely on hardcoded file offsets. Instead, it scans the binary for four unique assembly patterns with wildcards, making it potentially compatible across different builds:
70+
71+
| Pattern | Signature | Matches |
72+
|---------|-----------|---------|
73+
| Alloc×3 | `B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 89 83 50 03 00 00 B9 ...` | 1 (3 values) |
74+
| Check buf1 & buf3 | `42 8D 04 37 3D ?? ?? ?? ?? 7F ?? 48 8B CE` | 2 |
75+
| Check buf2 | `42 8D 04 3F 3D ?? ?? ?? ?? 0F 8F ?? ?? ?? ?? 41 80 3E 06` | 1 |
76+
| Memset buf3 | `49 8B C9 41 B8 ?? ?? ?? ?? 33 D2 E8 ?? ?? ?? ?? 48 8B CE` | 1 |
77+
78+
All 7 patch points must be found with identical values; otherwise the patcher reports an error.
79+
80+
## Why 64 KB is safe
81+
82+
The three buffers handle a **low-bandwidth control protocol**, not mouse tracking data:
83+
84+
- Messages are small (5–68 bytes each): DPI settings, polling rate, battery, profiles, macros, RGB
85+
- Peak throughput: ~200 messages/sec × 68 bytes ≈ **13.6 KB/sec**
86+
- A 1-second timer drains the buffers, so at most ~14 KB accumulates
87+
- 64 KB provides **~5× headroom** even under worst-case load
88+
- 8 KHz polling rate is irrelevant - it applies to the HID interrupt endpoint, not this control channel
89+
90+
## Notes
91+
92+
- This is a **workaround**, not a proper fix. The root cause is architectural: the app creates `UsbClient` objects for every supported device (not just connected ones), and each object has oversized buffers. An ideal fix would use lazy allocation or filter by connected devices.
93+
- The patch has been tested stable with 8 KHz polling, BLE, and USB modes.

0 commit comments

Comments
 (0)