代码之家  ›  专栏  ›  技术社区  ›  0xC0000022L

以非特权用户身份查询NTFS特殊文件的元数据?

  •  1
  • 0xC0000022L  · 技术社区  · 6 年前

    在没有特权的用户上下文中,如何查询ntfs特殊文件的大小?

    大小对我来说是最重要的元数据,但是如果我能得到 WIN32_FIND_DATA 我不介意。

    我的意思是,ntfs特殊文件包括: $Mft , $MftMirr , $LogFile , $BadClus 等等。

    为了打开mft,我必须获得某些特权,打开卷,然后解析mft。那就结束了。

    而且,似乎不可能按名称打开这些文件(对于大多数文件),这就排除了 NtQueryInformationFile() GetFileInformationByHandle() . 或者是我没试过的旗帜组合 可以以某种方式打开它们以查询文件信息吗?

    最后但并非最不重要的是,在使用各自的win32api时,我没有得到这些文件的返回( FindFirstFile() 等),或 NtQueryDirectoryFile() 也不是用 IRP_MN_QUERY_DIRECTORY 直接的。


    是的,我知道我可以用 FSCTL_GET_NTFS_VOLUME_DATA ,但那只是这些特殊文件之一。

    1 回复  |  直到 6 年前
        1
  •  2
  •   RbMm    6 年前

    NTFS 卷我们可以枚举所有的文件记录 FSCTL_GET_NTFS_FILE_RECORD . 不幸的格式 FileRecordBuffer 在Windows标题中未记录/未声明。但这是常见的ntfs结构。缓冲区以开头 NTFS_RECORD_HEADER (基类)之后是几个 NTFS_ATTRIBUTE 记录。部分和自定义定义:

    union NTFS_FILE_ID 
    {
        LONGLONG IndexNumber;
    
        struct  
        {
            LONGLONG MftRecordIndex : 48;
            LONGLONG SequenceNumber : 16;
        };
    };
    
    struct NTFS_RECORD_HEADER 
    {
        enum {
            FILE = 'ELIF',
            INDX = 'XDNI',
            BAAD = 'DAAB',
            HOLE = 'ELOH',
            CHKD = 'DKHC'
        } Type;
        USHORT UsaOffset;
        USHORT UsaCount;
        USN Usn;
    };
    
    struct NTFS_FILE_RECORD_HEADER : public NTFS_RECORD_HEADER
    {
        USHORT SequenceNumber;
        USHORT LinkCount;
        USHORT AttributesOffset;
        USHORT Flags;
        ULONG BytesInUse;
        ULONG BytesAllocated;
        ULONGLONG BaseFileRecord;
        USHORT NextAttributeNumber;
    
        enum{
            flgInUse = 1, flgDirectory = 2
        };
    };
    
    struct NTFS_ATTRIBUTE 
    {
        enum ATTRIBUTE_TYPE {
            StandardInformation = 0x10,
            AttributeList = 0x20,
            FileName = 0x30,
            ObjectId = 0x40,
            SecurityDescriptor = 0x50,
            VolumeName = 0x60,
            VolumeInformation = 0x70,
            Data = 0x80,
            IndexRoot = 0x90,
            IndexAllocation = 0xa0,
            Bitmap = 0xb0,
            ReparsePoint = 0xc0,
            EAInformation = 0xd0,
            EA = 0xe0,
            PropertySet = 0xf0,
            LoggedUtilityStream = 0x100,
            StopTag = MAXDWORD
        } Type;
        ULONG Length;
        BOOLEAN Nonresident;
        UCHAR NameLength;
        USHORT NameOffset;
        USHORT Flags;// 1 = Compresed
        USHORT AttributeNumber;
    };
    
    struct NTFS_RESIDENT_ATTRIBUTE : public NTFS_ATTRIBUTE 
    {
        ULONG ValueLength;
        USHORT ValueOffset;
        USHORT Flags;
    };
    
    struct NTFS_NONRESIDENT_ATTRIBUTE : public NTFS_ATTRIBUTE 
    {
        LONGLONG LowVcn;
        LONGLONG HighVcn;
        USHORT RunArrayOffset;
        UCHAR CompressionUnit;
        UCHAR Unknown[5];
        LONGLONG AllocationSize;
        LONGLONG DataSize;
        LONGLONG InitializedSize;
        LONGLONG CompressedSize;
    };
    
    struct NTFS_ATTRIBUTE_LIST
    {
        NTFS_ATTRIBUTE::ATTRIBUTE_TYPE Type;
        USHORT Length;
        UCHAR NameLength;
        UCHAR NameOffset;
        LONGLONG LowVcn;
        LONGLONG FileReferenceNumber : 48;
        LONGLONG FileReferenceNumber2 : 16;
        USHORT AttributeNumber;
        USHORT Unknown[3];
    };
    
    struct NTFS_STANDARD_ATTRIBUTE 
    {
        LONGLONG CreationTime;
        LONGLONG ChangeTime;
        LONGLONG LastWriteTime;
        LONGLONG LastAccessTime;
        ULONG FileAttributes;
        ULONG Unknown[3];
        ULONG QuotaId;
        ULONG SecurityId;
        ULONGLONG QuotaChange;
        USN Usn;
    };
    
    struct NTFS_FILENAME_ATTRIBUTE
    {
        NTFS_FILE_ID DirectoryId;
        LONGLONG CreationTime;
        LONGLONG ChangeTime;
        LONGLONG LastWriteTime;
        LONGLONG LastAccessTime;
        LONGLONG AllocationSize;
        LONGLONG DataSize;
        ULONG FileAttributes;
        ULONG EaSize;
        UCHAR FileNameLength;// in symbols !!
        UCHAR NameType;
        WCHAR FileName[];
    
        enum {
            systemName , longName, shortName, systemName2
        };
    };
    

    枚举所有文件的代码可以如下所示:

    inline ULONG BOOL_TO_ERROR(BOOL f)
    {
        return f ? NOERROR : GetLastError();
    }
    
    ULONG QFMD(PCWSTR szVolumeName)
    {
        HANDLE hVolume = CreateFile(szVolumeName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
    
        if (hVolume == INVALID_HANDLE_VALUE)
        {
            return GetLastError();
        }
    
        ULONG cb, BytesReturned;
        NTFS_VOLUME_DATA_BUFFER nvdb;
    
        ULONG err = BOOL_TO_ERROR(DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, 0, 0, &nvdb, sizeof(nvdb), &BytesReturned, 0));
    
        if (err == NOERROR)
        {
            NTFS_FILE_RECORD_INPUT_BUFFER nfrib;
    
            cb = FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer[nvdb.BytesPerFileRecordSegment]);
    
            PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)alloca(cb);
    
            // search for maximum valid FileReferenceNumber
            LONG a = 0, b = MAXLONG, o;
            do 
            {
                nfrib.FileReferenceNumber.QuadPart = o = (a + b) >> 1;
    
                err = BOOL_TO_ERROR(DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
                    &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0));
    
                err ? b = o : a = o + 1;
    
            } while(a < b);
    
            nfrib.FileReferenceNumber.QuadPart--;
    
            DbgPrint("MftRecordCount=%u\n", nfrib.FileReferenceNumber.LowPart);
    
    
            union {
                PVOID FileRecordBuffer;
                PBYTE pb;
                NTFS_RECORD_HEADER* pnrh;
                NTFS_FILE_RECORD_HEADER* pnfrh;
                NTFS_ATTRIBUTE* pna;
                NTFS_RESIDENT_ATTRIBUTE* pnra;
                NTFS_NONRESIDENT_ATTRIBUTE* pnaa;
            };
    
            NTFS_FILE_ID nfi;
            UNICODE_STRING us = { sizeof (nfi), sizeof (nfi), (PWSTR)&nfi };
            OBJECT_ATTRIBUTES oa = { sizeof(oa), hVolume, &us };
    
            do 
            {
                FileRecordBuffer = pnfrob->FileRecordBuffer;
    
                if (err = BOOL_TO_ERROR(DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
                    &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0)))
                {
                    break;
                }
    
                // are really file
                if (
                    pnrh->Type != NTFS_RECORD_HEADER::FILE ||
                    !(pnfrh->Flags & NTFS_FILE_RECORD_HEADER::flgInUse) ||
                    pnfrh->BaseFileRecord
                    )
                {
                    continue;
                }
    
                ULONG FileAttributes = INVALID_FILE_ATTRIBUTES;
                ULONGLONG FileSize = 0;
    
                nfi.MftRecordIndex = pnfrob->FileReferenceNumber.QuadPart;
                nfi.SequenceNumber = pnfrh->SequenceNumber;
    
                pb += pnfrh->AttributesOffset;
    
                for( ; ; ) 
                {
                    NTFS_FILENAME_ATTRIBUTE* pnfa;
                    NTFS_STANDARD_ATTRIBUTE* pnsa;
    
                    switch (pna->Type)
                    {
                    case NTFS_ATTRIBUTE::StopTag:
                        goto __end;
    
                    case NTFS_ATTRIBUTE::FileName:
    
                        pnfa = (NTFS_FILENAME_ATTRIBUTE*)RtlOffsetToPointer(pnra, pnra->ValueOffset);
    
                        if (pnfa->NameType == NTFS_FILENAME_ATTRIBUTE::longName)
                        {
                            //DbgPrint("<< %.*S\n", pnfa->FileNameLength, pnfa->FileName);
                        }
                        break;
    
                    case NTFS_ATTRIBUTE::StandardInformation:
    
                        pnsa = (NTFS_STANDARD_ATTRIBUTE*)RtlOffsetToPointer(pnra, pnra->ValueOffset);
                        FileAttributes = pnsa->FileAttributes;
                        break;
    
                    case NTFS_ATTRIBUTE::Data:
                        FileSize += pna->Nonresident ? pnaa->DataSize : pnra->ValueLength;
                        break;
                    }
    
                    pb += pna->Length;
                }
    
    __end:;
    
                //HANDLE hFile;
                //IO_STATUS_BLOCK iosb;
    
                //NTSTATUS status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES, &oa, &iosb, FILE_SHARE_VALID_FLAGS,
                //  FILE_OPEN_REPARSE_POINT| FILE_OPEN_BY_FILE_ID | FILE_OPEN_FOR_BACKUP_INTENT);
    
                //if (0 <= status)
                //{
                //  NtClose(hFile);
                //}
    
    
            } while (0 <= (nfrib.FileReferenceNumber.QuadPart = pnfrob->FileReferenceNumber.QuadPart - 1));
    
        }
    
        CloseHandle(hVolume);
    
        return err;
    }
    

    一些 NTFS System Files ,但此列表已旧,存在更多系统文件。如果需要具体的系统文件查询,需要将其编号分配给 NTFS_FILE_RECORD_INPUT_BUFFER . 仅查询sys文件的少量更改代码:

    ULONG QFMD(PCWSTR szVolumeName)
    {
        HANDLE hVolume = CreateFile(szVolumeName, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
    
        if (hVolume == INVALID_HANDLE_VALUE)
        {
            return GetLastError();
        }
    
        ULONG cb, BytesReturned;
        NTFS_VOLUME_DATA_BUFFER nvdb;
    
        ULONG err = BOOL_TO_ERROR(DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, 0, 0, &nvdb, sizeof(nvdb), &BytesReturned, 0));
    
        if (err == NOERROR)
        {
            NTFS_FILE_RECORD_INPUT_BUFFER nfrib;
    
            nfrib.FileReferenceNumber.QuadPart = 0x30;
    
            cb = FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer[nvdb.BytesPerFileRecordSegment]);
    
            PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)alloca(cb);
    
            union {
                PVOID FileRecordBuffer;
                PBYTE pb;
                NTFS_RECORD_HEADER* pnrh;
                NTFS_FILE_RECORD_HEADER* pnfrh;
                NTFS_ATTRIBUTE* pna;
                NTFS_RESIDENT_ATTRIBUTE* pnra;
                NTFS_NONRESIDENT_ATTRIBUTE* pnaa;
            };
    
            NTFS_FILE_ID nfi;
            UNICODE_STRING us = { sizeof (nfi), sizeof (nfi), (PWSTR)&nfi };
            OBJECT_ATTRIBUTES oa = { sizeof(oa), hVolume, &us };
    
            do 
            {
                FileRecordBuffer = pnfrob->FileRecordBuffer;
    
                if (err = BOOL_TO_ERROR(DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
                    &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0)))
                {
                    break;
                }
    
                // are really file
                if (
                    pnrh->Type != NTFS_RECORD_HEADER::FILE ||
                    !(pnfrh->Flags & NTFS_FILE_RECORD_HEADER::flgInUse) ||
                    pnfrh->BaseFileRecord
                    )
                {
                    continue;
                }
    
                ULONG FileAttributes = INVALID_FILE_ATTRIBUTES;
                ULONGLONG FileSize = 0;
                PCWSTR ShortName = 0, LongName = 0, SystemName = 0;
                UCHAR ShortNameLength = 0, LongNameLength = 0, SystemNameLength = 0;
    
                nfi.MftRecordIndex = pnfrob->FileReferenceNumber.QuadPart;
                nfi.SequenceNumber = pnfrh->SequenceNumber;
    
                pb += pnfrh->AttributesOffset;
    
                BOOL bSysFile = FALSE;
    
                for( ; ; ) 
                {
                    union {
                        NTFS_FILENAME_ATTRIBUTE* pnfa;
                        NTFS_STANDARD_ATTRIBUTE* pnsa;
                    };
    
                    switch (pna->Type)
                    {
                    case NTFS_ATTRIBUTE::StopTag:
                        goto __end;
    
                    case NTFS_ATTRIBUTE::FileName:
    
                        pnfa = (NTFS_FILENAME_ATTRIBUTE*)RtlOffsetToPointer(pnra, pnra->ValueOffset);
    
                        switch (pnfa->NameType)
                        {
                        case NTFS_FILENAME_ATTRIBUTE::systemName:
                        case NTFS_FILENAME_ATTRIBUTE::systemName2:
                            bSysFile = TRUE;
                            SystemName = pnfa->FileName, SystemNameLength = pnfa->FileNameLength;
                            break;
                        case NTFS_FILENAME_ATTRIBUTE::longName:
                            LongName = pnfa->FileName, LongNameLength = pnfa->FileNameLength;
                            break;
                        case NTFS_FILENAME_ATTRIBUTE::shortName:
                            ShortName = pnfa->FileName, ShortNameLength = pnfa->FileNameLength;
                            break;
                        }
                        break;
    
                    case NTFS_ATTRIBUTE::StandardInformation:
    
                        pnsa = (NTFS_STANDARD_ATTRIBUTE*)RtlOffsetToPointer(pnra, pnra->ValueOffset);
                        FileAttributes = pnsa->FileAttributes;
                        break;
    
                    case NTFS_ATTRIBUTE::Data:
                        FileSize += pna->Nonresident ? pnaa->DataSize : pnra->ValueLength;
                        break;
                    }
    
                    pb += pna->Length;
                }
    
    __end:;
    
                if (bSysFile)
                {
                    HANDLE hFile;
                    IO_STATUS_BLOCK iosb;
    
                    NTSTATUS status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES, &oa, &iosb, FILE_SHARE_VALID_FLAGS,
                        FILE_OPEN_REPARSE_POINT| FILE_OPEN_BY_FILE_ID | FILE_OPEN_FOR_BACKUP_INTENT);
    
                    if (0 <= status)
                    {
                        NtClose(hFile);
                    }
    
                    char sz[32];
                    StrFormatByteSize64A(FileSize, sz, RTL_NUMBER_OF(sz));
                    DbgPrint("%I64u: %08x %s [%x] %.*S\n", pnfrob->FileReferenceNumber.QuadPart, 
                        FileAttributes, sz, status, SystemNameLength, SystemName);
                }
    
    
            } while (0 <= (nfrib.FileReferenceNumber.QuadPart = pnfrob->FileReferenceNumber.QuadPart - 1));
    
        }
    
        CloseHandle(hVolume);
    
        return err;
    }
    

    我得到了下一个结果:

    38: 10000006 0 bytes [0] $Deleted
    34: 00000020 10.0 MB [0] $TxfLogContainer00000000000000000002
    33: 00000020 10.0 MB [0] $TxfLogContainer00000000000000000001
    32: 00000020 64.0 KB [0] $TxfLog.blf
    31: 00000026 1.00 MB [0] $Tops
    30: 80000006 0 bytes [0] $Txf
    29: 00000006 0 bytes [0] $TxfLog
    28: 00000026 27.0 MB [0] $Repair
    27: 00000006 0 bytes [0] $RmMetadata
    26: 20000026 0 bytes [c0000034] $Reparse
    25: 20000026 0 bytes [c0000034] $ObjId
    24: 20000026 0 bytes [c0000034] $Quota
    11: 00000006 0 bytes [0] $Extend
    10: 00000006 128 KB [0] $UpCase
    9: 20000006 0 bytes [c0000034] $Secure
    8: 00000006 237 GB [c0000022] $BadClus
    7: 00000006 8.00 KB [c0000022] $Boot
    6: 00000006 7.42 MB [c0000022] $Bitmap
    5: 00000806 0 bytes [0] .
    4: 00000006 2.50 KB [0] $AttrDef
    3: 00000006 0 bytes [0] $Volume
    2: 00000006 64.0 MB [c0000022] $LogFile
    1: 00000006 4.00 KB [0] $MFTMirr
    0: 00000006 212 MB [0] $MFT