长话短说,我正在尝试以另一个用户的身份查询回收站。这是一个带有服务的WPF应用程序,我需要在服务中查询回收站... 我知道 ...我们需要使用NetNamedPipeBinding
,并且不能使用OperationBehavior
属性。
到目前为止,我使用以下方法在Windows 10 VM中取得了成功:
OpenProcess
表示已知的pid(我们的WPF应用),它在用户(测试人员)下运行以模拟OpenProcessToken
获取令牌。WindowsIdentity.Impersonate()
SHQueryRecycleBin
查询回收站。然后我在Windows XP VM中尝试了相同的代码,但我无法使用它。一旦SHQueryRecycleBin
被调用,我就会看到一个消息框显示:
C:\上的回收站已损坏。是否要清空此驱动器的回收站?
我知道这不是真的,因为如果我作为测试人员运行,我可以查询回收站,并通过Windows资源管理器查看它。
这看起来像是一个常见问题,我找到了Microsoft KB article。这列在原因中:
当引用的逻辑驱动器是NTFS驱动器且权限比较操作中出错时,可能会发生此问题。
我相信我的所有问题都与权限有关。但这就是我被困住的地方。我不知道为什么我没有必要的权限,也不知道如何解决这个问题。有没有人有任何想法?
我尝试使用ProcessAccessFlags.All
,TOKEN_ALL_ACCESS
和AdjustTokenPrivileges
作为远景,但没有帮助。
我一直在使用LINQPad对此进行测试,并使用此SO answer在系统帐户下运行LINQPad。为了完整性,这里有一个片段,应该可以轻松复制/粘贴,输出在测试仪和系统下运行。
作为测试人员运行:
OpenProcessToken returned 1
AdjustTokenPrivileges = True
Got user's token as 2264
Process running as XPTESTER\tester
Impersonating XPTESTER\tester
hresult=0, cbSize=20, i64Size=160420, i64NumItems=8
以系统身份运行:
OpenProcessToken returned 1
AdjustTokenPrivileges = True
Got user's token as 2128
Process running as NT AUTHORITY\SYSTEM
Impersonating XPTESTER\tester
hresult=0, cbSize=20, i64Size=0, i64NumItems=0
原油测试代码:
void Main()
{
string drive = "C:";
uint pid = 1676;
IntPtr userToken = DuplicateProcessToken(pid);
LUID tLuid = new LUID();
TOKEN_PRIVILEGES NewState = new TOKEN_PRIVILEGES();
NewState.PrivilegeCount = 1;
NewState.Privileges.pLuid = tLuid;
NewState.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
var adjustResult = AdjustTokenPrivileges(userToken, false, ref NewState, (uint)Marshal.SizeOf(NewState), IntPtr.Zero, IntPtr.Zero);
Console.WriteLine("AdjustTokenPrivileges = {0}", adjustResult);
Console.WriteLine("Got user's token as {0}", userToken);
Console.WriteLine("Process running as {0}", WindowsIdentity.GetCurrent().Name);
using(var impersonatedUser = WindowsIdentity.Impersonate(userToken))
{
var winIdentity = WindowsIdentity.GetCurrent();
Console.WriteLine("Impersonating {0}", winIdentity.Name);
var result = new SHQUERYRBINFO();
result.cbSize = Marshal.SizeOf(typeof(SHQUERYRBINFO));
int hresult = SHQueryRecycleBin(drive, ref result);
Console.WriteLine(
"hresult={0}, cbSize={1}, i64Size={2}, i64NumItems={3}",
hresult,
result.cbSize,
result.i64Size,
result.i64NumItems);
}
}
public const Int32 SE_PRIVILEGE_ENABLED = 0x00000002;
public static IntPtr DuplicateProcessToken(uint pid)
{
IntPtr hProcess = OpenProcess(ProcessAccessFlags.All, 0, pid);
uint uPriv = TOKEN_ALL_ACCESS;
IntPtr token = IntPtr.Zero;
int result = OpenProcessToken(hProcess, uPriv, ref token);
Console.WriteLine("OpenProcessToken returned {0}", result);
return token;
}
public const uint STANDARD_RIGHTS_REQUIRED = 0x00F0000;
public const uint STANDARD_RIGHTS_READ = 0x002000;
public const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
public const uint TOKEN_DUPLICATE = 0x0002;
public const uint TOKEN_IMPERSONATE = 0x004;
public const uint TOKEN_QUERY = 0x0008;
public const uint TOKEN_QUERY_SOURCE = 0x0010;
public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const uint TOKEN_ADJUST_GROUPS = 0x0040;
public const uint TOKEN_ADJUST_DEFAULT = 0x0080;
public const uint TOKEN_ADJUST_SESSIONID = 0x0100;
public const uint TOKEN_READ = (STANDARD_RIGHTS_REQUIRED | TOKEN_QUERY);
public const uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED
| TOKEN_ASSIGN_PRIMARY
| TOKEN_DUPLICATE
| TOKEN_IMPERSONATE
| TOKEN_QUERY
| TOKEN_QUERY_SOURCE
| TOKEN_ADJUST_PRIVILEGES
| TOKEN_ADJUST_GROUPS
| TOKEN_ADJUST_DEFAULT
| TOKEN_ADJUST_SESSIONID);
// Pack = 8 for x64
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct SHQUERYRBINFO
{
public int cbSize;
public long i64Size;
public long i64NumItems;
}
[DllImport("shell32.dll", SetLastError = true)]
private static extern int SHQueryRecycleBin(string pszRootPath, ref SHQUERYRBINFO pSHQueryRBInfo);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, int blnheritHanfle, uint dwAppProcessId);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern int OpenProcessToken(IntPtr processHandle, uint desiredAccess, ref IntPtr tokenHandle);
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AdjustTokenPrivileges(
IntPtr TokenHandle,
[MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
ref TOKEN_PRIVILEGES NewState,
UInt32 BufferLength,
IntPtr PreviousState,
IntPtr ReturnLength);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LUID
{
public Int32 LowPart;
public Int32 HighPart;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LUID_AND_ATTRIBUTES
{
public LUID pLuid;
public Int32 Attributes;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TOKEN_PRIVILEGES
{
public Int32 PrivilegeCount;
public LUID_AND_ATTRIBUTES Privileges;
}