为什么 SafeHandle.DangerousGetHandle() 是“危险的”?

发布于 2024-12-19 17:39:36 字数 1301 浏览 2 评论 0原文

这是我第一次使用 SafeHandle

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

 [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    公共静态 extern int RegOpenKeyEx(
      UIntPtr hKey,
      字符串子键,
      int ul选项,
      int sam期望,
      输出 UIntPtr hkResult);

这个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;
            }
}

问题:

  1. 有没有更好的方法来编写这个而不使用“不安全”句柄?
  2. 为什么不安全的手柄很危险?

This is the first time ever that I'll be using SafeHandle.

I need to call this P/Invoke method that needs an UIntPtr.

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

This UIntPtr will be derived from .NET's RegistryKey class. I will be using the method above to convert the RegistryKey class to an IntPtr so I can use the above 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;
            }
}

Questions:

  1. Is there a better way to write this without using "unsafe" handles?
  2. Why are unsafe handles dangerous?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

唐婉 2024-12-26 17:39:36

该RegistryKey有一个句柄属性。所以你可以使用

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

这有潜在的危险,因为当你使用它时,你得到的指针可能不再有效。引用自 MSDN

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

The RegistryKey has a handle property. So you can use

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

This is potentially dangerous, because the pointer you are getting may not be valid anymore when you are using it. Quote from MSDN

Using the DangerousGetHandle method can pose security risks because, if the handle has been marked as invalid with SetHandleAsInvalid, DangerousGetHandle still returns the original, potentially stale handle value. The returned handle can also be recycled at any point. At best, this means the handle might suddenly stop working. At worst, if the handle or the resource that the handle represents is exposed to untrusted code, this can lead to a recycling security attack on the reused or returned handle. For example, an untrusted caller can query data on the handle just returned and receive information for an entirely unrelated resource. See the DangerousAddRef and the DangerousRelease methods for more information about using the DangerousGetHandle methodsafely.

z祗昰~ 2024-12-26 17:39:36

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

使您的 pinvoke 声明如下所示:

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

这样您就可以一致地使用安全句柄包装类。相应地调整反射代码。

What you are doing is in fact dangerous. The RegistryKey object you use can get garbage collected and finalized while you are using the IntPtr. Which makes the handle value invalid which makes your code randomly fail. Well, okay, random failure is not exactly dangerous but it does open the door to a handle recycle attack if you in fact keep a hold of the handle for an extended period of time. The random failure mode ought to be enough to inspire you to do something about it.

Make your pinvoke declaration look like this:

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

So you can consistently use the safe handle wrapper class. Adjust the reflection code accordingly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文