Skip to content

Instantly share code, notes, and snippets.

@ivan
Last active July 12, 2026 20:45
Show Gist options
  • Select an option

  • Save ivan/2c67e1348c17445e380b68b85162a933 to your computer and use it in GitHub Desktop.

Select an option

Save ivan/2c67e1348c17445e380b68b85162a933 to your computer and use it in GitHub Desktop.
Fix the walking speed in The Witness witness64_d3d11.exe (GOG, Patch 21.12.2017 from 06 March 2018) to not have sqrt(2) walking speed on stairs
#!/usr/bin/env python3
# Model-output: ChatGPT 5.6 Sol (High)
"""Patch The Witness stair movement and bypass its startup corruption guard.
The movement patch rescales a player-only walk-manifold request when traversal adds
vertical displacement. The startup patch removes the conditional jump that routes
a zero critical-asset sentinel to ``fatal_error_data_corruption``. The PE file size
and section count remain unchanged.
"""
from __future__ import annotations
import argparse
import hashlib
import struct
from pathlib import Path
import pefile
from keystone import KS_ARCH_X86, KS_MODE_64, Ks
EXPECTED_SHA256 = "0d582f75aca9ee30d09c9a78ba73cdc19eb99b29c8b36b9fcf3b82fa318a42f6"
CALL_SITE_RVA = 0x0024724F
ORIGINAL_TARGET_RVA = 0x002D24D0
EXPECTED_CALL_BYTES = bytes.fromhex("e87cb20800")
CORRUPTION_CHECK_RVA = 0x00067249
EXPECTED_CORRUPTION_CHECK_BYTES = bytes.fromhex("0f84010d0000")
DISABLED_CORRUPTION_CHECK_BYTES = bytes.fromhex("909090909090")
CODE_CAVE_SECTION_NAME = b"_RDATA"
CODE_CAVE_OFFSET_IN_SECTION = 0x8030
CODE_CAVE_CAPACITY = 0x1D0
IMAGE_SCN_MEM_EXECUTE = 0x20000000
HORIZONTAL_COMPLETION_MINIMUM = 0.90
def align_up(value: int, alignment: int) -> int:
"""Round a non-negative integer upward to an alignment boundary.
Args:
value: Byte offset or byte count to align.
alignment: Positive power-of-two boundary.
Returns:
The least aligned integer greater than or equal to value.
"""
assert value >= 0
assert alignment > 0 and alignment & (alignment - 1) == 0
return (value + alignment - 1) & ~(alignment - 1)
def sha256_file(path: Path) -> str:
"""Compute the SHA-256 digest of a file.
Args:
path: File whose bytes are hashed.
Returns:
Lowercase hexadecimal SHA-256 digest.
"""
digest = hashlib.sha256()
with path.open("rb") as file_handle:
for chunk in iter(lambda: file_handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def assemble_hook(hook_va: int, original_target_va: int) -> bytes:
"""Assemble the x86-64 constant-speed movement wrapper.
Args:
hook_va: Runtime virtual address of the wrapper's first byte.
original_target_va: Runtime virtual address of walk_manifold_move_by.
Returns:
Machine code for the wrapper.
"""
threshold_bits = struct.unpack("<I", struct.pack("<f", HORIZONTAL_COMPLETION_MINIMUM))[0]
assembly = f"""
sub rsp, 0x88
mov qword ptr [rsp + 0x20], rcx
mov qword ptr [rsp + 0x28], rdx
mov qword ptr [rsp + 0x30], r8
movss dword ptr [rsp + 0x38], xmm3
mov rax, qword ptr [rdx]
mov qword ptr [rsp + 0x40], rax
mov eax, dword ptr [rdx + 8]
mov dword ptr [rsp + 0x48], eax
call {original_target_va:#x}
mov word ptr [rsp + 0x3c], ax
test al, al
jz return_first
mov rdx, qword ptr [rsp + 0x28]
mov rax, qword ptr [rdx]
mov qword ptr [rsp + 0x50], rax
mov eax, dword ptr [rdx + 8]
mov dword ptr [rsp + 0x58], eax
movss xmm4, dword ptr [rdx + 8]
subss xmm4, dword ptr [rsp + 0x48]
mulss xmm4, xmm4
xorps xmm5, xmm5
ucomiss xmm4, xmm5
jbe return_first
movq xmm0, qword ptr [rsp + 0x30]
movaps xmm1, xmm0
mulps xmm1, xmm1
movaps xmm5, xmm1
shufps xmm5, xmm5, 0x55
addss xmm1, xmm5
xorps xmm5, xmm5
ucomiss xmm1, xmm5
jbe return_first
movss xmm2, dword ptr [rdx]
subss xmm2, dword ptr [rsp + 0x40]
mulss xmm2, xmm2
movss xmm3, dword ptr [rdx + 4]
subss xmm3, dword ptr [rsp + 0x44]
mulss xmm3, xmm3
addss xmm2, xmm3
movaps xmm5, xmm1
mov eax, {threshold_bits:#x}
movd xmm3, eax
mulss xmm5, xmm3
ucomiss xmm2, xmm5
jb return_first
movaps xmm3, xmm2
addss xmm3, xmm4
ucomiss xmm3, xmm1
jbe return_first
divss xmm1, xmm3
sqrtss xmm1, xmm1
shufps xmm1, xmm1, 0
mulps xmm0, xmm1
movq r8, xmm0
mov rcx, qword ptr [rsp + 0x20]
mov rdx, qword ptr [rsp + 0x28]
mov rax, qword ptr [rsp + 0x40]
mov qword ptr [rdx], rax
mov eax, dword ptr [rsp + 0x48]
mov dword ptr [rdx + 8], eax
movss xmm3, dword ptr [rsp + 0x38]
call {original_target_va:#x}
test al, al
jnz return_second
mov rdx, qword ptr [rsp + 0x28]
mov rax, qword ptr [rsp + 0x50]
mov qword ptr [rdx], rax
mov eax, dword ptr [rsp + 0x58]
mov dword ptr [rdx + 8], eax
return_first:
movzx eax, word ptr [rsp + 0x3c]
return_second:
add rsp, 0x88
ret
"""
assembler = Ks(KS_ARCH_X86, KS_MODE_64)
encoding, _ = assembler.asm(assembly, addr=hook_va)
code = bytes(encoding)
assert code.startswith(bytes.fromhex("4881ec88000000"))
assert code.endswith(bytes.fromhex("4881c488000000c3"))
return code
def build_unwind_info() -> bytes:
"""Build Windows x64 unwind metadata for the wrapper's stack allocation.
Args:
None.
Returns:
Eight-byte UNWIND_INFO structure for `sub rsp, 0x88`.
"""
unwind_info = bytes.fromhex("0107020007011100")
assert len(unwind_info) == 8
return unwind_info
def find_section(pe: pefile.PE, name: bytes) -> pefile.SectionStructure:
"""Find a PE section by its unpadded name.
Args:
pe: Parsed PE image.
name: Section name without trailing NUL bytes.
Returns:
Matching PE section structure.
"""
matches = [section for section in pe.sections if section.Name.rstrip(b"\0") == name]
if len(matches) != 1:
raise ValueError(f"Expected exactly one {name!r} section; found {len(matches)}")
return matches[0]
def patch_executable(source_path: Path, destination_path: Path) -> dict[str, int | str]:
"""Create a structurally conservative patched executable.
Args:
source_path: Original executable matching EXPECTED_SHA256.
destination_path: Path that receives the patched executable.
Returns:
Patch metadata and output digest.
"""
source_digest = sha256_file(source_path)
if source_digest != EXPECTED_SHA256:
raise ValueError(f"Unsupported executable SHA-256: {source_digest}; expected {EXPECTED_SHA256}")
image = bytearray(source_path.read_bytes())
original_size = len(image)
pe = pefile.PE(data=bytes(image))
image_base = int(pe.OPTIONAL_HEADER.ImageBase)
call_site_offset = pe.get_offset_from_rva(CALL_SITE_RVA)
actual_call = bytes(image[call_site_offset:call_site_offset + 5])
if actual_call != EXPECTED_CALL_BYTES:
raise ValueError(f"Unexpected call-site bytes at RVA {CALL_SITE_RVA:#x}: {actual_call.hex()}")
cave_section = find_section(pe, CODE_CAVE_SECTION_NAME)
cave_raw = int(cave_section.PointerToRawData) + CODE_CAVE_OFFSET_IN_SECTION
cave_rva = int(cave_section.VirtualAddress) + CODE_CAVE_OFFSET_IN_SECTION
cave_end = cave_raw + CODE_CAVE_CAPACITY
if cave_end > int(cave_section.PointerToRawData) + int(cave_section.SizeOfRawData):
raise ValueError("Configured code cave exceeds the existing section's raw data")
if any(image[cave_raw:cave_end]):
raise ValueError("Configured code cave is not empty in this executable")
hook_va = image_base + cave_rva
original_va = image_base + ORIGINAL_TARGET_RVA
hook_code = assemble_hook(hook_va, original_va)
unwind_info = build_unwind_info()
unwind_offset = align_up(len(hook_code), 4)
payload = hook_code + bytes(unwind_offset - len(hook_code)) + unwind_info
if len(payload) > CODE_CAVE_CAPACITY:
raise ValueError(f"Hook payload needs {len(payload)} bytes; cave has {CODE_CAVE_CAPACITY}")
image[cave_raw:cave_raw + len(payload)] = payload
cave_virtual_size_offset = cave_section.get_file_offset() + 8
cave_virtual_size = max(int(cave_section.Misc_VirtualSize), CODE_CAVE_OFFSET_IN_SECTION + len(payload))
if cave_virtual_size > int(cave_section.SizeOfRawData):
raise ValueError("Hook payload extends past the existing section's raw data")
struct.pack_into("<I", image, cave_virtual_size_offset, cave_virtual_size)
characteristics_offset = cave_section.get_file_offset() + 36
characteristics = int(cave_section.Characteristics) | IMAGE_SCN_MEM_EXECUTE
struct.pack_into("<I", image, characteristics_offset, characteristics)
exception_directory = pe.OPTIONAL_HEADER.DATA_DIRECTORY[3]
pdata_section = find_section(pe, b".pdata")
old_exception_size = int(exception_directory.Size)
runtime_entry_rva = int(exception_directory.VirtualAddress) + old_exception_size
runtime_entry_raw = pe.get_offset_from_rva(runtime_entry_rva)
pdata_raw_end = int(pdata_section.PointerToRawData) + int(pdata_section.SizeOfRawData)
if runtime_entry_raw + 12 > pdata_raw_end:
raise ValueError("The .pdata section has no room for wrapper unwind metadata")
if any(image[runtime_entry_raw:runtime_entry_raw + 12]):
raise ValueError("The intended .pdata append slot is not empty")
runtime_function = struct.pack("<III", cave_rva, cave_rva + len(hook_code), cave_rva + unwind_offset)
image[runtime_entry_raw:runtime_entry_raw + 12] = runtime_function
exception_size_offset = exception_directory.get_field_absolute_offset("Size")
struct.pack_into("<I", image, exception_size_offset, old_exception_size + 12)
pdata_virtual_size_offset = pdata_section.get_file_offset() + 8
new_pdata_virtual_size = max(int(pdata_section.Misc_VirtualSize), runtime_entry_rva + 12 - int(pdata_section.VirtualAddress))
struct.pack_into("<I", image, pdata_virtual_size_offset, new_pdata_virtual_size)
call_site_va = image_base + CALL_SITE_RVA
displacement = hook_va - (call_site_va + 5)
if not -(1 << 31) <= displacement < (1 << 31):
raise ValueError("Wrapper lies outside rel32 call range")
image[call_site_offset:call_site_offset + 5] = b"\xE8" + struct.pack("<i", displacement)
corruption_check_offset = pe.get_offset_from_rva(CORRUPTION_CHECK_RVA)
actual_corruption_check = bytes(
image[corruption_check_offset:corruption_check_offset + len(EXPECTED_CORRUPTION_CHECK_BYTES)]
)
if actual_corruption_check != EXPECTED_CORRUPTION_CHECK_BYTES:
raise ValueError(
f"Unexpected corruption-check bytes at RVA {CORRUPTION_CHECK_RVA:#x}: "
f"{actual_corruption_check.hex()}"
)
image[
corruption_check_offset:corruption_check_offset + len(DISABLED_CORRUPTION_CHECK_BYTES)
] = DISABLED_CORRUPTION_CHECK_BYTES
checksum_offset = pe.OPTIONAL_HEADER.get_field_absolute_offset("CheckSum")
struct.pack_into("<I", image, checksum_offset, int(pe.OPTIONAL_HEADER.CheckSum))
assert len(image) == original_size
destination_path.write_bytes(image)
patched_pe = pefile.PE(str(destination_path))
if int(patched_pe.FILE_HEADER.NumberOfSections) != int(pe.FILE_HEADER.NumberOfSections):
raise AssertionError("Section count changed unexpectedly")
if int(patched_pe.OPTIONAL_HEADER.SizeOfImage) != int(pe.OPTIONAL_HEADER.SizeOfImage):
raise AssertionError("SizeOfImage changed unexpectedly")
if destination_path.stat().st_size != source_path.stat().st_size:
raise AssertionError("File size changed unexpectedly")
return {
"source_sha256": source_digest,
"output_sha256": sha256_file(destination_path),
"hook_rva": cave_rva,
"hook_size": len(hook_code),
"unwind_rva": cave_rva + unwind_offset,
"file_size": original_size,
"number_of_sections": int(patched_pe.FILE_HEADER.NumberOfSections),
"size_of_image": int(patched_pe.OPTIONAL_HEADER.SizeOfImage),
"code_cave_virtual_size": cave_virtual_size,
"pe_checksum_preserved": int(patched_pe.OPTIONAL_HEADER.CheckSum),
"corruption_check_rva": CORRUPTION_CHECK_RVA,
}
def main() -> None:
"""Parse command-line paths and write the patched executable.
Args:
None.
Returns:
None.
"""
parser = argparse.ArgumentParser()
parser.add_argument("source", type=Path)
parser.add_argument("destination", type=Path)
arguments = parser.parse_args()
if arguments.source.resolve() == arguments.destination.resolve():
raise ValueError("Source and destination paths must differ")
metadata = patch_executable(arguments.source, arguments.destination)
for key, value in metadata.items():
rendered = f"{value:#x}" if isinstance(value, int) else value
print(f"{key}: {rendered}")
if __name__ == "__main__":
main()