2011-12-06 12 views
5

Questa è la prima volta in assoluto che userò SafeHandle.Perché SafeHandle.DangerousGetHandle() "Pericoloso"?

Devo chiamare questo metodo P/Invoke che richiede un UIntPtr.

[DllImport("advapi32.dll", CharSet = CharSet.Auto)] 
    public static extern int RegOpenKeyEx(
     UIntPtr hKey, 
     string subKey, 
     int ulOptions, 
     int samDesired, 
     out UIntPtr hkResult); 

Questo UIntPtr sarà derivata dalla classe RegistryKey di .NET. Userò il metodo di cui sopra per convertire la classe RegistryKey a un IntPtr modo da poter utilizzare quanto sopra P/Invoke:

 private static IntPtr GetRegistryKeyHandle(RegistryKey rKey) 
     { 
      //Get the type of the RegistryKey 
      Type registryKeyType = typeof(RegistryKey); 

      //Get the FieldInfo of the 'hkey' member of RegistryKey 
      System.Reflection.FieldInfo fieldInfo = 
       registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 

      //Get the handle held by hkey 
      if (fieldInfo != null) 
      { 
       SafeHandle handle = (SafeHandle)fieldInfo.GetValue(rKey); 

       //Get the unsafe handle 
       IntPtr dangerousHandle = handle.DangerousGetHandle();     
       return dangerousHandle; 
      } 
} 

Domande:

  1. c'è un modo migliore per scrivere questo senza usare maniglie "non sicure"?
  2. Perché le maniglie non sicure sono pericolose?

risposta

3

Quello che stai facendo è in effetti pericoloso. L'oggetto RegistryKey che si utilizza può ottenere i dati raccolti e finalizzati mentre si utilizza l'IntPtr. Il che rende invalido il valore dell'handle, il che rende il tuo codice casuale fallito. Bene, va bene, l'errore casuale non è esattamente pericoloso ma apre la porta a un attacco di riciclo dell'handle se in effetti mantieni la maniglia per un lungo periodo di tempo. La modalità di fallimento casuale dovrebbe essere sufficiente per ispirarti a fare qualcosa al riguardo.

Fai la tua dichiarazione PInvoke simile a questa:

[DllImport("advapi32.dll", CharSet=CharSet.Auto)] 
internal static extern int RegOpenKeyEx(SafeRegistryHandle key, string subkey, 
    int options, int sam, out SafeRegistryHandle result); 

in modo da poter sempre utilizzare la classe maniglia involucro di sicurezza. Regolare il codice di riflessione di conseguenza.

+0

Ho dimenticato di dire che lo scopo del mio codice è imitare il supporto del registro a 64 bit di NETFX4. Utilizziamo solo NETFX 3.5, quindi non è disponibile SafeRegistryHandle. – Ian

+0

Basta renderlo SafeHandleZeroOrMinusOneIsInvalid, la classe base di SafeRegistryHandle. O semplicemente SafeHandle se si odia digitare il nome (chi no). –

4

Il RegistryKey ha una proprietà handle. Quindi puoi usare

private static IntPtr GetRegistryKeyHandle(RegistryKey rKey) 
{ 
    return rKey.Handle.DangerousGetHandle; 
} 

Questo è potenzialmente pericoloso, perché il puntatore che stai ricevendo potrebbe non essere più valido quando lo stai usando. Citazione di MSDN

Utilizzando il metodo DangerousGetHandle può comportare rischi per la sicurezza, perché, se la maniglia è stato contrassegnato come non valido con SetHandleAsInvalid, DangerousGetHandle ancora restituisce il valore maniglia originale, potenzialmente stantio. L'handle restituito può anche essere riciclato in qualsiasi momento. Nel migliore dei casi, questo significa che l'handle potrebbe improvvisamente smettere di funzionare. Nel peggiore dei casi, se l'handle o la risorsa rappresentata dall'handle è esposto a codice non attendibile, ciò può comportare un attacco di sicurezza per il riciclaggio sull'impugnatura riutilizzata o restituita. Ad esempio, un chiamante non affidabile può interrogare i dati sull'handle appena restituito e ricevere informazioni per una risorsa completamente non correlata. Vedere i metodi DangerousAddRef e DangerousRelease per ulteriori informazioni sull'uso del metodo DangerousGetHandle.

+0

Ho dimenticato di dire che lo scopo del mio codice è imitare il supporto del registro a 64 bit di NETFX4. Utilizziamo solo NETFX 3.5, quindi non esiste alcun membro Handle nella classe RegistryKey. – Ian

Problemi correlati