Thread: Help with ZwQueryDirectoryFile for my Driver.

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    3

    Help with ZwQueryDirectoryFile for my Driver.

    Hello,

    I am new to driver development and currently developing a my simple driver that will simply ask a directory (or folder) as input from user-mode (e.g "z:\") and display all the files/folders exists in it. By the way, the directory input is passed-on to the kernel and then the kernel will processed the request; then the kernel sends a message containing the list of files/folders that will be parsed by the user-mode for display..

    i've read the msdn about ZwQueryDirectoryFile that returns various kind of information about files in the directory and i don't know how to used it. ^_^

    Can you help me how can i get all the files/folders exists in a directory?

    If im in the right track of using ZwQueryDirectoryFile, can you help me how to use this routine on getting files/folders?..

    And If you have other ways aside from using ZwQueryDirectoryFile routine, can you give me an idea HOW and if you have sample snippets can you show it to me?..

    Any help will be greatly appriciated.

    Thanks in advance to you guys.. ^_^

    -taDo-

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Seems like "crossing the river to get to water" sort of thing to do. Why would you want to do this in a kernel driver, when all you are asking to do can be done in user-mode. Kernel drivers are supposed to do stuff that can't be done in user-mode.

    That aside, it looks like ZwQueryDirectoryFile would be the right thing to do. If you are not comfortable with calling such a function, then I suggest you play around with user-mode Windows for a bit longer before writing kernel drivers. [I haven't used that particular function, but I have a fair idea of how you would go about using it from reading the MSDN page on it].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    I'm curious as to why you added "hide files" in the message tags.

    You're not by any chance attempting to hook the OS service in order to modify the answers given back to user space, in order to "hide files" by any chance?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Salem View Post
    I'm curious as to why you added "hide files" in the message tags.

    You're not by any chance attempting to hook the OS service in order to modify the answers given back to user space, in order to "hide files" by any chance?
    Why would anyone (honest) want to do that?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by taDo View Post
    Hello,

    I am new to driver development and currently developing a my simple driver that will simply ask a directory (or folder) as input from user-mode (e.g "z:\") and display all the files/folders exists in it. By the way, the directory input is passed-on to the kernel and then the kernel will processed the request; then the kernel sends a message containing the list of files/folders that will be parsed by the user-mode for display..

    i've read the msdn about ZwQueryDirectoryFile that returns various kind of information about files in the directory and i don't know how to used it. ^_^

    Can you help me how can i get all the files/folders exists in a directory?

    If im in the right track of using ZwQueryDirectoryFile, can you help me how to use this routine on getting files/folders?..

    And If you have other ways aside from using ZwQueryDirectoryFile routine, can you give me an idea HOW and if you have sample snippets can you show it to me?..

    Any help will be greatly appriciated.

    Thanks in advance to you guys.. ^_^

    -taDo-
    Code:
    #include <windows.h>
    #include <stdio.h>
    
    typedef LONG NTSTATUS;
    typedef NTSTATUS *PNTSTATUS;
    typedef DWORD ULONG_PTR;
    
    #define STATUS_SUCCESS (NTSTATUS)0x00000000L
    #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
    #define FILE_OPEN               0x00000001
    #define OBJ_CASE_INSENSITIVE    0x00000040L
    #define FILE_DIRECTORY_FILE     0x00000001
    
    #define InitializeObjectAttributes( p, n, a, r, s ) {    \
        (p)->uLength = sizeof( OBJECT_ATTRIBUTES );          \
        (p)->hRootDirectory = r;                             \
        (p)->uAttributes = a;                                \
        (p)->pObjectName = n;                                \
        (p)->pSecurityDescriptor = s;                        \
        (p)->pSecurityQualityOfService = NULL;               \
    }
    
    typedef struct _UNICODE_STRING {
    	USHORT Length;
    	USHORT MaximumLength;
    	PWSTR  Buffer;
    } UNICODE_STRING;
    
    typedef UNICODE_STRING *PUNICODE_STRING;
    typedef const UNICODE_STRING *PCUNICODE_STRING;
    typedef USHORT RTL_STRING_LENGTH_TYPE;
    
    typedef struct _STRING {
    	USHORT Length;
    	USHORT MaximumLength;
    	PCHAR Buffer;
    } STRING;
    
    typedef STRING *PSTRING;
    typedef STRING ANSI_STRING;
    typedef PSTRING PANSI_STRING;
    
    typedef struct _OBJECT_ATTRIBUTES {
    	ULONG uLength;
    	HANDLE hRootDirectory;
    	PUNICODE_STRING pObjectName;
    	ULONG uAttributes;
    	PVOID pSecurityDescriptor;        
    	PVOID pSecurityQualityOfService;  
    } OBJECT_ATTRIBUTES;
    
    #define InitializeObjectAttributes( p, n, a, r, s ) {    \
        (p)->uLength = sizeof( OBJECT_ATTRIBUTES );          \
        (p)->hRootDirectory = r;                             \
        (p)->uAttributes = a;                                \
        (p)->pObjectName = n;                                \
        (p)->pSecurityDescriptor = s;                        \
        (p)->pSecurityQualityOfService = NULL;               \
    }
    
    typedef OBJECT_ATTRIBUTES * POBJECT_ATTRIBUTES;
    
    typedef struct _IO_STATUS_BLOCK {
    	union {
    		NTSTATUS Status;
    		PVOID Pointer;
    	};
    	ULONG_PTR Information;
    } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
    
    typedef VOID (NTAPI *PIO_APC_ROUTINE) (IN PVOID ApcContext, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved);
    
    typedef enum _FILE_INFORMATION_CLASS {
    	FileDirectoryInformation         = 1,
    		FileFullDirectoryInformation,   
    		FileBothDirectoryInformation,   
    		FileBasicInformation,          
    		FileStandardInformation,        
    		FileInternalInformation,        
    		FileEaInformation,              
    		FileAccessInformation,          
    		FileNameInformation,            
    		FileRenameInformation,          
    		FileLinkInformation,            
    		FileNamesInformation,           
    		FileDispositionInformation,    
    		FilePositionInformation,       
    		FileFullEaInformation,         
    		FileModeInformation,            
    		FileAlignmentInformation,       
    		FileAllInformation,             
    		FileAllocationInformation,     
    		FileEndOfFileInformation,      
    		FileAlternateNameInformation,  
    		FileStreamInformation,          
    		FilePipeInformation,          
    		FilePipeLocalInformation,       
    		FilePipeRemoteInformation,     
    		FileMailslotQueryInformation,   
    		FileMailslotSetInformation,     
    		FileCompressionInformation,    
    		FileObjectIdInformation,        
    		FileCompletionInformation,      
    		FileMoveClusterInformation,     
    		FileQuotaInformation,           
    		FileReparsePointInformation,   
    		FileNetworkOpenInformation,    
    		FileAttributeTagInformation,   
    		FileTrackingInformation,        
    		FileIdBothDirectoryInformation, 
    		FileIdFullDirectoryInformation, 
    		FileValidDataLengthInformation, 
    		FileShortNameInformation,       
    		FileMaximumInformation
    } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
    
    typedef enum _EVENT_TYPE {NotificationEvent, SynchronizationEvent} EVENT_TYPE;
    
    typedef struct _FILE_BOTH_DIR_INFORMATION {
    	ULONG NextEntryOffset;
    	ULONG FileIndex;
    	LARGE_INTEGER CreationTime;
    	LARGE_INTEGER LastAccessTime;
    	LARGE_INTEGER LastWriteTime;
    	LARGE_INTEGER ChangeTime;
    	LARGE_INTEGER EndOfFile;
    	LARGE_INTEGER AllocationSize;
    	ULONG FileAttributes;
    	ULONG FileNameLength;
    	ULONG EaSize;
    	CCHAR ShortNameLength;
    	WCHAR ShortName[12];
    	WCHAR FileName[1];
    } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
    
    NTSTATUS (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING, PCWSTR);
    NTSTATUS (WINAPI * pZwCreateFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
    NTSTATUS (WINAPI * pZwCreateEvent)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN);
    NTSTATUS (WINAPI * pZwQuerydirectoryFile)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN);
    NTSTATUS (WINAPI * pZwWaitForSingleobject)(HANDLE, BOOLEAN, PLARGE_INTEGER);
    NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PANSI_STRING, PCUNICODE_STRING, BOOLEAN);
    NTSTATUS (WINAPI * pZwClose)(HANDLE);
    
    void IntializeNativeFunctions(VOID)
    {
    	HMODULE hModule = LoadLibrary ("Ntdll.dll");
    
    	pRtlInitUnicodeString = (NTSTATUS (WINAPI *)(PUNICODE_STRING, PCWSTR)) GetProcAddress (hModule, "RtlInitUnicodeString");
    	pZwCreateFile = (NTSTATUS (WINAPI *)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG)) GetProcAddress (hModule, "ZwCreateFile");
    	pZwCreateEvent = (NTSTATUS (WINAPI *)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN)) GetProcAddress (hModule, "ZwCreateEvent");
    	pZwQuerydirectoryFile = (NTSTATUS (WINAPI *)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN)) GetProcAddress (hModule, "ZwQueryDirectoryFile");
    	pZwWaitForSingleobject = (NTSTATUS (WINAPI *)(HANDLE, BOOLEAN, PLARGE_INTEGER)) GetProcAddress (hModule, "ZwWaitForSingleObject");
    	pRtlUnicodeStringToAnsiString = (NTSTATUS (WINAPI *)(PANSI_STRING, PCUNICODE_STRING, BOOLEAN)) GetProcAddress (hModule, "RtlUnicodeStringToAnsiString");
    	pZwClose = (NTSTATUS (WINAPI *)(HANDLE)) GetProcAddress (hModule, "ZwClose");
    }
    
    NTSTATUS ListDirectory(WCHAR * pszDirectoryName)
    {
    	UNICODE_STRING RootDirectoryName;
    	ANSI_STRING as;
    	OBJECT_ATTRIBUTES RootDirectoryAttributes;
    	NTSTATUS ntStatus = STATUS_SUCCESS;
    	HANDLE RootDirectoryHandle;
    	IO_STATUS_BLOCK Iosb;
    	HANDLE Event;
    	PUCHAR Buffer[65536];
    	WCHAR wszBuffer[50];
    
    	PFILE_BOTH_DIR_INFORMATION DirInformation;
    
    	if(pRtlInitUnicodeString == NULL) return -1;
    	if(pRtlUnicodeStringToAnsiString == NULL) return -1;
    	_snwprintf(wszBuffer,sizeof(wszBuffer),L"\\??\\%s\\",pszDirectoryName);
    	ntStatus = ((pRtlInitUnicodeString)(&RootDirectoryName, wszBuffer));
    	if (!NT_SUCCESS(ntStatus))
    		return ntStatus;
    	InitializeObjectAttributes (&RootDirectoryAttributes, &RootDirectoryName, OBJ_CASE_INSENSITIVE, 0, 0);
    	if(pZwCreateFile == NULL) return -1;
    	ntStatus =((pZwCreateFile)(&RootDirectoryHandle,
    		GENERIC_READ,
    		&RootDirectoryAttributes,
    		&Iosb,
    		0,
    		FILE_ATTRIBUTE_DIRECTORY,
    		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    		FILE_OPEN,
    		FILE_DIRECTORY_FILE,
    		0, 0));
    
    	if (!NT_SUCCESS(ntStatus))
    	{
    		printf("Unable to open %s, error = 0x%x\n", &RootDirectoryName, ntStatus);
    		return ntStatus;
    	}
    	if(pZwCreateEvent == NULL) return -1;
    	ntStatus = ((pZwCreateEvent)(&Event, GENERIC_ALL, 0, NotificationEvent, FALSE));
    	if (!NT_SUCCESS(ntStatus))
    	{
    		printf("Event creation failed with error 0x%x\n", ntStatus);
    		return ntStatus;
    	}
    	if(pZwQuerydirectoryFile == NULL) return -1;
    	if(((pZwQuerydirectoryFile)(RootDirectoryHandle,
    		Event, 0, 0,
    		&Iosb,
    		Buffer,
    		sizeof(Buffer),
    		FileBothDirectoryInformation,
    		FALSE,
    		NULL,
    		FALSE)) == STATUS_PENDING)
    	{
    		if(pZwWaitForSingleobject == NULL) return -1;
    		ntStatus = ((pZwWaitForSingleobject)(Event, TRUE, 0));
    	}
    	if (!NT_SUCCESS(ntStatus))
    	{
    		printf("Unable to query directory contents, error 0x%x\n", ntStatus);
    		return ntStatus;
    	}
    	DirInformation = (PFILE_BOTH_DIR_INFORMATION) Buffer;
    	while (1)
    	{
    		UNICODE_STRING EntryName;
    		EntryName.MaximumLength = EntryName.Length = (USHORT) DirInformation -> FileNameLength;
    		EntryName.Buffer = &DirInformation -> FileName[0];
    		((pRtlUnicodeStringToAnsiString)(&as, &EntryName, TRUE));
    		printf("%s\n", as.Buffer);
    		if (0 == DirInformation -> NextEntryOffset)
    			break;
    		else
    			DirInformation = (PFILE_BOTH_DIR_INFORMATION) (((PUCHAR)DirInformation) + DirInformation -> NextEntryOffset);
    	}
    	((pZwClose)(RootDirectoryHandle));
    	return ntStatus;
    }
    
    int main(VOID)
    {
    	WCHAR wszDirectory[] = {L"C:\\Temp"};
    	IntializeNativeFunctions();
    	ListDirectory(wszDirectory);
    	return 0;
    }

  6. #6
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by matsp View Post
    Why would anyone (honest) want to do that?

    --
    Mats
    It's a common technique used by rootkit writers. The FindNextfile function calls NtQueryDirectoryFile from ntdll.dll. So, if the user hooks NtQueryDirectoryFile, the rootkit's code can execute in place of NTQueryDirectoryFile. Thus, allowing the rootkit code to determine what info is sent back to the FindNextfile call. It's just one of many ways to hide spurious binaries.

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by BobS0327 View Post
    It's a common technique used by rootkit writers. The FindNextfile function calls NtQueryDirectoryFile from ntdll.dll. So, if the user hooks NtQueryDirectoryFile, the rootkit's code can execute in place of NTQueryDirectoryFile. Thus, allowing the rootkit code to determine what info is sent back to the FindNextfile call. It's just one of many ways to hide spurious binaries.
    And writing Rootkits counts as "honest", right?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by matsp View Post
    And writing Rootkits counts as "honest", right?

    --
    Mats
    Rootkits are not inherently bad. It's just a technology. Honest or dishonest (good or bad) is determined by the end users. For example, law enforcement may use a rootkit installed on a target system sanctioned by the court system to collect evidence. Large corporations may use rootkits to monitor and enforce their computer use regulations.

    Writing a rootkit may only provide a good learning experience since rootkits by themselves are virtually useless. The rootkit is only beneficial when an attacker initiates an exploit on a targeted system AND acquires administrative level privileges. The admin level privileges are needed to install and run the rootkit. At that point, the rootkit is used to maintain access to the targeted system so that the exploit can deliver the payload which may be something like a keylogger etc.

    So, any rootkit from HackerDefender to Gromozon is virtually useless without admin privileges.

  9. #9
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Quote Originally Posted by matsp View Post
    And writing Rootkits counts as "honest", right?

    --
    Mats
    There can be various reasons for learning such things:
    a) It's a must-know for computer security experts
    b) It's a learning tool for people who want to know about the architecture of an OS
    c) It's an useful thing to know for people who want to stay up-to-date with modern "low-level world"
    d) It can help making malware

    By your logic every single F-Secure/Norton/etc employee is an "unethical person".
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  10. #10
    Registered User
    Join Date
    Apr 2007
    Posts
    137
    And see complete C samples in DDK, better than all you'll find on the Web..

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with ZwQueryDirectoryFile for my Driver.
    By taDo in forum Networking/Device Communication
    Replies: 1
    Last Post: 11-26-2008, 12:13 AM
  2. Help with ZwQueryDirectoryFile for my Driver.
    By taDo in forum C++ Programming
    Replies: 1
    Last Post: 11-26-2008, 12:13 AM
  3. Replies: 0
    Last Post: 07-28-2008, 03:10 AM
  4. Linux (2.6.10+) device driver: multiple classes?
    By filker0 in forum Linux Programming
    Replies: 3
    Last Post: 09-26-2005, 08:46 PM
  5. egavga.bgi
    By PING in forum Game Programming
    Replies: 6
    Last Post: 11-16-2004, 01:46 AM

Tags for this Thread