import ctypes
from ctypes import wintypes
import struct
import re

PROCESS_VM_READ = 0x0010
PROCESS_QUERY_INFORMATION = 0x0400

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
OpenProcess = kernel32.OpenProcess
OpenProcess.restype = wintypes.HANDLE
OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD]

ReadProcessMemory = kernel32.ReadProcessMemory
ReadProcessMemory.restype = wintypes.BOOL
ReadProcessMemory.argtypes = [wintypes.HANDLE, wintypes.LPCVOID, wintypes.LPVOID, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)]

CloseHandle = kernel32.CloseHandle
CloseHandle.restype = wintypes.BOOL
CloseHandle.argtypes = [wintypes.HANDLE]

pid = 39484
h_proc = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, False, pid)

base = 0x7FF6AFC20000
text_start = base + 0x1000
text_size = 0x2E85000

targets = {
    0x7FF6B31CD070: "FogOfWar_2",
    0x7FF6B31CD2B8: "FogOfWarAdd",
    0x7FF6B2DAD670: "FogOfWar_1",
    0x7FF6B2DAD87D: "FogOfWar_3",
}

target_set = set(targets.keys())

chunk_size = 4 * 1024 * 1024
buf = ctypes.create_string_buffer(chunk_size)
bytes_read = ctypes.c_size_t(0)

# Check 48/4C 8B/8D/83/89
pattern = re.compile(rb'[\x48\x4C][\x8B\x8D]')

print("Scanning for FogOfWar references in .text...")
for offset in range(0, text_size, chunk_size - 16):
    cur_addr = text_start + offset
    n = min(chunk_size, text_size - offset)
    if ReadProcessMemory(h_proc, ctypes.c_void_p(cur_addr), buf, n, ctypes.byref(bytes_read)):
        data = bytes(buf)[:bytes_read.value]
        for m in pattern.finditer(data):
            pos = m.start()
            if pos + 7 <= len(data):
                disp = struct.unpack('<i', data[pos+3:pos+7])[0]
                insn_addr = cur_addr + pos
                rip_next = insn_addr + 7
                dest = rip_next + disp
                if dest in target_set:
                    print(f"Hit @ 0x{insn_addr:016X} -> {targets[dest]} (0x{dest:016X})")

CloseHandle(h_proc)
print("Done.")
