import ctypes
import ctypes.wintypes as w
import struct
import subprocess

k32 = ctypes.WinDLL("kernel32", use_last_error=True)
k32.OpenProcess.restype = w.HANDLE
k32.VirtualProtectEx.argtypes = [w.HANDLE, ctypes.c_void_p, ctypes.c_size_t, w.DWORD, ctypes.POINTER(w.DWORD)]
k32.VirtualProtectEx.restype = w.BOOL
k32.WriteProcessMemory.argtypes = [w.HANDLE, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)]
k32.WriteProcessMemory.restype = w.BOOL
k32.ReadProcessMemory.argtypes = [w.HANDLE, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)]
k32.ReadProcessMemory.restype = w.BOOL

out = subprocess.check_output(['powershell', '-Command', '(Get-Process -Name *PathOfExile*).Id'])
pid = int(out.decode().split()[0])
h = k32.OpenProcess(0x1F0FFF, False, pid)

addr = 0x7ff6b3229ca4
buf = (ctypes.c_ubyte * 4)()
k32.ReadProcessMemory(h, ctypes.c_void_p(addr), buf, 4, None)
orig_val = struct.unpack("<f", buf)[0]
print(f"Original float at {addr:#x}: {orig_val}")

old_prot = w.DWORD(0)
k32.VirtualProtectEx(h, ctypes.c_void_p(addr), 4, 0x40, ctypes.byref(old_prot))

# Write 8.0f
new_bytes = (ctypes.c_ubyte * 4).from_buffer_copy(struct.pack("<f", 8.0))
k32.WriteProcessMemory(h, ctypes.c_void_p(addr), new_bytes, 4, None)

# Verify read
k32.ReadProcessMemory(h, ctypes.c_void_p(addr), buf, 4, None)
cur_val = struct.unpack("<f", buf)[0]
print(f"New float at {addr:#x}: {cur_val}")

# Restore protect
k32.VirtualProtectEx(h, ctypes.c_void_p(addr), 4, old_prot.value, ctypes.byref(old_prot))
print("Protect restored successfully.")
