本文介绍在 Windows 系统上实现使某个文件无法被用户或其他程序删除。

实现的原理大致如下:

通过DuplicateHandle拷贝文件句柄给另外一个进程(一般是系统进程),因为系统进程不会被关闭,所以达到了占用某个文件,不让其他进程删除、读取、写入等。

DuplicateHandle的用法参考:- Windows内核对象

因为需要拷贝文件句柄给系统进程,所以涉及到打开系统进程,可能需要提权操作,一般授权给进程SE_DEBUG_NAME权限即可。

实现一个用于锁住文件的函数LockFile,将文件句柄复制给系统csrss.exe进程,函数实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
bool LockFile(LPCTSTR lpFilePath) {
if (lpFilePath == NULL)
return false;

// 查找进程csrss.exe
//
DWORD dwCsrssProcessID = 0;
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

while (Process32Next(hSnapShot, &pe)) {
if (lstrcmpi(pe.szExeFile, TEXT("csrss.exe")) == 0) {
dwCsrssProcessID = pe.th32ProcessID;
break;
}
}

CloseHandle(hSnapShot);

// 未找到
if (dwCsrssProcessID == 0) {
return false;
}

HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwCsrssProcessID);

// 打开失败,可能是当前进程未提权导致,需要提前进行提权操作
if (hProcess == NULL) {
return false;
}

HANDLE hFile = CreateFile(lpFilePath,
GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (hFile == INVALID_HANDLE_VALUE) {
CloseHandle(hProcess);
return false;
}

HANDLE hTargetHandle = INVALID_HANDLE_VALUE;
BOOL bRet = DuplicateHandle(GetCurrentProcess(),
hFile,
hProcess,
&hTargetHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE
);
CloseHandle(hProcess);

return (bRet == TRUE);
}