about ZwQueryDirectoryFile ?

Hi, all.

In application mode, I got the below result by FindFirstFile API.

CString strFolder;
WIN32_FIND_DATA FindData = { 0 };
HANDLE handle = NULL;

strFolder = L"c:\docume~1";

handle = FindFirstFile(strFolder, &FindData);

As result, it returns “Documents and Settings” in cFileName field and “DOCUME~1” in cAlternate field.

In kernel mode, I write below code to get the same result.

NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING uszDosDevicePath = CONSTANT_UNICODE_STRING(L"\??\c:\docume~1");
HANDLE hFindFile;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
struct SEARCH_BUFFER {
FILE_BOTH_DIR_INFORMATION DirInfo;
WCHAR Names[260];
} buffer;
PFILE_BOTH_DIR_INFORMATION pFileBothDirInfo;

InitializeObjectAttributes(&ObjectAttributes, &uszDosDevicePath, OBJ_CASE_INSENSITIVE, 0, 0);

status = ZwOpenFile(&hFindFile, FILE_LIST_DIRECTORY | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);

RtlZeroMemory(&buffer, sizeof(buffer));
pFileBothDirInfo = &buffer.DirInfo;

status = ZwQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pFileBothDirInfo,
sizeof(buffer),
FileBothDirectoryInformation,
TRUE,
NULL,
FALSE
);
if (!NT_SUCCESS(status))
{
ZwClose(hFindFile);
return;
}

ZwQueryDirectoryFile returns STATUS_SUCCESS, but pFileBothDirInfo->FileName is “.”, not “Documents and Settings”.

Q1 : Why it returns the different result of Ring3? How can i get the same result ?.

And after that, I called it again.

pFileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION) bufNext;

status = ZwQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pFileBothDirInfo,
4096,
FileBothDirectoryInformation,
FALSE,
NULL,
FALSE
);

It also returns STATUS_SUCCESS, but pFileBothDirInfo didn’t query some folders such as “administrator” or “TestPC” (“TestPC” is a windows user name).
But in Ring3 mode, I can get all directory infos by FindNextFile.

Q2. How can i get all all directory informations in kernel mode?

Thanx.

Let me just preface this by saying that file systems are not really my
thing. That being said, it’s late, so here’s my guess.

The first thing is that I think that there are a couple of things going
on here. Notice that ZwQueryDirectoryFile() breaks out the directory
(in the form of a handle) from the filename/pattern. FindFirstFile()
searches based on the path/pattern, which in your case happens to name
an actual directory, specified as a fullpath, so it returns that and
only that, because it’s the only file system entry on that volume with
that matches or can match that. ZwQueryDirectoryFile(), however,
appears to search within the directory that the handle implicitly
specifies, which means that you won’t get a hit for the directory name
itself; you’d have to search 'c:' to get that hit. Since you don’t
specify a filename/pattern, which it takes to mean all entries in the
directory, it just returns the first filename it finds, which happens to
be “.”

The second issue, which is I think why you’re not seeing certain
folders, is perhaps that you are not correctly processing the variable
length portion of the data, or possibly just because you’re buffer is
too small. According to MSDN, as long as the buffer is large enough to
contain the requested information for at least one full directory entry

  • in your case, FULL_BOTH_DIR_INFORMATION, very roughly 80 bytes + a
    variable part - ZwQueryDirectoryFile() will return STATUS_SUCCESS. It
    might be the case that you just need to repeat this process until it
    returns an empty buffer and STATUS_NO_MORE_FILES. Maybe there is an
    additional issue, which is quite possible as I really don’t know much
    about file systems, but I don’t really see anything, considering that
    you can access all of them in user mode.

By the way, I don’t believe that there is necessarily any guarantee
about the order in which files are returned, so if you’re counting on
that, it will probably work, but it still isn’t a good idea, assuming
that what I said is indeed the case.

Good luck,

mm

xxxxx@gmail.com wrote:

Hi, all.

In application mode, I got the below result by FindFirstFile API.

CString strFolder;
WIN32_FIND_DATA FindData = { 0 };
HANDLE handle = NULL;

strFolder = L"c:\docume~1";

handle = FindFirstFile(strFolder, &FindData);

As result, it returns “Documents and Settings” in cFileName field and “DOCUME~1” in cAlternate field.

In kernel mode, I write below code to get the same result.

NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING uszDosDevicePath = CONSTANT_UNICODE_STRING(L"\??\c:\docume~1");
HANDLE hFindFile;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
struct SEARCH_BUFFER {
FILE_BOTH_DIR_INFORMATION DirInfo;
WCHAR Names[260];
} buffer;
PFILE_BOTH_DIR_INFORMATION pFileBothDirInfo;

InitializeObjectAttributes(&ObjectAttributes, &uszDosDevicePath, OBJ_CASE_INSENSITIVE, 0, 0);

status = ZwOpenFile(&hFindFile, FILE_LIST_DIRECTORY | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);

RtlZeroMemory(&buffer, sizeof(buffer));
pFileBothDirInfo = &buffer.DirInfo;

status = ZwQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pFileBothDirInfo,
sizeof(buffer),
FileBothDirectoryInformation,
TRUE,
NULL,
FALSE
);
if (!NT_SUCCESS(status))
{
ZwClose(hFindFile);
return;
}

ZwQueryDirectoryFile returns STATUS_SUCCESS, but pFileBothDirInfo->FileName is “.”, not “Documents and Settings”.

Q1 : Why it returns the different result of Ring3? How can i get the same result ?.

And after that, I called it again.

pFileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION) bufNext;

status = ZwQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pFileBothDirInfo,
4096,
FileBothDirectoryInformation,
FALSE,
NULL,
FALSE
);

It also returns STATUS_SUCCESS, but pFileBothDirInfo didn’t query some folders such as “administrator” or “TestPC” (“TestPC” is a windows user name).
But in Ring3 mode, I can get all directory infos by FindNextFile.

Q2. How can i get all all directory informations in kernel mode?

Thanx.

The ZwOpenFile() should be with “\??\c:” and L"docume~1" should be in Filename parameter of ZwQueryDirectoryFile(). Also ReturnSingleEntry should be TRUE to mimics FindFirstFile().

-bg

Few imp things;

ReturnSingleEntry should be set to TRUE in your case, since you except
to handle only one file.

RestartScan value should be set to TRUE for first time and subsequently
to FALSE.

Thirdly don’t set the size to 4096, set what the actual size is for the
buffer in your case sizeof(SEARCH_BUFFER)

The first two files that u get will always be “.” and “…”, put a check
and just ignore them.

Happy hunting

Regards
Mohan

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, March 27, 2008 8:08 AM
To: Windows File Systems Devs Interest List
Subject: [ntfsd] about ZwQueryDirectoryFile ?

Hi, all.

In application mode, I got the below result by FindFirstFile API.

CString strFolder;
WIN32_FIND_DATA FindData = { 0 };
HANDLE handle = NULL;

strFolder = L"c:\docume~1";

handle = FindFirstFile(strFolder, &FindData);

As result, it returns “Documents and Settings” in cFileName field and
“DOCUME~1” in cAlternate field.

In kernel mode, I write below code to get the same result.

NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING uszDosDevicePath =
CONSTANT_UNICODE_STRING(L"\??\c:\docume~1");
HANDLE hFindFile;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
struct SEARCH_BUFFER {
FILE_BOTH_DIR_INFORMATION DirInfo;
WCHAR Names[260];
} buffer;
PFILE_BOTH_DIR_INFORMATION pFileBothDirInfo;

InitializeObjectAttributes(&ObjectAttributes, &uszDosDevicePath,
OBJ_CASE_INSENSITIVE, 0, 0);

status = ZwOpenFile(&hFindFile, FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT);

RtlZeroMemory(&buffer, sizeof(buffer));
pFileBothDirInfo = &buffer.DirInfo;

status = ZwQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pFileBothDirInfo,
sizeof(buffer),
FileBothDirectoryInformation,
TRUE,
NULL,
FALSE
);
if (!NT_SUCCESS(status))
{
ZwClose(hFindFile);
return;
}

ZwQueryDirectoryFile returns STATUS_SUCCESS, but
pFileBothDirInfo->FileName is “.”, not “Documents and Settings”.

Q1 : Why it returns the different result of Ring3? How can i get the
same result ?.

And after that, I called it again.

pFileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION) bufNext;

status = ZwQueryDirectoryFile(
hFindFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
pFileBothDirInfo,
4096,
FileBothDirectoryInformation,
FALSE,
NULL,
FALSE
);

It also returns STATUS_SUCCESS, but pFileBothDirInfo didn’t query some
folders such as “administrator” or “TestPC” (“TestPC” is a windows user
name).
But in Ring3 mode, I can get all directory infos by FindNextFile.

Q2. How can i get all all directory informations in kernel mode?

Thanx.


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@rsystems.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

thanx, all.

I modified the code as you said, so I got the satisfied result for the first case(namly Q1).

But I can’t query the all directory files.
Could you help me about Q2 ?

( 4096 is the bytes length of bufNext. )

Thank you.

Really sad is that people who cannot read can (very easily) write info this forum. Below is excerpt from msdn documentation for ZwQueryDirectoryFile().
-bg

FileName
Pointer to a caller-allocated Unicode string containing the name of a file (or multiple files, if wildcards are used) within the directory specified by FileHandle. This parameter is optional and can be NULL.
If FileName is not NULL, only files whose names match the FileName string are included in the directory scan. If FileName is NULL, all files are included. If RestartScan is FALSE, the value of FileName is ignored.