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 32572 (BoCuaCacCon):
# Sinh Lực (HP): 3215 (Max 3215)
# Nội Lực (Mana): 924 (Max 924, or cur ~853)
# Thể Lực (Stamina): 846 (Max 846)
pid = 32572
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
pat_hp = struct.pack('<i', 3215)

print(f"=== TÌM KIẾM CẤU TRÚC CHỈ SỐ CHÍNH XÁC CỦA BOCUACACCON (PID {pid}) ===")
print("Kỳ vọng: HP=3215, MaxMana=924, MaxStamina=846")

matches = []

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)
        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]
            idx = 0
            while True:
                idx = data.find(pat_hp, idx)
                if idx == -1: break
                m_addr = addr + idx
                
                # Check surrounding 128 bytes
                surrounding = data[max(0, idx - 64):min(len(data), idx + 64)]
                has_924 = struct.pack('<i', 924) in surrounding
                has_846 = struct.pack('<i', 846) in surrounding
                
                if has_924 or has_846:
                    print(f"\n[KHỚP CẤU TRÚC] tại RAM 0x{m_addr:08X}:")
                    # Dump 32 integers around match
                    dump_start = max(0, idx - 48)
                    for k in range(dump_start, min(len(data)-4, idx + 64), 4):
                        cur_addr = addr + k
                        rel = cur_addr - m_addr
                        val = struct.unpack_from('<i', data, k)[0]
                        tag = ""
                        if val == 3215: tag = " <=== SINH LỰC (HP: 3215)"
                        elif val == 924: tag = " <=== NỘI LỰC TỐI ĐA (Max Mana: 924)"
                        elif val == 846: tag = " <=== THỂ LỰC (Stamina: 846)"
                        elif val >= 800 and val <= 924: tag = f" <=== NỘI LỰC HIỆN TẠI? ({val})"
                        print(f"  0x{cur_addr:08X} [{rel:+04d}]: {val:<8} {tag}")
                    matches.append(m_addr)
                    
                idx += 4
                
    addr += mbi.RegionSize
    if addr >= 0x7FFFFFFF: break

kernel32.CloseHandle(hProc)
print(f"\nTổng số vùng cấu trúc tìm thấy: {len(matches)}")
