C# 为什么是SafeHandle.DangerousGetHandle();危险;?

C# 为什么是SafeHandle.DangerousGetHandle();危险;?,c#,.net-3.5,pinvoke,handles,C#,.net 3.5,Pinvoke,Handles,这是我第一次使用SafeHandle 我需要调用这个需要UIntPtr的p/Invoke方法 此UIntPtr将从.NET的RegistryKey类派生。我将使用上面的方法将RegistryKey类转换为IntPtr,以便使用上面的P/Invoke: private static IntPtr GetRegistryKeyHandle(RegistryKey rKey) { //Get the type of the RegistryKey

这是我第一次使用
SafeHandle

我需要调用这个需要UIntPtr的p/Invoke方法

此UIntPtr将从.NET的RegistryKey类派生。我将使用上面的方法将RegistryKey类转换为IntPtr,以便使用上面的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;
            }
}
问题:

  • 有没有更好的方法在不使用“不安全”句柄的情况下编写此文件
  • 为什么不安全手柄很危险

  • RegistryKey具有句柄属性。所以你可以用

    private static IntPtr GetRegistryKeyHandle(RegistryKey rKey)
    {
        return rKey.Handle.DangerousGetHandle;
    }
    
    这有潜在的危险,因为您使用的指针可能不再有效。引自

    使用DangerousGetHandle方法可能会带来安全风险,因为如果已使用SetHandlesInvalid将句柄标记为无效,则DangerousGetHandle仍会返回原始的、可能过时的句柄值。返回的句柄也可以在任何时候循环使用。充其量,这意味着手柄可能会突然停止工作。在最坏的情况下,如果句柄或句柄所代表的资源暴露于不受信任的代码中,这可能会导致对重用的或返回的句柄的循环安全攻击。例如,不受信任的调用方可以查询刚刚返回的句柄上的数据,并接收完全无关的资源的信息。有关安全使用DangerousGetHandle方法的更多信息,请参阅DangerousAddRef和DangerousRelease方法


    你所做的事实际上是危险的。您使用的RegistryKey对象可以在使用IntPtr时进行垃圾收集并最终确定。这会使句柄值无效,从而使代码随机失败。好吧,随机失效并不十分危险,但如果你真的长时间握住把手,它确实会打开把手回收攻击的大门。随机故障模式应该足以激励您对此采取措施

    使您的pinvoke声明如下所示:

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

    因此,您可以始终如一地使用安全句柄包装类。相应地调整反射代码。

    我忘了提到我的代码的目的是模仿NETFX4的64位注册表支持。我们只使用NetFX3.5,因此RegistryKey类中没有句柄成员。我忘了提到我的代码的目的是模拟NETFX4的64位注册表支持。我们只使用NETFX 3.5,因此没有可用的SafeRegistryHandle。只需将其设为SafeHandleZeroOrMinusOneIsInvalid,即SafeRegistryHandle的基类。或者,如果你讨厌输入名字(谁不喜欢),就用普通的安全手柄。
    [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
    internal static extern int RegOpenKeyEx(SafeRegistryHandle key, string subkey, 
        int options, int sam, out SafeRegistryHandle result);