"""
Escreve um byte 0xCC (INT3) diretamente na memoria de um processo, SEM anexar um debugger de
verdade -- evita o problema de travar a janela DirectX que tivemos com x32dbg/cdb.

Como o Windows tem LocalDumps configurado (HKLM\\...\\Windows Error Reporting\\LocalDumps) pro
AMo.exe, quando o INT3 disparar sem debugger anexado, ele vira uma excecao nao tratada normal e o
Windows salva um dump completo automaticamente em D:\\RoshEmulator\\captures\\crashdumps\\.

Uso:
    python patch_int3.py <pid> <endereco_hex>

O patch e' so na memoria (nao no arquivo em disco) -- se o processo for reaberto, volta ao normal.
"""
import ctypes
import ctypes.wintypes as wintypes
import sys

PROCESS_ALL_ACCESS = 0x1F0FFF
PAGE_EXECUTE_READWRITE = 0x40

def main():
    pid = int(sys.argv[1])
    addr = int(sys.argv[2], 16)

    kernel32 = ctypes.windll.kernel32
    hProcess = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
    if not hProcess:
        print("OpenProcess falhou:", ctypes.GetLastError())
        return 1

    orig = ctypes.create_string_buffer(1)
    bytesRead = ctypes.c_size_t(0)
    ok = kernel32.ReadProcessMemory(hProcess, ctypes.c_void_p(addr), orig, 1, ctypes.byref(bytesRead))
    if not ok:
        print("ReadProcessMemory falhou:", ctypes.GetLastError())
        return 1
    print(f"byte original em {addr:#x}: {orig.raw.hex()}")

    old_protect = wintypes.DWORD(0)
    ok = kernel32.VirtualProtectEx(hProcess, ctypes.c_void_p(addr), 1, PAGE_EXECUTE_READWRITE, ctypes.byref(old_protect))
    if not ok:
        print("VirtualProtectEx falhou:", ctypes.GetLastError())
        return 1

    patch = ctypes.create_string_buffer(b"\xCC", 1)
    bytesWritten = ctypes.c_size_t(0)
    ok = kernel32.WriteProcessMemory(hProcess, ctypes.c_void_p(addr), patch, 1, ctypes.byref(bytesWritten))
    print("patch escrito:", bool(ok), "bytes:", bytesWritten.value)

    # restaura protecao original
    kernel32.VirtualProtectEx(hProcess, ctypes.c_void_p(addr), 1, old_protect, ctypes.byref(old_protect))

    # confirma
    check = ctypes.create_string_buffer(1)
    kernel32.ReadProcessMemory(hProcess, ctypes.c_void_p(addr), check, 1, ctypes.byref(bytesRead))
    print(f"byte apos patch: {check.raw.hex()}")

    kernel32.CloseHandle(hProcess)
    return 0

if __name__ == "__main__":
    sys.exit(main())
