Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTFSD
Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Help on getting and setting Extended Attribute of file windows.

jay96612jay96612 Member Posts: 16

I am trying to classify the file so that even the file is sent out to another PC, the DLP still can track the file if DLP software is installed on the target PC as well. So to classify the file I am querying and setting the extended Attribute of the file. But getting an error, I don't know whether missing something or what.

Successfully opened the file but getting errors on ZwSetEaFile and ZwQueryEaFile

Following errors once I run the code:
On querying the Extended Attribute(EA): System error 1392 has occurred. The file or directory is corrupted and unreadable.
On setting the Extended Attribute(EA): System error 255 has occurred. The extended attributes are inconsistent.

Really Need some helping hand. I will be very thankful to you.

Note: My code is in DriverEntry

Attached code:

        NTSTATUS status;
    WCHAR filepathtoread[] = L"\\??\\\\E:\\test.txt";
    char header[10] = "EAdemo";
    LONG eaLength;
    PFILE_FULL_EA_INFORMATION eaBuffer = NULL; // to set
    PFILE_FULL_EA_INFORMATION pGetEA; // to get
    char Buffer[sizeof(FILE_FULL_EA_INFORMATION) + 20];
    IO_STATUS_BLOCK IoStatus;
    UNICODE_STRING str;
    OBJECT_ATTRIBUTES obj;
    HANDLE FileHandle;
    RtlInitUnicodeString(&str, filepathtoread);
    InitializeObjectAttributes(&obj, &str,OBJ_CASE_INSENSITIVE, NULL, NULL); // object attributes from file path

    status = NtOpenFile(&FileHandle,
        GENERIC_READ | FILE_READ_EA | FILE_WRITE_EA | SYNCHRONIZE,
        &obj,
        &IoStatus,
        0,
        FILE_SYNCHRONOUS_IO_NONALERT);

    if (!NT_SUCCESS(status)) {
        DbgPrint("EA:Error in open file: "); // Don't Close handle here because of invalid file handle
        return status;
    }
    DbgPrint("EA:Success in open file: ");

    eaLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) + sizeof(header) + 1;
    eaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, eaLength, '1EBA');

    if (NULL == eaBuffer) {
        DbgPrint("EA:Error in ExAllocatePoolWithTag ");
        NtClose(FileHandle);
        return status;
    }

    RtlZeroMemory(eaBuffer, eaLength);

    eaBuffer->NextEntryOffset = 0;
    eaBuffer->Flags = 0;
    eaBuffer->EaNameLength = (UCHAR)strlen(header);
    eaBuffer->EaValueLength = (USHORT)strlen(header);

    RtlCopyMemory(&eaBuffer->EaName[0], header, strlen(header) + 1);

    status = ZwSetEaFile(FileHandle,
        &IoStatus,
        eaBuffer,
        eaLength);

    if (!NT_SUCCESS(status)) {
        DbgPrint("EA:Error in ZwSetEaFile ");
        NtClose(FileHandle);
        return status;
    }
    DbgPrint("EA: EA set success.. Now Reading.. ");

    status = ZwQueryEaFile(FileHandle,
        &IoStatus,
        (PFILE_FULL_EA_INFORMATION)Buffer,
        sizeof(Buffer),
        TRUE,
        NULL,
        0,
        NULL,
        TRUE);

    if (!NT_SUCCESS(status)) {
        DbgPrint("EA:Error in ZwQueryEaFile ");
        NtClose(FileHandle);
        return status;
    }

    pGetEA = (PFILE_FULL_EA_INFORMATION)Buffer;

    DbgPrint("EA:EA is %S\n", pGetEA->EaName[0]);

    NtClose(FileHandle);

Comments

  • rod_widdowsonrod_widdowson Member - All Emails Posts: 1,158

    It won’t help, but

    • your eaLength calculation is wrong, you haven’t allowed space for the data so the write is over reading, you would have crashed under verify
    • It would be nice to know the NTSTATUS values not the post-digested Windows error
    • The +1 is totally suspicious. In Windows all strings are counted not zero terminated.

    None if which explain the behavior

  • jay96612jay96612 Member Posts: 16

    @rod_widdowson The NTSTATUS value is STATUS_EA_LIST_INCONSISTENT on calling ZwSetEaFile. can you please tell me the correct calculation for eaLength? I am lost now. Thank you very much for the info.

  • rod_widdowsonrod_widdowson Member - All Emails Posts: 1,158

    eaLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) + sizeof(header) + 1;

    The length has to be large enough for

    • The header part: FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0])
    • The name: sizeof(header)
    • The data: + 1;

    but you are setting the data length to be eaBuffer->EaValueLength = (USHORT)strlen(header);

    Try setting the eaLength to FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) + sizeof(header) + sizeof(header) or eaBuffer->EaValueLength = 1

  • jay96612jay96612 Member Posts: 16

    @rod_widdowson Thank you so much for clearing it to me. I have got the point now. You saved my day. Thanks a lot.

  • Dejan_MaksimovicDejan_Maksimovic Member - All Emails Posts: 350
    via Email
    Let's not make that hasty statement. Event in kernel mode that is not
    true, and it is completely false in user mode.

    On 10/10/20, rod_widdowson wrote:
    > OSR https://community.osr.com/
    > * The +1 is totally suspicious. In Windows all strings are counted not zero
    > terminated.
  • jay96612jay96612 Member Posts: 16

    @rod_widdowson How we are storing more than 1 bytes in EaName as EaName is an array of a single character.
    Look at this line:

        RtlCopyMemory(&eaBuffer->EaName[0], header, strlen(header) + 1);
    
    

    and 1 more thing since attributes are key/value pair so where can we store the value of a key.
    I don't see any value field in FILE_FULL_EA_INFORMATION structure.
    FILE_FULL_EA_INFORMATION structure for your reference:

    typedef struct _FILE_FULL_EA_INFORMATION {
      ULONG  NextEntryOffset;
      UCHAR  Flags;
      UCHAR  EaNameLength;
      USHORT EaValueLength;
      CHAR   EaName[1];
    } FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
    

    Please suggest a way to do this.
    I need your expertise in this regard.
    Thank you so much.

  • rod_widdowsonrod_widdowson Member - All Emails Posts: 1,158

    You need to read the Fine manual

    The value(s) associated with each entry follows the EaName array. That is, an EA's values are located at EaName + (EaNameLength + 1).

  • jay96612jay96612 Member Posts: 16

    ok got it. Thanks a lot.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Writing WDF Drivers 7 Dec 2020 LIVE ONLINE
Internals & Software Drivers 25 Jan 2021 LIVE ONLINE
Developing Minifilters 8 March 2021 LIVE ONLINE