当需要登录界面截图,和模拟键盘,或其它特殊操作,需要提权到SYSTEM
如果此时程序需要操作注册表,就无法使用HKEY_CURRENT_USER来设置当前用户的配置,此时就需要使用HKEY_USERS来设置当前系统登录用户的配置
又因为用的是SYSTEM用户运行程序,所以需要用winapi来获取sid,而无法直接获取
定义一些内容
C#
[DllImport("kernel32.dll")]
public static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQueryUserToken(int sessionId, out IntPtr token);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(
nint TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
nint TokenInformation,
int TokenInformationLength,
out int ReturnLength);
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurity]
public static extern bool ConvertSidToStringSid(IntPtr sid, out string stringSid);
public enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
MaxTokenInfoClass
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_USER
{
public SID_AND_ATTRIBUTES User;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct USER_INFO_0
{
public string usri0_name;
}
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int NetUserEnum(
StringBuilder servername,
int level,
int filter,
out IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
ref int resume_handle
);
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int NetApiBufferFree(IntPtr Buffer);
[DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool LookupAccountName(
string lpSystemName,
string lpAccountName,
IntPtr Sid,
ref int cbSid,
StringBuilder ReferencedDomainName,
ref int cchReferencedDomainName,
out int peUse
);
获取当前登录用户的sid
C#
private static string currentUsername = string.Empty;
public static string GetCurrentUserSid()
{
if (OperatingSystem.IsWindows() == false)
{
return string.Empty;
}
if (OperatingSystem.IsWindows())
{
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
currentUsername = currentIdentity.Name;
//不是SYSTEM用户,直接获取当前用户sid
if (IsSystemUser() == false)
{
return currentIdentity.User.Value;
}
}
//获取系统登录用户sid
IntPtr hToken;
int sessionId = (int)Kernel32.WTSGetActiveConsoleSessionId();
if (WTSAPI32.WTSQueryUserToken(sessionId, out hToken))
{
try
{
IntPtr tokenInformation;
int returnLength;
if (GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, 0, out returnLength) || returnLength == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
tokenInformation = Marshal.AllocHGlobal(returnLength);
try
{
if (!GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation, returnLength, out returnLength))
{
return string.Empty;
}
var user = (TOKEN_USER)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_USER));
string stringSid;
if (ConvertSidToStringSid(user.User.Sid, out stringSid))
{
return stringSid;
}
}
finally
{
Marshal.FreeHGlobal(tokenInformation);
}
}
finally
{
if (hToken != IntPtr.Zero)
{
Marshal.FreeHGlobal(hToken);
}
}
}
return string.Empty;
}
public static bool IsSystemUser()
{
return currentUsername == "NT AUTHORITY\\SYSTEM";
}
未登录系统,获取默认用户sid
当系统只有一个登录用户时,可以作为默认sid,以操作注册表
C#
public static string GetDefaultUserSid()
{
if (OperatingSystem.IsWindows() == false)
{
return string.Empty;
}
List<string> registrySids = Registry.Users.GetSubKeyNames().ToList();
List<string> sids = new List<string>();
int resumeHandle = 0;
int result = NetApi32.NetUserEnum(null, 0, 2, out IntPtr bufPtr, -1, out int entriesRead, out int totalEntries, ref resumeHandle);
if (result == 0)
{
try
{
for (int i = 0; i < entriesRead; i++)
{
USER_INFO_0 userInfo = (USER_INFO_0)Marshal.PtrToStructure(bufPtr+(Marshal.SizeOf(typeof(USER_INFO_0))*i), typeof(USER_INFO_0));
int cbSid = 0;
int cchReferencedDomainName = 0;
int peUse;
StringBuilder referencedDomainName = new StringBuilder();
IntPtr pSid = IntPtr.Zero;
bool bSuccess = LookupAccountName(null, userInfo.usri0_name, pSid, ref cbSid, referencedDomainName, ref cchReferencedDomainName, out peUse);
if (!bSuccess && cbSid > 0)
{
pSid = Marshal.AllocHGlobal(cbSid);
referencedDomainName.EnsureCapacity(cchReferencedDomainName);
bSuccess = LookupAccountName(null, userInfo.usri0_name, pSid, ref cbSid, referencedDomainName, ref cchReferencedDomainName, out peUse);
}
if (bSuccess)
{
if (ConvertSidToStringSid(pSid, out string stringSid))
{
if (registrySids.Contains(stringSid))
{
sids.Add(stringSid);
}
}
}
if (pSid != IntPtr.Zero)
{
Marshal.FreeHGlobal(pSid);
}
}
}
catch (Exception)
{
}
finally
{
NetApi32.NetApiBufferFree(bufPtr);
}
}
if(sids.Count == 1)
{
return sids[0];
}
return string.Empty;
}
可以配置注册表了
C#
HKEY_USERS\{sid}\xxx