4652dc5c4a31f080b63b3aba9d0727beb141bf2f
1
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0f4ab63101 |
patchmanager: fix signature patches reporting neither on or off (#873)
## Link to GitHub Issue or related Pull Request, if one exists
None
## Description of change
Patch Manager showed valid signature patches as broken: **"Bad patch;
patch is neither on or off"** instead of Enabled/Disabled, so they could
not be toggled.
`SignaturePatch::to_memory` had two bugs. In the configurator it cached
a file offset as `data_offset_ptr`, so status checks `memcmp`'d a fake
address. It also passed JSON `offset` into `find_pattern` while still
indexing the signature/replacement from 0, which mis-aligned every patch
with `offset != 0`. This change locates the signature start, applies
`offset` afterward, compares only the replacement window, and leaves the
pointer null so `is_patch_active` re-resolves from `data_offset`.
Not proposed as built-in patches. The JSON below is the reproduction
case: each entry uses `offset > 0` and a replacement shorter than the
signature.
## Testing
Reproduced in Patch Manager against `bm2dx.dll` using the signature JSON
below. Before the fix, every patch reported "neither on or off". After
the fix, each patch locates, shows Disabled/Enabled, and toggling writes
only the replacement bytes at `signature_match + offset`.
## Demo
<details>
<summary>Signature JSON used to reproduce (offset + short
replacement)</summary>
```json
[
{
"info": "streaming / getcm patches (type=signature)",
"gameCode": "LDJ",
"notes": "Each site uses a unique signature (usage=0 only)."
},
{
"type": "group",
"id": "streaming-getcm",
"name": "Streaming getcm",
"description": "Enable all children so streaming.common merges without Banner FS and getcm can fire without visiting Test Mode.",
"gameCode": "LDJ"
},
{
"name": "Streaming: merge common without Banner",
"description": "NOP jz in streaming.common callback so CM work table is filled even when Banner FS is still null.",
"caution": "Required. Without this, early common responses are discarded and getcm stays empty.",
"gameCode": "LDJ",
"type": "signature",
"group": "streaming-getcm",
"dllName": "bm2dx.dll",
"signature": "E8????????4885C00F84????????488D0D????????488D15????????41B848080000",
"replacement": "909090909090",
"offset": 8,
"usage": 0
},
{
"name": "Streaming: scheduler without Banner (common)",
"description": "NOP jz after Banner getter on the common branch of the periodic scheduler.",
"caution": "Enable with the getcm scheduler sibling. Unique via imul of common-interval dword.",
"gameCode": "LDJ",
"type": "signature",
"group": "streaming-getcm",
"dllName": "bm2dx.dll",
"signature": "E8????????4885C0742469057E791C0AE8030000",
"replacement": "9090",
"offset": 8,
"usage": 0
},
{
"name": "Streaming: scheduler without Banner (getcm)",
"description": "NOP jz after Banner getter on the getcm branch of the periodic scheduler.",
"caution": "Enable with the common scheduler sibling. Unique via imul of getcm-interval dword. Without this, getcm never schedules while Banner FS is null.",
"gameCode": "LDJ",
"type": "signature",
"group": "streaming-getcm",
"dllName": "bm2dx.dll",
"signature": "E8????????4885C07424690574B91D0AE8030000",
"replacement": "9090",
"offset": 8,
"usage": 0
},
{
"name": "Streaming: fall into getcm after common",
"description": "NOP jmp-after-common so the same scheduler tick can evaluate getcm instead of returning early.",
"caution": "Pair with Banner scheduler skips (or a live Banner FS).",
"gameCode": "LDJ",
"type": "signature",
"group": "streaming-getcm",
"dllName": "bm2dx.dll",
"signature": "891D????????E9????????E8????????4885C074246905",
"replacement": "9090909090",
"offset": 6,
"usage": 0
},
{
"name": "Streaming: getcm interval 1s #1",
"description": "Default getcm poll interval 1800s to 1s (first init store).",
"caution": "Enable #1 and #2 together. Trailing BF3C000000 distinguishes this init site.",
"gameCode": "LDJ",
"type": "signature",
"group": "streaming-getcm",
"dllName": "bm2dx.dll",
"signature": "C705????????18150000C705????????08070000C705????????201C0000BF3C000000",
"replacement": "01000000",
"offset": 16,
"usage": 0
},
{
"name": "Streaming: getcm interval 1s #2",
"description": "Default getcm poll interval 1800s to 1s (second init store).",
"caution": "Enable #1 and #2 together. Trailing 448925 distinguishes this init site.",
"gameCode": "LDJ",
"type": "signature",
"group": "streaming-getcm",
"dllName": "bm2dx.dll",
"signature": "C705????????18150000C705????????08070000C705????????201C0000448925",
"replacement": "01000000",
"offset": 16,
"usage": 0
}
]
```
</details>
Co-authored-by: Cursor <cursoragent@cursor.com>
|