Запросить метаданные для специальных файлов NTFS как непривилегированный пользователь? - PullRequest
0 голосов
/ 22 октября 2018

Из непривилегированного пользовательского контекста, как я могу запросить размер специальных файлов NTFS?

Размер - это самая важная часть метаданных для меня, но если бы я мог получить все, что обычно находится вWIN32_FIND_DATA Я бы не стал возражать.

Я имею в виду специальные файлы NTFS (среди прочих): $Mft, $MftMirr, $LogFile, $BadClus и так далее.

Чтобы открыть MFT, мне нужно получить определенные привилегии, открыть том и затем проанализировать MFT.Так что это не так.

Также, кажется, невозможно открыть эти файлы по имени (для большинства из них), что исключает NtQueryInformationFile() и GetFileInformationByHandle().Или, может быть, есть комбинация флагов, которые я не пробовал, и можно как-то открыть их для запроса информации о файле?

И последнее, но не менее важное: я не получаю эти файлывозвращается при использовании соответствующих API Win32 (FindFirstFile() и др.), ни с NtQueryDirectoryFile(), ни с использованием IRP_MN_QUERY_DIRECTORY напрямую.


Да, я понимаю, что могу эффективно получить размерMFT с использованием FSCTL_GET_NTFS_VOLUME_DATA, но это только один из этих специальных файлов.

1 Ответ

0 голосов
/ 23 октября 2018

на ntfs томе мы можем перечислить все записи в файле с FSCTL_GET_NTFS_FILE_RECORD.К сожалению, формат FileRecordBuffer недокументирован / не объявлен в заголовках окон.но это обычные нтф структуры.буфер начинается с 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 , но этот списокуже старый, существует больше системных файлов.если хотите запросить конкретный системный файл, присвойте ему номер 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
...