Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 临时模拟并启用权限?_C_Windows_Security - Fatal编程技术网

C 临时模拟并启用权限?

C 临时模拟并启用权限?,c,windows,security,C,Windows,Security,我们维护一个DLL,它可以做很多与系统相关的事情;遍历文件系统、注册表等。此DLL的调用者可能正在使用模拟,也可能未使用模拟。为了更好地支持所有可能的场景,我尝试将其修改为更智能的。我将使用删除文件的示例。目前我们只调用DeleteFile(),如果调用失败,则到此结束。我得出以下结论: BOOL TryReallyHardToDeleteFile(LPCTSTR lpFileName) { // 1. caller without privilege BOOL bSuccess

我们维护一个DLL,它可以做很多与系统相关的事情;遍历文件系统、注册表等。此DLL的调用者可能正在使用模拟,也可能未使用模拟。为了更好地支持所有可能的场景,我尝试将其修改为更智能的。我将使用删除文件的示例。目前我们只调用DeleteFile(),如果调用失败,则到此结束。我得出以下结论:

BOOL TryReallyHardToDeleteFile(LPCTSTR lpFileName)
{
    // 1. caller without privilege
    BOOL bSuccess = DeleteFile(lpFileName);
    DWORD dwError = GetLastError();
    if(!bSuccess && dwError == ERROR_ACCESS_DENIED)
    {
        // failed with access denied; try with privilege
        DWORD dwOldRestorePrivilege = 0;
        BOOL bHasRestorePrivilege = SetPrivilege(SE_RESTORE_NAME, SE_PRIVILEGE_ENABLED, &dwOldRestorePrivilege);
        if(bHasRestorePrivilege)
        {
            // 2. caller with privilege
            bSuccess = DeleteFile(lpFileName);
            dwError = GetLastError();
            SetPrivilege(SE_RESTORE_NAME, dwOldRestorePrivilege, NULL);
        }
        if(!bSuccess && dwError == ERROR_ACCESS_DENIED)
        {
            // failed with access denied; if caller is impersonating then try as process
            HANDLE hToken = NULL;
            if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &hToken))
            {
                if(RevertToSelf())
                {
                    // 3. process without privilege
                    bSuccess = DeleteFile(lpFileName);
                    dwError = GetLastError();
                    if(!bSuccess && dwError == ERROR_ACCESS_DENIED)
                    {
                        // failed with access denied; try with privilege
                        bHasRestorePrivilege = SetPrivilege(SE_RESTORE_NAME, SE_PRIVILEGE_ENABLED, &dwOldRestorePrivilege);
                        if(bHasRestorePrivilege)
                        {
                            // 4. process with privilege
                            bSuccess = DeleteFile(lpFileName);
                            dwError = GetLastError();
                            SetPrivilege(SE_RESTORE_NAME, dwOldRestorePrivilege, NULL);
                        }
                    }
                    SetThreadToken(NULL, hToken);
                }
                CloseHandle(hToken);
                hToken = NULL;
            }
        }
    }
    if(!bSuccess)
    {
        SetLastError(dwError);
    }
    return bSuccess;
}

所以首先它尝试作为调用者。如果在拒绝访问的情况下失败,它会临时启用调用方令牌中的权限,然后重试。如果由于访问被拒绝而失败,并且调用者正在模拟,则它会暂时取消代理并重试。如果在拒绝访问的情况下失败,它将临时启用进程令牌中的权限并重试。我认为这应该可以处理几乎任何情况,但我想知道是否有更好的方法来实现这一点?我们可能希望使用此方法执行许多操作(即,几乎所有访问安全对象的操作)。

对于DLL来说,这一切似乎都非常有趣!这听起来像是服务的作业,而不是DLL,或者,如果要允许用户帐户删除特权帐户放在那里的数据,那么为什么不简单地在允许删除操作的对象上设置ACL呢


话虽如此,你到底想做什么?用户帐户通常不能删除管理员帐户放在那里的数据

备份和还原权限一起将提供对所有文件的完全访问,完全停止。这些都可用于LocalSystem。要使用此选项,您必须打开具有FILE\u FLAG\u BACKUP\u语义的文件。有些Win32 API不是为与此一起使用而设计的,并且不会将标志传递给内核,尽管在某些情况下,您可以使用CreateFile来打开目录。(对于内核来说,目录只是另一种文件)

如果您真的需要能够访问所有内容,我会说启用这些特权并执行扫描操作,无论调用方的安全性如何,这些操作都应该成功

一个悬而未决的问题是文件可能被锁定或打开,但不能共享访问权限。从用户模式无法避免这种情况(如果不杀死拥有资源的进程,可能是杀戮过度)。这就是我所知道的主流扫描仪使用内核模式文件系统过滤器驱动程序实现此功能的原因


另外,考虑一下审计:您希望本地系统或与调用进程关联的用户显示审计条目吗?

唯一的方法是作为服务运行,并从服务中模拟用户。必须向服务授予模拟特权,默认情况下,所有服务帐户都会授予该特权。当您模拟呼叫者时,您可能必须模拟委派,以便轻松地离开机器

为什么不直接进入最后一个选项呢?没有异常处理,如果我正确阅读了您的解释,保证工作正常。这不适用于进程作为LocalSystem(即服务)运行并且我们需要读取网络位置上的文件(即只有模拟用户帐户才能访问文件)的情况。@Chris:这也违背了特权最低的思维方式。您应该只需要执行该操作所需的权限,不再需要。这是一种更难的做事方式,但更“理想”的方式。@Ioan-我没想到。我想这取决于早期尝试失败的可能性。您错过了readonly属性标志:)我同意您所说的大部分内容,但这超出了我的控制范围。这个DLL是一种扫描组件,在概念上类似于防病毒软件。在我们的产品中,它作为本地系统上下文中的服务运行。但是,用户可以指定要扫描的位置;这可能包括需要模拟才能访问的网络路径。因此,我们首先模拟用户,然后运行扫描。如果用户还想扫描系统路径(可能他没有访问权限),我们需要暂时不需要人为地访问它们。DeleteFile()只是一个例子;我本可以用FindFirstFile()来代替;LocalSystem没有该访问权限。模拟还将允许我访问用户的加密文件,LocalSystem也无法访问这些文件(至少不能访问解密的内容)。是的,这就是我们服务的结构。然而,我无法控制第三方将如何使用我们的DLL,所以我试图以一种通用的方式处理这个问题。到目前为止,在我的测试中,它似乎工作得很好,尽管如果模拟用户是标准用户,那么他们的令牌中没有任何有用的特权,这是一个浪费的步骤。实际上,我们需要模拟的唯一原因是访问网络路径;也许我可以在尝试访问本地路径时取消模拟,在尝试访问网络路径时重新模拟。