C# 访问模拟用户的CurrentUser注册表项-与.NET 3.5兼容
我最近编写了一个应用程序,它模拟用户帐户,获取当前用户注册表项的句柄(使用PInvoke“LoadUserProfile”检索ProfileInfo.hProfile对象),并使用RegistryKey.FromHandle创建注册表项 参考代码:C# 访问模拟用户的CurrentUser注册表项-与.NET 3.5兼容,c#,.net,.net-3.5,registry,impersonation,C#,.net,.net 3.5,Registry,Impersonation,我最近编写了一个应用程序,它模拟用户帐户,获取当前用户注册表项的句柄(使用PInvoke“LoadUserProfile”检索ProfileInfo.hProfile对象),并使用RegistryKey.FromHandle创建注册表项 参考代码: using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(hToken)) { using (SafeRegistryHandle sa
using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(hToken))
{
using (SafeRegistryHandle safeHandle = new SafeRegistryHandle(hProfile, true))
{
using (RegistryKey impersonatedUserHkcu = RegistryKey.FromHandle(safeHandle, RegistryView.Default))
{
// Do something with registry
}
}
}
这段代码运行良好(在Windows 7中运行),但使用了仅受.NET 4.0及更高版本支持的对象/方法(SafeRegistryHandle、RegistryKey.FromHandle()、RegistryView enum)
现在,我需要使这个应用程序与.NET3.5兼容,以便在装有WindowsXP的机器上使用,并且不可能安装.NETFramework4.0
是否有任何与.NET3.5相同的对象可以用于实现相同的结果?(即,对模拟用户的注册表项进行修改)。
或者是否存在只包含.NET 4对象的某种源代码?经过几天的研究,我找到了实现我的需求的方法
最初的建议是使用Win Api函数RegOpenKeyEx
(有关信息和示例,请参阅);但据我所知,我发现
如果您的服务或应用程序模拟不同的用户,请不要对HKEY_CURRENT_用户使用此功能。相反,调用RegOpenCurrentUser函数
最后,方法是使用RegOpenCurrentUser
函数。(不幸的是,P/Invoke网站上仍然没有该函数的踪迹,但您可以找到一些信息)
我目前是这样定义它的:
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenCurrentUser(int samDesired, out IntPtr phkResult);
public enum RegistrySecurity
{
KEY_ALL_ACCESS = 0xF003F,
KEY_CREATE_LINK = 0x0020,
KEY_CREATE_SUB_KEY = 0x0004,
KEY_ENUMERATE_SUB_KEYS = 0x0008,
KEY_EXECUTE = 0x20019,
KEY_NOTIFY = 0x0010,
KEY_QUERY_VALUE = 0x0001,
KEY_READ = 0x20019,
KEY_SET_VALUE = 0x0002,
KEY_WOW64_32KEY = 0x0200,
KEY_WOW64_64KEY = 0x0100,
KEY_WRITE = 0x20006,
}
public IntPtr GetImpersonateUserRegistryHandle(RegistrySecurity _access)
{
IntPtr safeHandle = new IntPtr();
int result = RegOpenCurrentUser((int)_access, out safeHandle);
return safeHandle;
}
/// <summary>
/// Get a registry key from a pointer.
/// </summary>
/// <param name="hKey">Pointer to the registry key</param>
/// <param name="writable">Whether or not the key is writable.</param>
/// <param name="ownsHandle">Whether or not we own the handle.</param>
/// <returns>Registry key pointed to by the given pointer.</returns>
public RegistryKey _pointerToRegistryKey(IntPtr hKey, bool writable, bool ownsHandle)
{
//Get the BindingFlags for private contructors
System.Reflection.BindingFlags privateConstructors = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
//Get the Type for the SafeRegistryHandle
Type safeRegistryHandleType =
typeof(Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
//Get the array of types matching the args of the ctor we want
Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), typeof(bool) };
//Get the constructorinfo for our object
System.Reflection.ConstructorInfo safeRegistryHandleCtorInfo = safeRegistryHandleType.GetConstructor(
privateConstructors, null, safeRegistryHandleCtorTypes, null);
//Invoke the constructor, getting us a SafeRegistryHandle
Object safeHandle = safeRegistryHandleCtorInfo.Invoke(new Object[] { hKey, ownsHandle });
//Get the type of a RegistryKey
Type registryKeyType = typeof(RegistryKey);
//Get the array of types matching the args of the ctor we want
Type[] registryKeyConstructorTypes = new Type[] { safeRegistryHandleType, typeof(bool) };
//Get the constructorinfo for our object
System.Reflection.ConstructorInfo registryKeyCtorInfo = registryKeyType.GetConstructor(
privateConstructors, null, registryKeyConstructorTypes, null);
//Invoke the constructor, getting us a RegistryKey
RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(new Object[] { safeHandle, writable });
//return the resulting key
return resultKey;
}
我在这里发布了一个模拟类来回答同样的问题: 要写入密钥,只需执行以下操作:
string userName = "domain\user";
string password = "whatever";
string KEY_STR = "SomeSubKey\\ASubKeyToThat";
WindowsImpersonationContext adminContext = Impersonation.getWic(userName, password);
if (adminContext != null)
{
try
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(KEY_STR, true);
key.SetValue("State", 0x60001);
}
catch (Exception ex)
{
Console.Out.WriteLine("\nUnable to set registry value:\n\t" + ex.Message);
Impersonation.endImpersonation();
adminContext.Undo();
}
finally
{
Impersonation.endImpersonation();
// The above line does this --
//if (tokenHandle != IntPtr.Zero) CloseHandle(tokenHandle);
adminContext.Undo();
}
}
除了获取所需的
WindowsImpersonationContext
之外,没有句柄或其他奇特的函数。未重新发布该部分,因为您似乎已经知道如何获取WIC。这缺少如何获取WindowsImpersonationContext
以及您登录用户并发送凭据的位置。一个完整的例子就好了。如果您可以使用注册表键
,我不知道您为什么需要函数来返回键。只需执行注册表项key=Registry.CurrentUser.OpenSubKey(key\u STR,true)代码>,其中键\u STR
是您的路径。您不需要所有这些,以及SafeRegistryHandle
等等。即使对于.NET3.5来说,也太过分了。
string userName = "domain\user";
string password = "whatever";
string KEY_STR = "SomeSubKey\\ASubKeyToThat";
WindowsImpersonationContext adminContext = Impersonation.getWic(userName, password);
if (adminContext != null)
{
try
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(KEY_STR, true);
key.SetValue("State", 0x60001);
}
catch (Exception ex)
{
Console.Out.WriteLine("\nUnable to set registry value:\n\t" + ex.Message);
Impersonation.endImpersonation();
adminContext.Undo();
}
finally
{
Impersonation.endImpersonation();
// The above line does this --
//if (tokenHandle != IntPtr.Zero) CloseHandle(tokenHandle);
adminContext.Undo();
}
}