Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 deletions win/tools/autopatch/autopatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import subprocess
import sys
import tempfile
import urllib.error
import urllib.request
import xml.etree.ElementTree as ET
from binascii import unhexlify
Expand Down Expand Up @@ -53,17 +54,19 @@ def parse_args():
parser.add_argument("-S", "--search",
nargs="+",
default=[
"8BF04533FF85C0",
"8985ECFBFFFF85C08B85DCFBFFFF7504",
"8BF04533FF85C0,8BF085C0750549892FEB",
"8985ECFBFFFF85C08B85DCFBFFFF7504,89450885C08B450C7504",
],
help="representation of search pattern(s) binary string")
help="representation of search pattern(s) binary string. "
"Separate fallback alternatives with commas")
parser.add_argument("-R", "--replacement",
nargs="+",
default=[
"33C08BF04533FF",
"31C08985ECFBFFFF8B85DCFBFFFF7504",
"33C08BF04533FF,33C08BF0750549892FEB",
"31C08985ECFBFFFF8B85DCFBFFFF7504,33C08945088B450C7504",
],
help="representation of replacement(s) binary string")
help="representation of replacement(s) binary string. "
"Fallback alternatives must match search order")
parser.add_argument("-o", "--stdout",
action="store_true",
help="output into stdout")
Expand Down Expand Up @@ -143,6 +146,10 @@ def extract_single_file(archive, filename, *, sevenzip="7z"):
return result


def parse_binary_alternatives(value):
return [unhexlify(item) for item in value.split(',')]


def make_patch(archive, *,
arch_tgt,
search,
Expand All @@ -163,11 +170,19 @@ def make_patch(archive, *,
f = fo.read()
else:
f = expand(tgt, sevenzip=sevenzip)
offset = f.find(search)
if offset == -1:
matches = []
for pattern, patched_pattern in zip(search, replacement):
offset = f.find(pattern)
if offset == -1:
continue
if f[offset + len(pattern):].find(pattern) != -1:
raise MultipleOccurencesException("Multiple occurences of pattern found!")
matches.append((offset, pattern, patched_pattern))
if not matches:
raise PatternNotFoundException("Pattern not found.")
if f[offset + len(search):].find(search) != -1:
raise MultipleOccurencesException("Multiple occurences of pattern found!")
if len(matches) > 1:
raise MultipleOccurencesException("Multiple fallback patterns found!")
offset, search, replacement = matches[0]
del f
print("Pattern found @ %016X" % (offset,), file=sys.stderr)

Expand All @@ -183,8 +198,10 @@ def identify_driver(archive, *, sevenzip="7z"):
manifest = extract_single_file(archive, "setup.cfg", sevenzip=sevenzip)
root = ET.fromstring(manifest)
version = root.attrib['version']
product_type = root.find('./properties/string[@name="ProductType"]') \
.attrib['value']
product_type_element = root.find('./properties/string[@name="ProductType"]')
if product_type_element is None:
raise UnknownPlatformException("Can't find ProductType in setup.cfg")
product_type = product_type_element.attrib['value']
return version, product_type


Expand All @@ -197,9 +214,11 @@ def format_patch(diff, filename):

def patch_flow(installer_file, search, replacement, target, target_name, patch_name, *,
tempdir, direct=False, stdout=False, sevenzip="7z"):
search = unhexlify(search)
replacement = unhexlify(replacement)
assert len(search) == len(replacement), "len() of search and replacement is not equal"
search = parse_binary_alternatives(search)
replacement = parse_binary_alternatives(replacement)
assert len(search) == len(replacement), "count of search and replacement alternatives is not equal"
for search_item, replacement_item in zip(search, replacement):
assert len(search_item) == len(replacement_item), "len() of search and replacement is not equal"

# Check if installer file exists or try to download

Expand Down Expand Up @@ -230,7 +249,7 @@ def patch_flow(installer_file, search, replacement, target, target_name, patch_n
else:
print(f"Using downloaded file in '{file_path}'")
installer_file = file_path
except (urllib.error.URLError, Exception) as e:
except urllib.error.URLError as e:
raise InstallerNotFoundException(f"Failed to download the file: {e}")
except Exception as e:
raise InstallerNotFoundException(f"An error occurred during download: {str(e)}")
Expand Down