OpenFileById以用户身份运行时获取System.AccessViolationException(以admin身份运行)

时间:2018-11-29 00:03:43

标签: c# .net memory pinvoke protected

我有一些代码可以从特定路径的文件中检索128位NTFS ID。然后,我尝试使用此ID检索文件路径。该代码在检索以admin身份运行的路径时有效。在生产中这是不可能的。不幸的是,我无法调用Marshal.GetLastWin32Error(),因为System.AccessViolationException导致应用程序完全崩溃。下面是检索路径的代码。

    public const int NO_PERMISSION = 0;

    [DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern SafeFileHandle CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        [InAttribute()] System.IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        [InAttribute()] System.IntPtr hTemplateFile
    );

    [DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern SafeFileHandle OpenFileById(
      IntPtr hVolumeHint,
      FILE_ID_DESCRIPTOR lpFileId,
      uint dwDesiredAccess,
      uint dwShareMode,
      [InAttribute()] System.IntPtr lpSecurityAttributes,
      uint dwFlagsAndAttributes
    );

    public enum _FILE_ID_TYPE
    {
        FileIdType = 0,
        ObjectIdType,
        ExtendedFileIdType,
        MaximumFileIdType
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct FILE_ID_128
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        [FieldOffset(0)]
        public byte[] Identifier;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct FILE_ID_DESCRIPTOR
    {
        public uint dwSize;
        public _FILE_ID_TYPE Type;
        public FILE_ID_128 ExtendedFileId;
    }

    public static string GetObjectPathFromId(string pathToSection, string hexId)
    {
        // We need a file handle to the drive we are looking in
        using (SafeFileHandle handle = Methods.CreateFile(
            pathToSection,
            Constants.NO_PERMISSION,
            Constants.NO_PERMISSION,
            IntPtr.Zero,
            Constants.OPEN_EXISTING,
            0x02000000 | 0x00000080,
            IntPtr.Zero))
        {
            // Build descriptor
            FILE_ID_DESCRIPTOR descriptor = new FILE_ID_DESCRIPTOR();
            descriptor.dwSize = (uint)Marshal.SizeOf(descriptor);
            descriptor.Type = _FILE_ID_TYPE.ExtendedFileIdType;
            descriptor.ExtendedFileId.Identifier = StringToByteArrayFastest(hexId);

            using (SafeFileHandle actualFile = OpenFileById(handle.DangerousGetHandle(), descriptor, 
                Constants.NO_PERMISSION, Constants.NO_PERMISSION,
                    IntPtr.Zero, 0))
            {
                if (actualFile.IsInvalid)
                    return "";
                // Buffer for the path, this should be way big enough
                int sizeOfBuffer = 1024;
                // Allocate a buffer
                IntPtr pointer = Marshal.AllocHGlobal(sizeOfBuffer);
                uint size = (uint)sizeOfBuffer;
                uint returnValue = GetFinalPathNameByHandleW(actualFile.DangerousGetHandle(), pointer, size, 0);
                // Copy it into a managed array
                byte[] outPut = new byte[sizeOfBuffer];
                Marshal.Copy(pointer, outPut, 0, (int)returnValue);
                // Decode it
                var str = Encoding.Unicode.GetString(outPut);
                // Will be an empty string if the call fails
                return str;
            }
        }
    }

我还是要指定-此代码以admin身份运行时效果很好。这些文件归用户所有,该用户无需任何其他权限即可删除,重命名和移动文件。

任何帮助将不胜感激!

Edit1:

我实现了How to handle AccessViolationException处的答案,以成功捕获异常。但是,即使执行完此Marshal.GetLastWin32Error()也会返回0。如果有人对如何调试此类问题有任何想法,请告诉我。

当我以admin(而不是用户)身份运行时,它仍然可以正常运行。

Edit2:

不确定是否相关-此代码库是否针对.NET Standard 2.0构建-使用此库代码的应用程序针对.NET Framework 4.6.2构建

0 个答案:

没有答案