如何在C#中使用CreateFile打开目录以检查已删除的条目?

Fre*_*red 5 c# winapi

如何在C#中使用CreateFile打开目录以检查已删除文件的条目?或者现在不可能?我记得当能够使用CreateFile或可能的CreateFileEx在NTFS分区上打开目录时,但是在旧操作系统下使用C++.

到目前为止,我已经有足够的Windows API调用(到kernel32.dll)读取现有文件,但它不会打开目录:

using System;
using System.Collections.Generic;
using System.Text;

using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Runtime.ConstrainedExecution;
using System.Security;

namespace Kernel_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Kernel_Tools cKT = new Kernel_Tools();

            cKT.DoTest("C:\\Temp");
            cKT.DoTest("C:\\Temp\\test.txt");
        }
    }

    [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
    [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
    class Kernel_Tools
    {
        public void DoTest(string cTarget)
        {
            IntPtr cFile = NativeMethods.CreateFile(
                cTarget,
                NativeMethods.GENERIC_READ /* 0 or NativeMethods.GENERIC_READ */ ,
                FileShare.Read,
                IntPtr.Zero /* failed try: NativeMethods.OPEN_ALWAYS */,
                (FileMode) NativeMethods.OPEN_EXISTING,
                NativeMethods.FILE_FLAG_BACKUP_SEMANTICS /* 0 */ ,
                IntPtr.Zero);

            Console.WriteLine(cTarget);
            Console.WriteLine(cFile);

            if ((int)cFile != -1)
            {
                int length = 20;

                byte[] bytes = new byte[length];
                int numRead = 0;

                int ErrorCheck = NativeMethods.ReadFile(cFile, bytes, length, out numRead, IntPtr.Zero);
                // This sample code will not work for all files.
                //int r = NativeMethods.ReadFile(_handle, bytes, length, out numRead, IntPtr.Zero);
                // Since we removed MyFileReader's finalizer, we no longer need to
                // call GC.KeepAlive here.  Platform invoke will keep the SafeHandle
                // instance alive for the duration of the call.
                if (ErrorCheck == 0)
                {
                    Console.WriteLine("Read failed.");
                    NativeMethods.CloseHandle(cFile);
                    return;
                    //throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                if (numRead < length)
                {
                    byte[] newBytes = new byte[numRead];
                    Array.Copy(bytes, newBytes, numRead);
                    bytes = newBytes;
                }

                for (int i = 0; i < bytes.Length; i++)
                    Console.Write((char)bytes[i]);

                Console.Write("\n\r");

                //    Console.WriteLine();
                NativeMethods.CloseHandle(cFile);
            }
        }
    }

    [SuppressUnmanagedCodeSecurity()]
    internal static class NativeMethods
    {
        // Win32 constants for accessing files.
        internal const int GENERIC_READ = unchecked((int)0x80000000);

        internal const int FILE_FLAG_BACKUP_SEMANTICS = unchecked((int)0x02000000);

        internal const int OPEN_EXISTING = unchecked((int)3);

        // Allocate a file object in the kernel, then return a handle to it.
        [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
        internal extern static IntPtr CreateFile(
           String fileName,
           int dwDesiredAccess,
           System.IO.FileShare dwShareMode,
           IntPtr securityAttrs_MustBeZero,
           System.IO.FileMode dwCreationDisposition,
           int dwFlagsAndAttributes,
           IntPtr hTemplateFile_MustBeZero);

        // Use the file handle.
        [DllImport("kernel32", SetLastError = true)]
        internal extern static int ReadFile(
           IntPtr handle,
           byte[] bytes,
           int numBytesToRead,
           out int numBytesRead,
           IntPtr overlapped_MustBeZero);

        // Free the kernel's file object (close the file).
        [DllImport("kernel32", SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        internal extern static bool CloseHandle(IntPtr handle);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑1:修改它以使用OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS和GENERIC_READ.

当作为Vista管理用户运行时,这将打开并显示指定文本文件的开头,与原始文件一样,但仍无法打开目录.我猜我需要SE_BACKUP_NAME和SE_RESTORE_NAME权限,但我不确定如何指定除了将其作为本地计算机运行的服务(我只有最模糊的想法).

sco*_*ttm 7

AFAIK,这是一个相当复杂的过程.您不能只使用CreateFile并枚举"已删除的文件".您必须加载驱动器的主文件表,并枚举标记为已删除的文件,然后尝试从MFT中列出的磁盘位置加载数据.这将需要大量的Platform Invoked代码,并且可能需要对C#中的本机数据结构进行一些重新定义.

对你的问题的简短回答是这样的:

CreateFile("\\\\.\\PhysicalDrive0",
            GENERIC_READ,
            FILE_SHARE_READ|FILE_SHARE_WRITE,
            0,
            OPEN_EXISTING,
            0,
            NULL)
Run Code Online (Sandbox Code Playgroud)

您使用create file打开磁盘本身.

这是关于Code Project整个过程的一篇非常好的文章.但是,这一切都在c ++中.代码在那里,似乎你知道如何p\invoke,所以移植它不应该是一个问题.

编辑:

驱动器是外置的这一事实不应该让它变得更难,你仍然可以像我展示的那样打开磁盘(也许在连接驱动器后使用WMI工具查找路径).然后,您可以使用Wiki32页面上的FAT32信息来定义您可以读取MFT和文件系统的其他部分的数据结构.到达目的地后,您只需遍历目录表中的32字节文件定义,查看第一个字节:

0xE5    Entry has been previously erased and is available. File undelete utilities must replace this character with a regular character as part of the undeletion process.
Run Code Online (Sandbox Code Playgroud)