gpt4 book ai didi

c# - 模拟和 CurrentUser 注册表访问

转载 作者:可可西里 更新时间:2023-11-01 08:46:59 35 4
gpt4 key购买 nike

环境:Windows XP SP3、C#、.Net 4.0

问题:

我试图在模拟类中添加对模拟用户注册表配置单元的访问权限,但我遇到了基于被模拟用户类型的问题(或者更准确地说,限制似乎是模拟用户)。

我原来是在关注 an impersonation example from CodeProject其中显示了对 LoadUserProfile() 的调用使用通过调用 DuplcateToken() 生成的重复 token 开始模拟后发生来自 LogonUser() 获得的原始 token .我无法在我的环境中使用管理员帐户模拟受限用户的示例(从示例中包含的屏幕截图来看,它似乎是在 Windows Vista\7 系统上完成的,并且没有提供有关涉及的帐户类型)。

调用 LoadUserProfile()抛出“拒绝访问”的错误。查看 userenv.log 显示“LoadUserProfile: failed to enable the restore privilege.error c0000022”这一行。 MSDN 上的 LoadUserProfile 文档显示调用进程必须拥有 SE_RESTORE_NAME 和 SE_BACKUP_NAME 权限,默认情况下只有 Administrators 和 Backup Operators 组的成员拥有这些权限。 (作为旁注,当我稍后尝试将这两个权限添加到用户组时,我仍然收到拒绝访问,但 userenv.log 显示“DropClientContext:客户端 [编号] 没有足够的权限。错误 5”,我不能' t 找到任何信息)

鉴于我模拟的用户没有这些权限,我将调用移至 LoadUserProfile()在开始模拟之前,这次加载没有问题,我能够在这个测试中读写它。以为我已经找到了我的答案,我为帐户类型创建了一个条件检查,以便 LoadUserProfile()如果当前用户是管理员的成员,则在模拟之前调用,或者如果成员不是管理员的成员,则等到模拟之后调用(在后面的实例中,我将依赖具有这些权限的模拟用户)。不幸的是我错了;我还没有发现我的答案。当我测试角色颠倒(用户 > 管理员)的调用时,调用 LoadUserProfile()仍然再次失败,出现拒绝访问错误,并且 userenv.log 显示相同的“LoadUserProfile: failed to enable the restore privilege.error c0000061”,但这次有不同的错误号。

认为对LogonUser()返回的token默认可能没有开启权限和\或 DuplicateToken()我给 AdjustTokenPrivilege() 添加了两个电话在从 WindowsIdentity.GetCurrent(TokenAccessLevels.AdjustPrivileges | TokenAccessLevels.Query).Token 获得的当前用户 token (发生在模拟之后)上.TokenAccessLevels.AdjustPrivilegesTokenAccessLevels.Query之所以被指定,是因为 MSDN 上的 AdjustTokenPrivilege 文档指定正在调整的 token 上需要它们(我还尝试使用从 OpenProcessToken() 检索到的句柄通过调用 System.Diagnostics.Process.GetCurrentProcess().Handle 获取 token ,但是当从用户调用时失败了模拟的内部和外部,GetCurrentProcess() 是抛出访问被拒绝的函数)
AdjustTokenPrivilege()WindowsIdentity...Token 一起使用时成功返回但是 LoadUserProfile()仍然导致拒绝访问(恢复特权)。
在这一点上我不相信 AdjustTokenPrivilege()正在做它的工作,所以我开始使用 GetTokenInformation() 确定特定 token 的可用权限以及它们处于什么状态。这导致了它自己的一小袋乐趣。在学习了一些新东西后,我可以拨打 GetTokenInformation()并打印出权限列表及其当前状态,但结果有些不确定,因为在调用 AdjustTokenPrivilege() 之前和之后,还原和备份都显示属性为 0。作为管理员和冒充管理员(奇怪的是,当调用 AdjustTokenPrivilege() 时, token 上的其他三个权限从 2 变为 1,但实际上没有被调整,其值仍为 0)

我取消了对 DuplicateToken() 的调用并用从 LogonUser() 返回的 token 替换它正在使用的所有地方看看这是否有助于测试 token 的特权LogonUser()DuplicateToken() token 是相同的。当我最初编写模拟类时,我一直在调用 WindowsImpersonationContext.Impersonate() 时使用主要 token 。没有任何问题,并认为值得一试。

在我在下面提供的代码示例中,我可以在以管理员身份运行时模拟和访问用户的注册表,但反过来不行。任何帮助将不胜感激。

事前编辑:

我也试过使用 RegOpenCurrentUser() API 代替 LoadUserProfile()并成功使用管理员 > 自我和管理员 > 用户模拟,但是当从另一个管理员帐户或用户模拟管理员时 RegOpenCurrentUser()返回一个指向 HKEY_USERS\S-1-5-18(无论是什么)而不是实际帐户配置单元的指针。我猜是因为它实际上并没有加载,这让我回到了需要使用的地方 LoadUserProfile()
来自 RegOpenCurrentUser 文档 (MSDN):

RegOpenCurrentUser uses the thread's token to access the appropriate key, or the default if the profile is not loaded.



代码片段:
// Private variables used by class
private IntPtr tokenHandle;
private PROFILEINFO pInfo;
private WindowsImpersonationContext thisUser;
private string sDomain = string.Empty;
private string sUsername = string.Empty;
private string sPassword = string.Empty;
private bool bDisposed = false;
private RegistryKey rCurrentUser = null;
private SafeRegistryHandle safeHandle = null;

//Constants used for privilege adjustment
private const string SE_RESTORE_NAME = "SeRestorePrivilege";
private const string SE_BACKUP_NAME = "SeBackupPrivilege";
private const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001;
private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
private const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004;
private const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000;

[StructLayout(LayoutKind.Sequential)]
protected struct PROFILEINFO {
public int dwSize;
public int dwFlags;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpUserName;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpProfilePath;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpDefaultPath;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpPolicyPath;
public IntPtr hProfile;
}

protected struct TOKEN_PRIVILEGES {
public UInt32 PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public LUID_AND_ATTRIBUTES[] Privileges;
}

[StructLayout(LayoutKind.Sequential)]
protected struct LUID_AND_ATTRIBUTES {
public LUID Luid;
public UInt32 Attributes;
}

[StructLayout(LayoutKind.Sequential)]
protected struct LUID {
public uint LowPart;
public int HighPart;
}


// Private API calls used by class
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
protected static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
protected static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);

[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
protected static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile);

[DllImport("kernel32.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]
protected static extern bool CloseHandle(IntPtr hObject);

[DllImport("advapi32.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]
protected static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, UInt32 Zero, IntPtr Null1, IntPtr Null2);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)][return: MarshalAs(UnmanagedType.Bool)]
protected static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref LUID lpLuid);


[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Start() {

tokenHandle = IntPtr.Zero; // set the pointer to nothing
if (!LogonUser(sUsername, sDomain, sPassword, 2, 0, ref tokenHandle)) {
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
} // end if !LogonUser returned false

try { //All of this is for loading the registry and is not required for impersonation to start
LUID LuidRestore = new LUID();
LUID LuidBackup = new LUID();
if(LookupPrivilegeValue(null, SE_RESTORE_NAME, ref LuidRestore) && LookupPrivilegeValue(null, SE_BACKUP_NAME, ref LuidBackup)) {
//Create the TokenPrivileges array to pass to AdjustTokenPrivileges
LUID_AND_ATTRIBUTES[] LuidAndAttributes = new LUID_AND_ATTRIBUTES[2];
LuidAndAttributes[0].Luid = LuidRestore;
LuidAndAttributes[0].Attributes = SE_PRIVILEGE_ENABLED;
LuidAndAttributes[1].Luid = LuidBackup;
LuidAndAttributes[1].Attributes = SE_PRIVILEGE_ENABLED;

TOKEN_PRIVILEGES TokenPrivileges = new TOKEN_PRIVILEGES();
TokenPrivileges.PrivilegeCount = 2;
TokenPrivileges.Privileges = LuidAndAttributes;

IntPtr procHandle = WindowsIdentity.GetCurrent(TokenAccessLevels.AdjustPrivileges | TokenAccessLevels.Query).Token;

if(AdjustTokenPrivileges(procHandle, false, ref TokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero)) {
pInfo = new PROFILEINFO();
pInfo.dwSize = Marshal.SizeOf(pInfo);
pInfo.lpUserName = sUsername;
pInfo.dwFlags = 1;

LoadUserProfile(tokenHandle, ref pInfo); //this is not required to take place
if(pInfo.hProfile != IntPtr.Zero) {
safeHandle = new SafeRegistryHandle(pInfo.hProfile, true);
rCurrentUser = RegistryKey.FromHandle(safeHandle);
}//end if pInfo.hProfile
}//end if AdjustTokenPrivileges
}//end if LookupPrivilegeValue 1 & 2
}catch{
//We don't really care that this didn't work but we don't want to throw any errors at this point as it would stop impersonation
}//end try

WindowsIdentity thisId = new WindowsIdentity(tokenHandle);
thisUser = thisId.Impersonate();

} // end function Start

最佳答案

来自 LoadUserProfile docs :

Starting with Windows XP Service Pack 2 (SP2) and Windows Server 2003, the caller must be an administrator or the LocalSystem account. It is not sufficient for the caller to merely impersonate the administrator or LocalSystem account.



如果您的流程以普通用户身份开始,那么您就不走运了。您可能会启动一个新进程(在管理员凭据下)来加载配置文件。

关于c# - 模拟和 CurrentUser 注册表访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4392221/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com