如何获取进程所有者 ID 和当前用户 SID
本文解释了如何获取进程所有者 ID 和当前用户 SID。
引言
本文档解释了如何获取进程所有者 ID 和当前用户 SID。这在开发终端服务应用程序时很有用。 有两种主要方法可以通过进程 ID (PID) 获取进程所有者 SID:
- 使用 Windows 管理工具 (WMI)。 这是获取信息的最慢方法。
- 使用
Win32
API。
如何使用 WMI 获取进程所有者 SID
使用 WMI 获取进程所有者 SID 的方法是最短但最慢的方法。 代码非常简单,不需要注释。
public static string GetProcessInfoByPID(int PID, out string User, out string Domain)
{
User = String.Empty;
Domain = String.Empty;
OwnerSID = String.Empty;
string processname = String.Empty;
try
{
ObjectQuery sq = new ObjectQuery
("Select * from Win32_Process Where ProcessID = '" + PID + "'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq);
if (searcher.Get().Count == 0)
return OwnerSID;
foreach (ManagementObject oReturn in searcher.Get())
{
string[] o = new String[2];
//Invoke the method and populate the o var with the user name and domain
oReturn.InvokeMethod("GetOwner", (object[])o);
//int pid = (int)oReturn["ProcessID"];
processname = (string)oReturn["Name"];
//dr[2] = oReturn["Description"];
User = o[0];
if (User == null)
User = String.Empty;
Domain = o[1];
if (Domain == null)
Domain = String.Empty;
string[] sid = new String[1];
oReturn.InvokeMethod("GetOwnerSid", (object[])sid);
OwnerSID = sid[0];
return OwnerSID;
}
}
catch
{
return OwnerSID;
}
return OwnerSID;
}
如何使用 Win32 API 获取进程所有者 SID
使用 Win32
API 的方法稍微复杂一些,但效果更好(更快)。
public const int TOKEN_QUERY = 0X00000008;
const int ERROR_NO_MORE_ITEMS = 259;
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId
}
[DllImport("advapi32")]
static extern bool OpenProcessToken(
HANDLE ProcessHandle, // handle to process
int DesiredAccess, // desired access to process
ref IntPtr TokenHandle // handle to open access token
);
[DllImport("kernel32")]
static extern HANDLE GetCurrentProcess();
[DllImport("advapi32", CharSet = CharSet.Auto)]
static extern bool GetTokenInformation(
HANDLE hToken,
TOKEN_INFORMATION_CLASS tokenInfoClass,
IntPtr TokenInformation,
int tokeInfoLength,
ref int reqLength
);
[DllImport("kernel32")]
static extern bool CloseHandle(HANDLE handle);
[DllImport("advapi32", CharSet = CharSet.Auto)]
static extern bool ConvertSidToStringSid(
IntPtr pSID,
[In, Out, MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid
);
[DllImport("advapi32", CharSet = CharSet.Auto)]
static extern bool ConvertStringSidToSid(
[In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid,
ref IntPtr pSID
);
/// <summary>
/// Collect User Info
/// </summary>
/// <param name="pToken">Process Handle</param>
public static bool DumpUserInfo(HANDLE pToken, out IntPtr SID)
{
int Access = TOKEN_QUERY;
HANDLE procToken = IntPtr.Zero;
bool ret = false;
SID = IntPtr.Zero;
try
{
if (OpenProcessToken(pToken, Access, ref procToken))
{
ret = ProcessTokenToSid(procToken, out SID);
CloseHandle(procToken);
}
return ret;
}
catch (Exception err)
{
return false;
}
}
private static bool ProcessTokenToSid(HANDLE token, out IntPtr SID)
{
TOKEN_USER tokUser;
const int bufLength = 256;
IntPtr tu = Marshal.AllocHGlobal(bufLength);
bool ret = false;
SID = IntPtr.Zero;
try
{
int cb = bufLength;
ret = GetTokenInformation(token,
TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb)
if (ret)
{
tokUser = (TOKEN_USER)Marshal.PtrToStructure(tu, typeof(TOKEN_USER));
SID = tokUser.User.Sid;
}
return ret;
}
catch (Exception err)
{
return false;
}
finally
{
Marshal.FreeHGlobal(tu);
}
}
public static string ExGetProcessInfoByPID
(int PID, out string SID)//, out string OwnerSID)
{
IntPtr _SID = IntPtr.Zero;
SID = String.Empty;
try
{
Process process = Process.GetProcessById(PID);
if (DumpUserInfo(process.Handle, out _SID))
{
ConvertSidToStringSid(_SID, ref SID);
}
return process.ProcessName;
}
catch
{
return "Unknown";
}
}
如何获取当前用户 SID
如何使用所有者 SID 信息? 想象一个简单的场景,您需要显示当前用户的进程列表。 这在开发要在终端服务器上使用的应用程序时很常见,在终端服务器上,许多用户使用具有相同名称的应用程序。
private WindowsIdentity _user = WindowsIdentity.GetCurrent();
...
public bool IsCurrentUserProcess(int ProcessID)
{
string stringSID = String.Empty;
string process = Utils.ExGetProcessInfoByPID(ProcessID, out stringSID);
return String.Compare(stringSID, this._user.User.Value, true) == 0);
}
结论
这只是 WMI 可以做的一小部分示例。 不幸的是,WMI 的运行速度比较慢,因此目前没有比使用 Win32
API 更快的方法来获取所需的信息。
参考文献
- 了解有关 WMI 的更多信息 请点击此处
- 代码示例: 如何使用 C# 调用 Win32 Native API GetTokenInformation()?
历史
- 2006年7月16日:初始发布