C# Pinvoke NtOpenFile和NtQueryAfile,以便在C中读取NTFS扩展属性

C# Pinvoke NtOpenFile和NtQueryAfile,以便在C中读取NTFS扩展属性,c#,pinvoke,ntfs,C#,Pinvoke,Ntfs,我试图为扩展属性而不是备用数据流编写一个简单的NTFS读取器函数!在C中,它将在以后的一些powershell脚本中使用,因此我需要使用C 到目前为止,我收集了一些关于NtOpenFile的信息: [StructLayout(LayoutKind.Sequential, Pack = 0)] public struct OBJECT_ATTRIBUTES { public Int32 Length; public

我试图为扩展属性而不是备用数据流编写一个简单的NTFS读取器函数!在C中,它将在以后的一些powershell脚本中使用,因此我需要使用C

到目前为止,我收集了一些关于NtOpenFile的信息:

 [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct OBJECT_ATTRIBUTES
        {
            public Int32 Length;
            public IntPtr RootDirectory;
            public IntPtr ObjectName;
            public uint   Attributes;
            public IntPtr SecurityDescriptor;
            public IntPtr SecurityQualityOfService;

        }

        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct IO_STATUS_BLOCK
        {
            public uint status;
            public IntPtr information;
        }   

        [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
        public static extern int NtOpenFile(
            out  IntPtr handle,
            System.IO.FileAccess access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            System.IO.FileShare share,
            uint openOptions
            );
但仍然没有关于NtQueryAfile的信息,也没有调用它并整理其结果的演示代码,谢谢您的帮助

编辑1 使用这段新代码会更进一步,但在调用NtQueryAfile后仍然会遇到访问被拒绝的问题。有什么想法吗

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
using System.ComponentModel;
using HANDLE = System.IntPtr;

namespace ConsoleApplication1
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct OBJECT_ATTRIBUTES
        {
            public Int32 Length;
            public IntPtr RootDirectory;
            public IntPtr ObjectName;
            public uint   Attributes;
            public IntPtr SecurityDescriptor;
            public IntPtr SecurityQualityOfService;

        }

        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct IO_STATUS_BLOCK
        {
            public uint status;
            public IntPtr information;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct UNICODE_STRING
        {
            public ushort Length;
            public ushort MaximumLength;
            public IntPtr Buffer;

        }


        [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
        public static extern uint NtOpenFile(
            out  IntPtr handle,
            System.IO.FileAccess access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            System.IO.FileShare share,
            uint openOptions
            );


        [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
        public static extern uint NtQueryEaFile(
            IntPtr handle,
            out IO_STATUS_BLOCK ioStatus,
            out IntPtr buffer,
            uint  length,
            bool retSingleEntry,
            IntPtr eaList,
            uint  eaListLength,
            IntPtr eaIndex,
            bool restartScan
            );

        [DllImport("ntdll.dll")]
        public static extern void RtlInitUnicodeString(
            out UNICODE_STRING DestinationString,
            [MarshalAs(UnmanagedType.LPWStr)] string SourceString);

        [DllImport("ntdll.dll")]
        public static extern uint RtlNtStatusToDosError(uint Status);

        [DllImport("kernel32.dll")]
        public static extern uint FormatMessage(int dwFlags, IntPtr lpSource, uint dwMessageId,
            int dwLanguageId, StringBuilder lpBuffer, int nSize, IntPtr Arguments);

        static void Main(string[] args)
        {
            UInt32 FILE_OPEN = 0x1;
            UInt32 OBJ_CASE_INSENSITIVE = 0x40;
            UInt32 FILE_READ_EA = 8;
            UInt32 FILE_RANDOM_ACCESS = 0x00000800;
            UInt32 FILE_DIRECTORY_FILE = 0x00000002;
            UInt32 FILE_NON_DIRECTORY_FILE = 0x00000040;
            UInt32 FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
            uint NT_SUCCESS = 0x0;
            bool restartScan = false;
            bool returnSingleEntry = false;

            IntPtr _RootHandle; //This will need to be initialized with the root handle, can use CreateFile from kernel32.dll
            _RootHandle = IntPtr.Zero;

            UNICODE_STRING unicodeString;
            RtlInitUnicodeString(out unicodeString, @"\??\C:\temp");
            IntPtr unicodeIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(unicodeString));
            Marshal.StructureToPtr(unicodeString, unicodeIntPtr, false);

            OBJECT_ATTRIBUTES objAttributes = new OBJECT_ATTRIBUTES();
            IO_STATUS_BLOCK ioStatusBlock = new IO_STATUS_BLOCK();
            //Microsoft.Win32.SafeHandles.SafeFileHandle hFile;
            HANDLE hFile;


            objAttributes.Length = System.Convert.ToInt32(Marshal.SizeOf(objAttributes));
            objAttributes.ObjectName = unicodeIntPtr;
            objAttributes.RootDirectory = _RootHandle;
            objAttributes.Attributes = OBJ_CASE_INSENSITIVE;
            objAttributes.SecurityDescriptor = IntPtr.Zero;
            objAttributes.SecurityQualityOfService = IntPtr.Zero;

            uint status = NtOpenFile(out hFile, FileAccess.Read, ref objAttributes, out ioStatusBlock, FileShare.Read, FILE_DIRECTORY_FILE | FILE_READ_EA | FILE_OPEN_FOR_BACKUP_INTENT);
            if (status != NT_SUCCESS)
                ExitWithError(status);           

            IntPtr buffer = Marshal.AllocHGlobal(65535);
            status = NtQueryEaFile(hFile, out ioStatusBlock, out buffer, System.Convert.ToUInt32(Marshal.SizeOf(buffer)), returnSingleEntry, IntPtr.Zero, 0, IntPtr.Zero, restartScan);
            if (status != NT_SUCCESS)
                ExitWithError(status);   

        }

        public static void ExitWithError(uint errorCode)
        {
            Console.WriteLine(GetSystemMessage(RtlNtStatusToDosError(errorCode)));
            Environment.Exit(1);
        }

        public static string GetSystemMessage(uint errorCode)
        {
            int capacity = 512;
            int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
            StringBuilder sb = new StringBuilder(capacity);
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, errorCode, 0,
                sb, sb.Capacity, IntPtr.Zero);
            int i = sb.Length;
            if (i > 0 && sb[i - 1] == 10) i--;
            if (i > 0 && sb[i - 1] == 13) i--;
            sb.Length = i;
            return sb.ToString();
        }

    }
}
EDIT2在查看了此代码后:我用以下代码修改了我的代码:

NtOpenFile现在是:

[DllImport("ntdll.dll", ExactSpelling = true)]
        public static extern uint NtOpenFile(
            out  SafeFileHandle  handle,
            UInt32 access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            System.IO.FileShare share,
            uint openOptions
            );
[DllImport("ntdll.dll", ExactSpelling = true)]
public static extern uint NtQueryEaFile(
    SafeFileHandle handle,
    out IO_STATUS_BLOCK ioStatus,
    out IntPtr buffer,
    uint  length,
    bool retSingleEntry,
    IntPtr eaList,
    uint  eaListLength,
    IntPtr eaIndex,
    bool restartScan
    );
UInt32 FILE_OPEN = 0x1;
            UInt32 OBJ_CASE_INSENSITIVE = 0x40;
            UInt32 FILE_READ_EA = 8;
            UInt32 FILE_RANDOM_ACCESS = 0x00000800;
            UInt32 FILE_DIRECTORY_FILE = 0x00000002;
            UInt32 FILE_NON_DIRECTORY_FILE = 0x00000040;
            UInt32 FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
            UInt32 READ_CONTROL = 0x00020000;
            const UInt32 STATUS_NO_EAS_ON_FILE = 0xC0000052;

            uint status = NtOpenFile(out hFile, READ_CONTROL | FILE_READ_EA, ref objAttributes, out ioStatusBlock, FileShare.ReadWrite | FileShare.Delete, FILE_OPEN_FOR_BACKUP_INTENT);
            if (status != NT_SUCCESS)
                ExitWithError(status);           

            IntPtr buffer = Marshal.AllocHGlobal(65535);

            // status = NtQueryEaFile(fileHandle, &ioStatus, qbuf, sizeof(FILE_FULL_EA_INFORMATION), TRUE, NULL, 0, &QueryEAIndex, FALSE);
            status = NtQueryEaFile(hFile, out ioStatusBlock,out buffer, System.Convert.ToUInt32(Marshal.SizeOf(buffer)), returnSingleEntry, IntPtr.Zero, 0, IntPtr.Zero, restartScan);
            switch (status)
            {
                case STATUS_NO_EAS_ON_FILE:
                    Console.WriteLine("No EAs found");
                    break;

                case NT_SUCCESS:
                    Console.WriteLine("EAs found !");
                    break;

                default:
                    ExitWithError(status);
                    break;
            }                    
NtQueryEaFile现在是:

[DllImport("ntdll.dll", ExactSpelling = true)]
        public static extern uint NtOpenFile(
            out  SafeFileHandle  handle,
            UInt32 access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            System.IO.FileShare share,
            uint openOptions
            );
[DllImport("ntdll.dll", ExactSpelling = true)]
public static extern uint NtQueryEaFile(
    SafeFileHandle handle,
    out IO_STATUS_BLOCK ioStatus,
    out IntPtr buffer,
    uint  length,
    bool retSingleEntry,
    IntPtr eaList,
    uint  eaListLength,
    IntPtr eaIndex,
    bool restartScan
    );
UInt32 FILE_OPEN = 0x1;
            UInt32 OBJ_CASE_INSENSITIVE = 0x40;
            UInt32 FILE_READ_EA = 8;
            UInt32 FILE_RANDOM_ACCESS = 0x00000800;
            UInt32 FILE_DIRECTORY_FILE = 0x00000002;
            UInt32 FILE_NON_DIRECTORY_FILE = 0x00000040;
            UInt32 FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
            UInt32 READ_CONTROL = 0x00020000;
            const UInt32 STATUS_NO_EAS_ON_FILE = 0xC0000052;

            uint status = NtOpenFile(out hFile, READ_CONTROL | FILE_READ_EA, ref objAttributes, out ioStatusBlock, FileShare.ReadWrite | FileShare.Delete, FILE_OPEN_FOR_BACKUP_INTENT);
            if (status != NT_SUCCESS)
                ExitWithError(status);           

            IntPtr buffer = Marshal.AllocHGlobal(65535);

            // status = NtQueryEaFile(fileHandle, &ioStatus, qbuf, sizeof(FILE_FULL_EA_INFORMATION), TRUE, NULL, 0, &QueryEAIndex, FALSE);
            status = NtQueryEaFile(hFile, out ioStatusBlock,out buffer, System.Convert.ToUInt32(Marshal.SizeOf(buffer)), returnSingleEntry, IntPtr.Zero, 0, IntPtr.Zero, restartScan);
            switch (status)
            {
                case STATUS_NO_EAS_ON_FILE:
                    Console.WriteLine("No EAs found");
                    break;

                case NT_SUCCESS:
                    Console.WriteLine("EAs found !");
                    break;

                default:
                    ExitWithError(status);
                    break;
            }                    
对NtOpenFile的调用现在是:

[DllImport("ntdll.dll", ExactSpelling = true)]
        public static extern uint NtOpenFile(
            out  SafeFileHandle  handle,
            UInt32 access,
            ref OBJECT_ATTRIBUTES objectAttributes,
            out IO_STATUS_BLOCK ioStatus,
            System.IO.FileShare share,
            uint openOptions
            );
[DllImport("ntdll.dll", ExactSpelling = true)]
public static extern uint NtQueryEaFile(
    SafeFileHandle handle,
    out IO_STATUS_BLOCK ioStatus,
    out IntPtr buffer,
    uint  length,
    bool retSingleEntry,
    IntPtr eaList,
    uint  eaListLength,
    IntPtr eaIndex,
    bool restartScan
    );
UInt32 FILE_OPEN = 0x1;
            UInt32 OBJ_CASE_INSENSITIVE = 0x40;
            UInt32 FILE_READ_EA = 8;
            UInt32 FILE_RANDOM_ACCESS = 0x00000800;
            UInt32 FILE_DIRECTORY_FILE = 0x00000002;
            UInt32 FILE_NON_DIRECTORY_FILE = 0x00000040;
            UInt32 FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
            UInt32 READ_CONTROL = 0x00020000;
            const UInt32 STATUS_NO_EAS_ON_FILE = 0xC0000052;

            uint status = NtOpenFile(out hFile, READ_CONTROL | FILE_READ_EA, ref objAttributes, out ioStatusBlock, FileShare.ReadWrite | FileShare.Delete, FILE_OPEN_FOR_BACKUP_INTENT);
            if (status != NT_SUCCESS)
                ExitWithError(status);           

            IntPtr buffer = Marshal.AllocHGlobal(65535);

            // status = NtQueryEaFile(fileHandle, &ioStatus, qbuf, sizeof(FILE_FULL_EA_INFORMATION), TRUE, NULL, 0, &QueryEAIndex, FALSE);
            status = NtQueryEaFile(hFile, out ioStatusBlock,out buffer, System.Convert.ToUInt32(Marshal.SizeOf(buffer)), returnSingleEntry, IntPtr.Zero, 0, IntPtr.Zero, restartScan);
            switch (status)
            {
                case STATUS_NO_EAS_ON_FILE:
                    Console.WriteLine("No EAs found");
                    break;

                case NT_SUCCESS:
                    Console.WriteLine("EAs found !");
                    break;

                default:
                    ExitWithError(status);
                    break;
            }                    
你猜怎么着?它起作用了!好几乎正确读取没有EAs的目录会在文件上抛出状态\u no\u EAs\u。但是读取带有EAs的目录会抛出一个状态“缓冲区”太小,因此我的缓冲区定义/分配确实有一些pbr:-/

有关NtOpenFile的文档可以在MSDN上找到。对于NtQueryAfile,我认为您可以参考Windows驱动程序工具包中的ZWQueryAfile例程。大部分的Zw。。。例程复制本机NT API调用NT…,因此签名应该相同

从ZWQueryAfile调用NtQueryAfile:


我的建议是从C++中获得一些工作代码并从那里开始。然后您就有了一些已知的工作,剩下的就是互操作。为什么使用Pack=0?是什么让你使用SetLastError=true的?我可以告诉你,第二个参数缓冲区完全错了。这不是一个外号。这是您分配的缓冲区。所以[Out]字节[]将是一个不错的选择。无论如何,由于这是一个没有文档记录的函数,我们很难知道什么是对的或错的。您确定需要使用未记录的API吗?对于Pack=0的使用,默认值为0。不管怎样,在AIK和SetLastError中,它来自此示例SetLastError是错误的。此函数不调用SetLastError。关于SetLastError,您是对的,已将其删除。但无论如何,这不是拒绝访问的原因。在更多的搜索之后,我偶然发现了这个源代码:我更改了NtOpenFile的DLLImport:Access现在是Uint32而不是System.IO.FileAccess,所以我可以使用READ_CONTROL | FILE_READ_EA作为值,我将用新的细节更新我的问题