Windows系统中如何对被其他程序占用的文件执行写入操作?
实现思路(Rust优先)
前置要求
所有操作都需要程序以管理员权限运行,且开启SeDebugPrivilege特权,否则无法枚举系统全局句柄、访问其他进程资源。上述特权的Rust实现参考代码:
use winapi::um::securitybaseapi::{AdjustTokenPrivileges, LookupPrivilegeValueW}; use winapi::um::processthreadsapi::{OpenProcessToken, GetCurrentProcess}; use winapi::um::winnt::{SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, TOKEN_QUERY}; use winapi::um::handleapi::CloseHandle; unsafe fn enable_debug_privilege() -> bool { let mut token = std::ptr::null_mut(); if OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &mut token, ) == 0 { return false; } let mut luid = std::mem::zeroed(); if LookupPrivilegeValueW(std::ptr::null(), SE_DEBUG_NAME, &mut luid) == 0 { CloseHandle(token); return false; } let mut tp = winapi::um::winnt::TOKEN_PRIVILEGES { PrivilegeCount: 1, Privileges: [winapi::um::winnt::LUID_AND_ATTRIBUTES { Luid: luid, Attributes: SE_PRIVILEGE_ENABLED, }], }; let ret = AdjustTokenPrivileges( token, 0, &mut tp, std::mem::size_of_val(&tp) as u32, std::ptr::null_mut(), std::ptr::null_mut() ); CloseHandle(token); ret != 0 && winapi::um::errhandlingapi::GetLastError() == 0 }
步骤1:查找目标文件对应的句柄
核心依赖ntapi和winapi两个crate,实现逻辑如下:
- 调用
NtQuerySystemInformation,传入SystemHandleInformation(值为16)参数,获取系统全局所有句柄的列表,注意需要动态调整缓冲区大小直到API返回成功 - 遍历所有句柄,筛选类型为
File的句柄:先调用OpenProcess打开句柄所属进程,获取PROCESS_DUP_HANDLE权限,再调用DuplicateHandle将目标进程的句柄复制到当前进程 - 对复制到当前进程的句柄调用
GetFinalPathNameByHandleW,获取对应的文件绝对路径,和你要操作的目标文件路径匹配,匹配成功则记录该句柄所属的进程ID、原句柄值
注意:
NtQuerySystemInformation属于Windows未公开的Native API,不同Windows版本的结构体定义、参数可能存在差异,使用时需要做好多版本兼容测试。
步骤2:强制关闭跨进程文件句柄
无需远程注入目标进程,直接调用DuplicateHandle传入指定标志即可关闭目标进程的句柄,Rust实现逻辑:
- 调用
OpenProcess打开目标进程,获取PROCESS_DUP_HANDLE权限 - 调用
DuplicateHandle,参数依次传入:目标进程句柄、要关闭的源句柄值、当前进程句柄、空指针接收新句柄、0、FALSE、DUPLICATE_CLOSE_SOURCE(值为1)标志 - 调用成功后,目标进程内的对应文件句柄会被直接关闭
强制关闭句柄后目标程序的行为
程序后续对已关闭的句柄执行任何读写、刷新、关闭操作时,都会收到ERROR_INVALID_HANDLE(错误码6)的报错,具体表现取决于程序自身的错误处理逻辑:
- 记事本:记事本打开文件时会将全部内容读取到内存,打开完成后就不再使用原句柄,直到用户触发保存操作。强制关闭其句柄后,记事本当前编辑的内容不会受影响,用户点击保存时会重新打开文件获取新句柄写入,会直接覆盖你对原文件做出的修改,不会触发报错。
- Word:Word打开文件后会长期持有文件句柄,且会定期执行自动保存、元数据同步、临时文件校验等后台操作。强制关闭其句柄后,大概率会立刻弹出文件访问错误的提示,用户点击保存时会直接失败,部分版本会要求用户另存为新文件,不会覆盖你对原文件的修改,极端情况下会出现程序崩溃。
- 其他流式读取类程序(如视频播放器、日志采集工具):关闭句柄后会直接中断当前读取操作,弹出文件读取失败的提示。
内容的提问来源于stack exchange,提问作者thegrinderguy
相关产品推荐
相关产品推荐

