2013-05-10 38 views
2

我最近編寫了一個模擬用戶帳戶的應用程序,獲取CURRENT_USER註冊表項的句柄(使用PInvoke「LoadUserProfile」檢索ProfileInfo.hProfile對象)並創建使用RegistryKey.FromHandle註冊表項。訪問CurrentUser模擬用戶的註冊表密鑰 - 與.NET 3.5的兼容性

參考代碼:

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枚舉)。

現在,我需要使此應用程序與.NET 3.5兼容,以便在具有Windows XP的計算機中使用它,並且無法安裝.NET Framework 4.0。

我可以使用.NET 3.5來實現相同的結果嗎? (即,修改模擬用戶的註冊表項)。 或者確實存在某種唯一的.NET 4對象的源代碼?

回答

5

經過幾天的研究,and help from MSDN community to the same question,我找到了滿足我的需求的方式。

最初的建議是使用Win Api函數RegOpenKeyEx(有關信息和示例,請參見P/Invoke website);但根據this MSDN article,我發現

如果您的服務或應用程序模擬不同的用戶,請不要將此函數與HKEY_CURRENT_USER一起使用。相反,調用RegOpenCurrentUser函數。

最後,要走的路是RegOpenCurrentUser函數。 (遺憾的是還是有沒有上的P/Invoke網站這個功能的痕跡,但你可以找到一些相關信息on MSDN

這是我當前如何定義它:

[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; 
} 

這是我如何使用它來獲取註冊表:

IntPtr localRegistryHandle = GetImpersonateUserRegistryHandle(TestRegistryAccess.RegistrySecurity.KEY_ALL_ACCESS); 

using(RegistryKey localRegistry = _pointerToRegistryKey(localRegistryHandle, true, true)) 
{ 
    // do something with local registry 
} 
+0

這是缺少你如何得到你的'WindowsImpersonationContext'和你登錄你的用戶併發送憑據的地方。一個完整的例子本來不錯。如果你可以使用'RegistryKey',我不知道你爲什麼需要一個函數來返回一個密鑰。只要執行'RegistryKey key = Registry.CurrentUser.OpenSubKey(KEY_STR,true);',其中'KEY_STR'是你的路徑。你並不需要所有這些,而且'SafeRegistryHandle'和所有。過度殺毒,即使是.NET 3.5。 – vapcguy 2017-02-22 22:48:05

0

寫的模擬類我這裏張貼着回答同一個樣的問題:Impersonate admin account to edit registry key not working (C#)

要寫到鑰匙,你只是做:

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。