import sys, struct, ctypes
from ctypes import wintypes

sys.stdout.reconfigure(encoding='utf-8')
kernel32 = ctypes.windll.kernel32
advapi32 = ctypes.windll.advapi32

def enable_debug():
    hToken = wintypes.HANDLE()
    if advapi32.OpenProcessToken(kernel32.GetCurrentProcess(), 0x0020 | 0x0008, ctypes.byref(hToken)):
        luid = wintypes.LARGE_INTEGER()
        if advapi32.LookupPrivilegeValueW(None, "SeDebugPrivilege", ctypes.byref(luid)):
            class TP(ctypes.Structure):
                _fields_ = [('Count', wintypes.DWORD), ('Luid', wintypes.LARGE_INTEGER), ('Attr', wintypes.DWORD)]
            tp = TP(1, luid, 2)
            advapi32.AdjustTokenPrivileges(hToken, False, ctypes.byref(tp), ctypes.sizeof(tp), None, None)
        kernel32.CloseHandle(hToken)
enable_debug()

class MEMORY_BASIC_INFORMATION(ctypes.Structure):
    _fields_ = [
        ('BaseAddress', ctypes.c_void_p),
        ('AllocationBase', ctypes.c_void_p),
        ('AllocationProtect', wintypes.DWORD),
        ('RegionSize', ctypes.c_size_t),
        ('State', wintypes.DWORD),
        ('Protect', wintypes.DWORD),
        ('Type', wintypes.DWORD),
    ]

# PID 30076: MeCuaCacCon
# HP: 548, MaxHP: 548, MP: 2455, MaxMP: 2455, Sta: 709, MaxSta: 709
pid = 30076
hProc = kernel32.OpenProcess(0x0010 | 0x0400, False, pid)
if not hProc:
    print(f"Cannot open PID {pid}")
    sys.exit(1)

mbi = MEMORY_BASIC_INFORMATION()
addr = 0
found_blocks = []

print(f"Scanning PID {pid} (MeCuaCacCon) for HP=548, MP=2455, Sta=709...")

while kernel32.VirtualQueryEx(hProc, ctypes.c_void_p(addr), ctypes.byref(mbi), ctypes.sizeof(mbi)):
    if mbi.State == 0x1000 and (mbi.Protect & 0xEE) != 0 and (mbi.Protect & 0x01) == 0:
        size = min(mbi.RegionSize, 1024 * 1024 * 8) # 8MB
        buf = (ctypes.c_char * size)()
        bytesRead = ctypes.c_size_t()
        
        if kernel32.ReadProcessMemory(hProc, ctypes.c_void_p(addr), buf, size, ctypes.byref(bytesRead)):
            data = bytes(buf)[:bytesRead.value]
            
            # Pattern A: 548, 548 (HP, MaxHP) as 4-byte ints
            pat1 = struct.pack('<ii', 548, 548)
            idx = 0
            while True:
                idx = data.find(pat1, idx)
                if idx == -1:
                    break
                match_addr = addr + idx
                
                # Check around this match for 2455 (MP) or 709 (Sta)
                surrounding = data[max(0, idx-64):min(len(data), idx+128)]
                has_mp = struct.pack('<i', 2455) in surrounding
                has_sta = struct.pack('<i', 709) in surrounding
                
                # Read 16 ints around match
                ints_after = struct.unpack_from('<8i', data, idx)
                print(f"  [HP MATCH] at 0x{match_addr:08X} | Integers: {ints_after} | has_mp={has_mp} | has_sta={has_sta}")
                found_blocks.append((match_addr, ints_after, has_mp, has_sta))
                idx += 4

    addr += mbi.RegionSize
    if addr >= 0x7FFFFFFF:
        break

kernel32.CloseHandle(hProc)
print(f"Total HP candidate matches: {len(found_blocks)}")
