"""
Acha o endereco base (load address) de um modulo (DLL) carregado dentro de um processo alvo,
via CreateToolhelp32Snapshot(TH32CS_SNAPMODULE). Necessario porque o kernel32.dll/ucrtbase.dll de
32-bit usados pelo AMo.exe (rodando sob WOW64) tem base DIFERENTE do kernel32.dll de 64-bit do
nosso proprio python.exe -- nao da pra so usar GetModuleHandle local.

Uso:
    python find_module_base.py <pid> <nome_dll_parcial>
"""
import ctypes
import ctypes.wintypes as wintypes
import sys

TH32CS_SNAPMODULE = 0x00000008
TH32CS_SNAPMODULE32 = 0x00000010
MAX_MODULE_NAME32 = 255
MAX_PATH = 260


class MODULEENTRY32(ctypes.Structure):
    _fields_ = [
        ("dwSize", wintypes.DWORD),
        ("th32ModuleID", wintypes.DWORD),
        ("th32ProcessID", wintypes.DWORD),
        ("GlblcntUsage", wintypes.DWORD),
        ("ProccntUsage", wintypes.DWORD),
        ("modBaseAddr", ctypes.POINTER(ctypes.c_byte)),
        ("modBaseSize", wintypes.DWORD),
        ("hModule", wintypes.HMODULE),
        ("szModule", ctypes.c_char * (MAX_MODULE_NAME32 + 1)),
        ("szExePath", ctypes.c_char * MAX_PATH),
    ]


def find_module_base(pid, name_substr):
    kernel32 = ctypes.windll.kernel32
    snap = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid)
    if snap == -1:
        raise OSError(f"CreateToolhelp32Snapshot falhou: {ctypes.GetLastError()}")

    entry = MODULEENTRY32()
    entry.dwSize = ctypes.sizeof(MODULEENTRY32)
    results = []
    if kernel32.Module32First(snap, ctypes.byref(entry)):
        while True:
            name = entry.szModule.decode("ascii", "ignore")
            if name_substr.lower() in name.lower():
                base = ctypes.cast(entry.modBaseAddr, ctypes.c_void_p).value
                results.append((name, base, entry.modBaseSize))
            if not kernel32.Module32Next(snap, ctypes.byref(entry)):
                break
    kernel32.CloseHandle(snap)
    return results


if __name__ == "__main__":
    pid = int(sys.argv[1])
    name_substr = sys.argv[2]
    for name, base, size in find_module_base(pid, name_substr):
        print(f"{name}: base={base:#x} size={size:#x}")
