SetFilePointerEx API读取MFT

时间:2011-12-04 09:22:59

标签: c# .net windows winapi pinvoke

我想从分区上的MFT偏移中读取一些字节。我有分区句柄并成功读取1K字节,但SetFilePointerEx返回错误。请帮帮我。

int nread = 0;
IntPtr handle = IntPtr.Zero;
byte[] buff = new byte[1024];
IntPtr newaddress = IntPtr.Zero;
long MFTAddress = bytepersector * sectorpercluster * (long)MFTStart;
string driveRoot = "\\\\.\\c:";

IntPtr hRoot = CreateFile(driveRoot,
    GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    IntPtr.Zero,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    IntPtr.Zero);

SetFilePointerEx(hRoot, MFTAddress, ref newaddress, 0);

int error = GetLastError();
if (hRoot != IntPtr.Zero)
    handle = ReadFile(newaddress, buff, 1024,ref nread, new System.Threading.NativeOverlapped());

这是找到MFTOffset和其他信息的代码。

            uint nread = 0;
        IntPtr handle;
        byte[] buff = new byte[1024];
        string driveRoot = string.Concat("\\\\.\\", driveLetter);
        IntPtr hRoot = CreateFile(driveRoot,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            IntPtr.Zero);
        if (hRoot != IntPtr.Zero)
             ReadFile(hRoot, buff, 1024,out nread, IntPtr.Zero);
        string SystemFile = Convert.ToString(LittleEndian(4, new byte[] { buff[3], buff[4], buff[5], buff[6] }, typeof(string)));
        int BytePerSector = 0;
        int SectorPerCluster = 0;
        double MFTStart = 0;
        if (SystemFile == "NTFS")
        {
            listBox1.Items.Add(SystemFile);

            BytePerSector = (int)LittleEndian(2, new byte[] { buff[11], buff[12] }, BytePerSector.GetType());
            listBox1.Items.Add("Byte per Sector : " + BytePerSector);

            SectorPerCluster = (int)LittleEndian(1, new byte[] { buff[13] }, typeof(int));
            listBox1.Items.Add("Sector per Cluster : " + SectorPerCluster.ToString());

            MFTStart = (long)LittleEndian(8, new byte[]{
                buff[48],buff[49],buff[50],buff[51],buff[52],buff[53],buff[54],buff[55]}, typeof(long));
            listBox1.Items.Add("MFT LCN : " + MFTStart);

        }
        else
            listBox1.Items.Add("No NTFS Valoume");

我想读MFT。我在partition.i上找到了它的偏移量。我用CreateFile API获得了分区句柄然后我用ReadFile API从MBR中获得了MFT偏移量。比较结果与WinHex结果是正确的。现在我想转移到mft地址在partition.i上找到了SetFilePointer API来做到这一点。 我使用了SetFilePointer但是在使用ReadFile(newAddress)

时出错了
public static void ReadMFT(string DriveLetter, ulong MFTStart, int bytepersector, int sectorpercluster)
    {
        IntPtr handle = IntPtr.Zero;
        IntPtr newaddress = IntPtr.Zero;
        long MFTAddress = bytepersector * sectorpercluster * (long)MFTStart;
        string driveRoot = string.Concat("\\\\.\\", DriveLetter);
        IntPtr hRoot = CreateFile(driveRoot,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            IntPtr.Zero);

        **newaddress = SetFilePointer(hRoot, (ulong)MFTAddress, IntPtr.Zero, 0);**
        Console.WriteLine("hroot : " + hRoot.ToString());
        Console.WriteLine("MFTAddress : " + MFTAddress.ToString());
        Console.WriteLine("NewAddress : " + newaddress.ToString());
        if (hRoot.ToInt64() != INVALID_HANDLE_VALUE)
        {
            uint nread;
            byte[] buff = new byte[1024];
            if (**ReadFile(newaddress, buff, (uint)buff.Length, out nread, IntPtr.Zero)**)
                Console.WriteLine("Read successful");
            else
                Console.WriteLine("Read unsuccessful");

        }
        while (true)
        {
            //read other MFT Record
            break;
        }
    }

2 个答案:

答案 0 :(得分:2)

我可以看到以下错误:

  • 您没有检查CreateFile的成功或失败的返回值。
  • 您将错误的内容传递给ReadFile的第一个参数。您需要将句柄传递给文件。
  • 您使用了您不想要的重叠I / O,并且无法使用已编组的byte[]缓冲区。通过IntPtr.Zero或[{1}} lpOverlapped,具体取决于您的P / invoke的声明方式。
  • null不返回句柄,它返回一个布尔值,表示函数调用成功。
  • 您绝不能从托管代码中调用ReadFile。而是致电Marshal.GetLastWin32Error。原因在该方法的documentation中进行了解释。
  • 除非先前的API调用确实失败,否则请勿调用GetLastError。您没有检查SetFilePointerEx是否成功。就像Marshal.GetLastWin32Error一样,它返回一个布尔值来表示成功或失败。

答案 1 :(得分:1)

根据documentation 物理磁盘和卷 部分),如果要访问分区表,则必须使用DeviceIoControl。从Windows Vista开始适用限制和要求。

从文档链接的示例:Calling DeviceIoControl