1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2026 Tomasz Kramkowski <tomasz@kramkow.ski>
# SPDX-License-Identifier: CC0-1.0
"""Patching wrapper script.
This file is generated.
See https://kramkow.ski/project/steamvr-patches.html and
https://the-tk.com/cgit/steamvr-patches/about/ for more information.
Use at your own risk!
Installation (where <thing> is the thing this patcher targets, e.g. steamvr):
1. Put this `patch-<thing>` script somewhere, e.g. `~/.local/libexec/patch-<thing>`
2. Mark it executable
3. Change the launch options of the specified <thing> to:
`/absolute/path/to/patch-<thing> %command%`.
If you already have something in there, I'm sure you can figure it out.
4. Launch <thing> normally. You should see a desktop notification with some
diagnostics which specify if the script actually did/tried to do something.
"""
import hashlib
import os
import stat
import subprocess
import sys
import tempfile
from base64 import b85decode
from dataclasses import dataclass
from io import BytesIO
from json import loads as json_loads
from pathlib import Path
from zlib import decompress
NAME = Path(__file__).name
MARKER = b"Valve, please fix."
@dataclass(frozen=True)
class Edit:
offset: int
replacement: bytes
@dataclass(frozen=True)
class Patch:
original_hash: bytes
patched_hash: bytes
edits: tuple[Edit, ...]
@classmethod
def from_dict(cls, data: dict) -> "Patch":
return cls(
bytes.fromhex(data["original_hash"]),
bytes.fromhex(data["patched_hash"]),
tuple(
Edit(offset, bytes.fromhex(replacement))
for offset, replacement in data["edits"]
),
)
def apply_to(self, data: bytes) -> bytes:
payload = data.removesuffix(MARKER)
digest = sha256(payload)
if digest == self.patched_hash:
return payload + MARKER
if digest != self.original_hash:
if payload != data:
raise LookupError(
"already patched with another set of patches: "
"verify file integrity and restart"
)
raise LookupError("unrecognized file hash: this wrapper may need updating")
result = BytesIO(payload)
for edit in self.edits:
result.seek(edit.offset)
result.write(edit.replacement)
patched = result.getvalue()
if sha256(patched) != self.patched_hash:
raise ValueError("patched file checksum mismatch")
return patched + MARKER
def decode_patch_data(data: bytes) -> dict:
return json_loads(decompress(b85decode(data)))
# Just to keep the file small, not for obfuscation.
PATCH_DATA = {}
PATCHES: dict[str, Patch] = {
path: Patch.from_dict(data) for path, data in PATCH_DATA.items()
}
def sha256(data):
return hashlib.sha256(data).digest()
def notify(message):
print(f"{NAME}: {message}", file=sys.stderr)
try:
subprocess.run(
["notify-send", NAME, message],
check=False,
timeout=3,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except (OSError, subprocess.TimeoutExpired):
pass
def replace(path, data):
mode = stat.S_IMODE(path.stat().st_mode)
with tempfile.NamedTemporaryFile(
dir=path.parent, prefix=path.name + ".", delete=False
) as f:
temporary = Path(f.name)
try:
f.write(data)
f.flush()
os.fchmod(f.fileno(), mode)
os.fsync(f.fileno())
os.replace(temporary, path)
finally:
temporary.unlink(missing_ok=True)
def main(command):
diagnostics = []
if not command:
print(f"Usage: {NAME} command [args...]", file=sys.stderr)
return 2
try:
root = Path.cwd()
pending = []
for relative, patch in PATCHES.items():
path = (root / relative).resolve()
try:
original = path.read_bytes()
except FileNotFoundError as e:
diagnostics.append(f"Skipped `{relative}`: {e}")
continue
try:
updated = patch.apply_to(original)
except ValueError as e:
raise ValueError(f"Patching `{relative}` failed: {e}") from e
except LookupError as e:
diagnostics.append(f"Skipped `{relative}`: {e}")
continue
if updated != original:
pending.append((path, updated))
for path, updated in pending:
replace(path, updated)
diagnostics.append(f"Patched {path}")
if diagnostics:
notify("\n".join(diagnostics))
except (OSError, ValueError) as e:
notify("\n".join([f"Encountered an error: {e}", *diagnostics]))
return 1
os.execvp(command[0], command)
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
|