暂时模仿和启用特权?

我们维护一个做很多与系统有关的东西的DLL; 遍历文件系统,registry等。这个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; } 

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

唯一可以做到这一点的方法是作为服务运行,并在服务内模拟用户。 该服务必须被授予默认授予所有服务帐户的模拟特权。 当你模仿呼叫者,你可能不得不冒充委派,所以你可以轻松地离开机器。

一起备份和恢复特权将提供对所有文件的完全访问,完全停止。 这些可用于LocalSystem。 您必须使用FILE_FLAG_BACKUP_SEMANTICS打开文件才能使用此文件。 一些Win32 API并没有被设计成与这个一起使用,并且不会将该标志传递给内核,尽管在某些情况下,您可以使用CreateFile来打开该目录。 (对于内核来说,目录只是另一种文件)。

如果你真的需要能够访问所有的东西,我会说启用这些权限,并执行扫描操作应该能够成功,无论调用者的安全未被模拟。

一个突出的问题是文件可能被锁定或打开,但不能共享访问。 没有办法从用户模式中解决这个问题(不杀死拥有资源的进程,可能是矫枉过正)。 这就是为什么我所知道的主流扫描仪使用内核模式文件系统过滤器驱动程序来实现此功能。

另外,请考虑审计:您是否希望审计条目显示给LocalSystem或与调用进程关联的用户?

这一切似乎真的是一个DLL的时髦! 这听起来像是一个服务的工作,而不是一个DLL,或者,如果你要允许用户帐户删除由特权帐户放在那里的数据,那么为什么不简单地设置允许删除操作的对象的ACL ?

就这样说,你究竟在做什么? 一个用户帐户通常不应该能够删除由管理员帐户放在那里的数据!