能否实现文件仅对特定进程访问?现有代码仅授权父进程问题
你的目标可行,但当前代码存在核心逻辑错误:Windows文件系统的ACL是基于安全主体(用户、组、服务账户等)的SID进行权限控制的,而非进程本身的标识。你通过GetSecurityInfo获取的是目标进程的所有者SID(即运行该进程的用户账户SID),所以本质上是给该用户账户授予了权限——这就是为什么同用户的父进程能访问文件的原因,而非仅目标进程。
核心错误点
你的GetProcessSid函数返回的是进程所有者的SID,不是进程专属的标识:
GetSecurityInfo(hProcess,SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,pSID,NULL,NULL,NULL,NULL);
这行代码获取的是进程对象的所有者SID,也就是启动该进程的用户账户的SID,所有以该用户身份运行的进程都会拥有这个SID,自然都能访问文件。
实现特定进程访问文件的正确方法
要实现仅特定进程能访问文件,不能依赖用户SID,需要采用以下方案之一:
方案1:使用条件ACL(推荐,Windows 7+)
从Windows 7开始,NTFS支持条件ACL,可以在权限条目中添加条件,仅允许指定进程ID、进程路径的进程访问文件。
示例步骤:
- 创建文件时,先初始化一个拒绝所有访问的DACL。
- 创建允许访问的ACE,并添加条件(比如匹配目标进程ID或路径)。
- 将带条件的ACE添加到文件的ACL中。
关键代码片段(构造带进程ID条件的ACE):
// 假设targetProcessId是目标进程的ID WCHAR condition[256]; swprintf_s(condition, L"(ProcessId = %lu)", targetProcessId); EXPLICIT_ACCESS_W ea; ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS_W)); ea.grfAccessPermissions = GENERIC_ALL; ea.grfAccessMode = GRANT_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ea.Trustee.ptstrName = L"NT AUTHORITY\\Authenticated Users"; ea.Trustee.pMultipleTrustee = NULL; ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; // 设置条件 DWORD dwRes = SetEntriesInAclW(1, &ea, NULL, &pNewDACL); if (dwRes == ERROR_SUCCESS) { // 获取ACL中的第一个ACE PACCESS_ALLOWED_ACE pAce = (PACCESS_ALLOWED_ACE)GetAce(pNewDACL, 0); // 为ACE添加条件 dwRes = SetAceCondition(pNewDACL, 0, condition); }
注意:
SetAceCondition是Windows 7及以上提供的API,需要链接advapi32.lib,并定义_WIN32_WINNT >= 0x0601。
方案2:通过句柄传递(简单直接)
如果目标进程已经在运行,或你能控制目标进程的启动,可以:
- 创建文件时指定
FILE_SHARE_NONE,且DACL拒绝所有访问,确保其他进程无法打开文件。 - 打开目标进程,使用
DuplicateHandle将文件句柄复制到目标进程的句柄表中。 - 目标进程通过复制后的句柄访问文件,其他进程因无法打开文件而被拒绝。
关键代码片段:
// 创建文件,拒绝所有访问 HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); // 复制句柄到目标进程 HANDLE hTargetProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, targetProcessId); HANDLE hProcessFileHandle; DuplicateHandle(GetCurrentProcess(), hFile, hTargetProcess, &hProcessFileHandle, GENERIC_ALL, FALSE, DUPLICATE_SAME_ACCESS); CloseHandle(hTargetProcess);
目标进程可以通过这个复制的句柄读写文件,其他进程无法打开该文件。
方案3:强制完整性级别(适用于隔离场景)
给目标进程设置一个自定义的强制完整性级别,然后让文件仅允许该完整性级别访问:
- 创建一个自定义完整性级别SID(比如
S-1-16-0x1000,低完整性级别是S-1-16-0x4000,可以自定义中间值)。 - 修改目标进程的令牌,设置其完整性级别为自定义SID。
- 创建文件时,设置文件的完整性级别为同一个自定义SID,并在ACL中仅允许该完整性级别访问。
这种方法需要管理员权限,且实现相对复杂,适合需要严格隔离的场景。
总结
你的当前思路混淆了进程所有者SID和进程专属标识,导致权限应用到了用户而非进程。通过上述方案可以实现仅特定进程访问文件的目标,其中条件ACL是最符合文件系统权限模型的方案,而句柄传递是最直接简单的实现方式。
内容的提问来源于stack exchange,提问作者szefitoo

