Python中读写其他进程标准句柄的问题及解决方法
问题原因
你代码里的win32api.GetStdHandle只能获取当前进程的标准输入/输出/错误句柄,和你通过OpenProcess打开的目标进程完全无关。如果当前进程没有关联控制台(比如用pythonw.exe运行),拿到的句柄本身就是无效的,自然会触发WriteFile的无效句柄错误。
解决方法
要操作其他进程的标准句柄,需要通过以下步骤实现:
- 调用原生Windows API
NtQueryInformationProcess获取目标进程的PEB(进程环境块)地址 - 读取目标进程内存中的PEB数据,从中提取标准句柄数组
- 使用
DuplicateHandle将目标进程的句柄复制到当前进程的句柄表中(句柄是进程私有资源,不能直接跨进程使用) - 用复制后的句柄进行读写操作
以下是修正后的代码示例:
import win32api import win32con import win32file import ctypes from ctypes import wintypes # 定义所需的结构体和API class PROCESS_BASIC_INFORMATION(ctypes.Structure): _fields_ = [ ("Reserved1", wintypes.PVOID), ("PebBaseAddress", wintypes.PVOID), ("Reserved2", wintypes.PVOID * 2), ("UniqueProcessId", wintypes.ULONG), ("Reserved3", wintypes.PVOID) ] class PEB(ctypes.Structure): _fields_ = [ ("Reserved1", wintypes.BYTE * 2), ("BeingDebugged", wintypes.BYTE), ("Reserved2", wintypes.BYTE * 1), ("Reserved3", wintypes.PVOID * 2), ("Ldr", wintypes.PVOID), ("ProcessParameters", wintypes.PVOID), ] class RTL_USER_PROCESS_PARAMETERS(ctypes.Structure): _fields_ = [ ("Reserved1", wintypes.PVOID * 16), ("Reserved2", wintypes.PVOID * 10), ("StdHandle", wintypes.HANDLE * 3), # 索引0:STD_INPUT, 1:STD_OUTPUT, 2:STD_ERROR ] ntdll = ctypes.WinDLL("ntdll.dll") ntdll.NtQueryInformationProcess.argtypes = [ wintypes.HANDLE, wintypes.ULONG, wintypes.PVOID, wintypes.ULONG, wintypes.PULONG ] ntdll.NtQueryInformationProcess.restype = wintypes.LONG # 目标进程PID pid = 4908 # 打开目标进程,需要足够权限 process_handle = win32api.OpenProcess( win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ | win32con.PROCESS_DUP_HANDLE, False, pid ) # 获取PROCESS_BASIC_INFORMATION pbi = PROCESS_BASIC_INFORMATION() return_length = wintypes.ULONG() ntdll.NtQueryInformationProcess( process_handle, 0, # ProcessBasicInformation ctypes.byref(pbi), ctypes.sizeof(pbi), ctypes.byref(return_length) ) # 读取PEB数据 peb = PEB() win32file.ReadProcessMemory( process_handle, pbi.PebBaseAddress, ctypes.byref(peb), ctypes.sizeof(peb), None ) # 读取RTL_USER_PROCESS_PARAMETERS params = RTL_USER_PROCESS_PARAMETERS() win32file.ReadProcessMemory( process_handle, peb.ProcessParameters, ctypes.byref(params), ctypes.sizeof(params), None ) # 复制目标进程的stdout句柄到当前进程 target_stdout = params.StdHandle[1] current_process = win32api.GetCurrentProcess() duplicated_handle = win32api.DuplicateHandle( process_handle, target_stdout, current_process, 0, False, win32con.DUPLICATE_SAME_ACCESS ) # 写入数据 win32file.WriteFile(duplicated_handle, b"Hello from Python!") # 关闭句柄 win32api.CloseHandle(duplicated_handle) win32api.CloseHandle(process_handle)
注意事项
- 必须以管理员权限运行脚本,否则可能因权限不足无法读取目标进程内存或复制句柄
- 目标进程必须是控制台进程,且其标准句柄已关联到控制台或其他可读写的对象(如果目标进程已重定向标准输出到文件,需确保有文件访问权限)
- 不同Windows版本的PEB结构体可能存在差异,上述代码仅适用于常见的x86/x64系统
内容的提问来源于stack exchange,提问作者user0
相关产品推荐
相关产品推荐

