#!/usr/bin/env python3
"""Watch for a (re)launched FIFA17.exe and auto-apply both ProtoSSL cert patches
the moment its unpacked code is mapped. Idempotent; keeps watching across relaunches."""
import glob, time, struct

# Watch for a (re)launched FIFA17.exe and auto-apply ProtoSSL cert + FUT store patches
import glob, time, os

GATE2=0x1461361b0; GATE2_ORIG=bytes.fromhex("48895c"); GATE2_PATCH=bytes.fromhex("31c0c3")
GATE1=0x146132548; GATE1_ORIG=bytes.fromhex("0f8576010000"); GATE1_PATCH=bytes.fromhex("90"*6)

RET_TRUE = bytes.fromhex("b801000000c3")
NOP2 = bytes.fromhex("9090")
IMG_BASE = 0x180000000

STORE_PATCHES = {
    0x1800f7fb0: RET_TRUE,
    0x1800fb850: RET_TRUE,
    0x180100500: RET_TRUE,
    0x180013cf0: RET_TRUE,
    0x180017543: bytes.fromhex("eb3f"),
    0x180017487: NOP2,
    0x180017490: NOP2,
    0x1800175aa: NOP2,
}

LOG="/tmp/autopatch.log"

def log(m):
    line=f"[{time.strftime('%H:%M:%S')}] {m}"
    print(line,flush=True); open(LOG,"a").write(line+"\n")

def find_pids():
    out=[]
    for d in glob.glob('/proc/[0-9]*'):
        try:
            if open(d+'/comm').read().strip()=='FIFA17.exe': out.append(int(d.split('/')[-1]))
        except: pass
    return out

def cardsdll_base(pid):
    try:
        for line in open(f'/proc/{pid}/maps'):
            if 'CardsDLL' in line: return int(line.split('-')[0], 16)
    except: pass
    return None

def rd(pid,va,n):
    with open(f'/proc/{pid}/mem','rb') as f:
        f.seek(va); return f.read(n)
def wr(pid,va,b):
    with open(f'/proc/{pid}/mem','r+b') as f:
        f.seek(va); f.write(b)

patched=set()
store_patched=set()

log("=== AUTOPATCH watching for FIFA17.exe ===")
while True:
    for pid in find_pids():
        if pid not in patched:
            try:
                g2=rd(pid,GATE2,3); g1=rd(pid,GATE1,6)
            except Exception:
                continue  # code not mapped yet
            if g2==GATE2_PATCH and g1==GATE1_PATCH:
                log(f"pid {pid}: cert gates already patched"); patched.add(pid)
            elif g2==GATE2_ORIG and g1==GATE1_ORIG:
                try:
                    wr(pid,GATE2,GATE2_PATCH); wr(pid,GATE1,GATE1_PATCH)
                    log(f"pid {pid}: PATCHED cert gates")
                    patched.add(pid)
                except Exception as e:
                    log(f"pid {pid}: cert patch write failed: {e}")

        # Continuously enforce store patches every tick
        cbase = cardsdll_base(pid)
        if cbase is not None:
            try:
                for va, data in STORE_PATCHES.items():
                    live = cbase + (va - IMG_BASE)
                    if rd(pid, live, len(data)) != data:
                        wr(pid, live, data)
                        log(f"pid {pid}: ENFORCED store patch @ {live:#x}")
                if pid not in store_patched:
                    log(f"pid {pid}: PATCHED store gates in CardsDLL @ {cbase:#x}")
                    store_patched.add(pid)
            except Exception as e:
                log(f"pid {pid}: store patch write failed: {e}")

    time.sleep(1)
