Windows驱动程序内核:如何枚举所有子目录和文件?

我在一个小的反垃圾邮件工作,我需要添加一个function是:

  • 删除rootkit目录下的所有文件,以及你可能的子目录。

所以,首先需要知道所有这些目录和文件,对吗?

对此,我有下面的代码已经使这个任务的一半。 他枚举特定目录的所有目录和文件,但不“查看”子目录(文件和文件夹)。

例如:

在这里输入图像说明

输出:

在这里输入图像说明

码:

#include <ntifs.h> typedef unsigned int UINT; NTSTATUS EnumFilesInDir() { HANDLE hFile = NULL; UNICODE_STRING szFileName = { 0 }; OBJECT_ATTRIBUTES Oa = { 0 }; NTSTATUS ntStatus = 0; IO_STATUS_BLOCK Iosb = { 0 }; UINT uSize = sizeof(FILE_BOTH_DIR_INFORMATION); FILE_BOTH_DIR_INFORMATION *pfbInfo = NULL; BOOLEAN bIsStarted = TRUE; RtlInitUnicodeString(&szFileName, L"\\??\\C:\\MyDirectory"); InitializeObjectAttributes(&Oa, &szFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); ntStatus = ZwCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &Oa, &Iosb, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, '0000'); if (pfbInfo == NULL) { ZwClose(hFile); return STATUS_NO_MEMORY; } while (TRUE) { lbl_retry: RtlZeroMemory(pfbInfo, uSize); ntStatus = ZwQueryDirectoryFile(hFile, 0, NULL, NULL, &Iosb, pfbInfo, uSize, FileBothDirectoryInformation, FALSE, NULL, bIsStarted); if (STATUS_BUFFER_OVERFLOW == ntStatus) { ExFreePoolWithTag(pfbInfo, '000'); uSize = uSize * 2; pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, '0000'); if (pfbInfo == NULL) { ZwClose(hFile); return STATUS_NO_MEMORY; } goto lbl_retry; } else if (STATUS_NO_MORE_FILES == ntStatus) { ExFreePoolWithTag(pfbInfo, '000'); ZwClose(hFile); return STATUS_SUCCESS; } else if (STATUS_SUCCESS != ntStatus) { ExFreePoolWithTag(pfbInfo, '000'); ZwClose(hFile); return ntStatus; } if (bIsStarted) { bIsStarted = FALSE; } while (TRUE) { WCHAR * szWellFormedFileName = ExAllocatePoolWithTag(PagedPool, (pfbInfo->FileNameLength + sizeof(WCHAR)), '0001'); if (szWellFormedFileName) { RtlZeroMemory(szWellFormedFileName, (pfbInfo->FileNameLength + sizeof(WCHAR))); RtlCopyMemory(szWellFormedFileName, pfbInfo->FileName, pfbInfo->FileNameLength); //KdPrint(("File name is: %S\n", szWellFormedFileName)); KdPrint((" %S\n", szWellFormedFileName)); ExFreePoolWithTag(szWellFormedFileName, '000'); } if (pfbInfo->NextEntryOffset == 0) { break; } pfbInfo += pfbInfo->NextEntryOffset; } } ZwClose(hFile); ExFreePoolWithTag(pfbInfo, '000'); return ntStatus; } 

那么,这是怎么回事?

提前感谢您的帮助或build议。


————————————————– – – – 编辑: – – – – – – – – – – – – – – – – – – – – – ————————–

我find了一个可能的解决scheme,但我在这一行中遇到了BSOD

 if ( (*pDir)->NextEntryOffset) 

KernelFindNextFile方法中。

一些build议?

这是我发现的代码:

 #include <ntifs.h> #include <stdlib.h> HANDLE KernelCreateFile(IN PUNICODE_STRING pstrFile,IN BOOLEAN bIsDir) { HANDLE hFile = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK StatusBlock = {0}; ULONG ulShareAccess = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE; ULONG ulCreateOpt = FILE_SYNCHRONOUS_IO_NONALERT; OBJECT_ATTRIBUTES objAttrib = {0}; ULONG ulAttributes = OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE; InitializeObjectAttributes(&objAttrib,pstrFile,ulAttributes,NULL,NULL); ulCreateOpt |= bIsDir?FILE_DIRECTORY_FILE:FILE_NON_DIRECTORY_FILE; Status = ZwCreateFile( &hFile, GENERIC_ALL, &objAttrib, &StatusBlock, 0, FILE_ATTRIBUTE_NORMAL, ulShareAccess, FILE_OPEN_IF, ulCreateOpt, NULL, 0); if (!NT_SUCCESS(Status)) { return (HANDLE)-1; } return hFile; } PFILE_BOTH_DIR_INFORMATION KernelFindFirstFile(IN HANDLE hFile,IN ULONG ulLen,OUT PFILE_BOTH_DIR_INFORMATION pDir) { NTSTATUS Status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK StatusBlock = {0}; PFILE_BOTH_DIR_INFORMATION pFileList = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,ulLen); Status = ZwQueryDirectoryFile( hFile,NULL,NULL,NULL, &StatusBlock, pDir, ulLen, FileBothDirectoryInformation, TRUE, NULL, FALSE); RtlCopyMemory(pFileList,pDir,ulLen); Status = ZwQueryDirectoryFile( hFile,NULL,NULL,NULL, &StatusBlock, pFileList, ulLen, FileBothDirectoryInformation, FALSE, NULL, FALSE); return pFileList; } NTSTATUS KernelFindNextFile(IN OUT PFILE_BOTH_DIR_INFORMATION* pDir) { if ( (*pDir)->NextEntryOffset) { (*pDir)=(PFILE_BOTH_DIR_INFORMATION)((UINT32)(*pDir)+(*pDir)->NextEntryOffset); return STATUS_SUCCESS; } return STATUS_UNSUCCESSFUL; } void Traversal() { UNICODE_STRING ustrFolder = {0}; WCHAR szSymbol[0x512] = L"\\??\\"; UNICODE_STRING ustrPath = RTL_CONSTANT_STRING(L"C:\\MyDirectory"); HANDLE hFile = NULL; SIZE_T nFileInfoSize = sizeof(FILE_BOTH_DIR_INFORMATION)+270*sizeof(WCHAR); SIZE_T nSize = nFileInfoSize*0x256; char strFileName[0x256] = {0}; PFILE_BOTH_DIR_INFORMATION pFileListBuf = NULL; PFILE_BOTH_DIR_INFORMATION pFileList = NULL; PFILE_BOTH_DIR_INFORMATION pFileDirInfo = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,nSize); wcscat_s(szSymbol,_countof(szSymbol),ustrPath.Buffer); RtlInitUnicodeString(&ustrFolder,szSymbol); hFile = KernelCreateFile(&ustrFolder,TRUE); pFileList = pFileListBuf; KernelFindFirstFile(hFile,nSize,pFileDirInfo); if (pFileList) { RtlZeroMemory(strFileName,0x256); RtlCopyMemory(strFileName,pFileDirInfo->FileName,pFileDirInfo->FileNameLength); if (strcmp(strFileName,"..")!=0 || strcmp(strFileName,".")!=0) { if (pFileDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { DbgPrint("[Directory]%S\n",strFileName); } else { DbgPrint("[File]%S\n",strFileName); } } } while (NT_SUCCESS(KernelFindNextFile(&pFileList))) { RtlZeroMemory(strFileName,0x256); RtlCopyMemory(strFileName,pFileList->FileName,pFileList->FileNameLength); if (strcmp(strFileName,"..")==0 || strcmp(strFileName,".")==0) { continue; } if (pFileList->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { DbgPrint("[Directory]%S\n",strFileName); } else { DbgPrint("[File]%S\n",strFileName); } } RtlZeroMemory(strFileName,0x256); RtlCopyMemory(strFileName,pFileListBuf->FileName,pFileListBuf->FileNameLength); if (strcmp(strFileName,"..")!=0 || strcmp(strFileName,".")!=0) { if (pFileDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { DbgPrint("[Directory]%S\n",strFileName); } else { DbgPrint("[File]%S\n",strFileName); } ExFreePool(pFileListBuf); ExFreePool(pFileDirInfo); } } 

BSOD:

 FAULTING_SOURCE_LINE_NUMBER: 263 FAULTING_SOURCE_CODE: 259: } 260: 261: NTSTATUS KernelFindNextFile(IN OUT PFILE_BOTH_DIR_INFORMATION* pDir) 262: { > 263: if ((*pDir)->NextEntryOffset) 264: { 265: (*pDir) = (PFILE_BOTH_DIR_INFORMATION)((UINT32)(*pDir) + (*pDir)->NextEntryOffset); 266: return STATUS_SUCCESS; 267: } 268: 

好的,这里测试工作的代码。 如果有人不能使用它或得到蓝屏 – 可能问题不是在代码,但在某些人的技能

几个注意事项 – 如果你有以前的模式内核 – 使用Nt* API(当出口),而不是Zw* API。 或者Io* api。 如果你不明白为什么,或者你以前的模式是什么 – 最好甚至不要在内核中尝试编程。

强制使用FILE_OPEN_REPARSE_POINT选项,甚至不尝试运行这个代码,如果不明白这是什么,为什么需要使用

删除 – 使用FILE_DELETE_ON_CLOSE选项打开文件,仅转储 – 使用FILE_DIRECTORY_FILE选项。

你自己使用的代码<= 0x1800字节的堆栈在x64在最深的文件夹,如c:\Users – 所以这对内核是好的,但总是检查堆栈空间与IoGetRemainingStackSize

如果你不能自己做这个,我的代码中每个逗号都是不正确的

 #define ALLOCSIZE PAGE_SIZE #ifdef _REAL_DELETE_ #define USE_DELETE_ON_CLOSE FILE_DELETE_ON_CLOSE #else #define USE_DELETE_ON_CLOSE FILE_DIRECTORY_FILE #endif // int nLevel, PSTR prefix for debug only void ntTraverse(POBJECT_ATTRIBUTES poa, ULONG FileAttributes, int nLevel, PSTR prefix) { if (IoGetRemainingStackSize() < PAGE_SIZE) { DbgPrint("no stack!\n"); return ; } if (nLevel > MAXUCHAR) { DbgPrint("nLevel > MAXUCHAR\n"); return ; } NTSTATUS status; IO_STATUS_BLOCK iosb; UNICODE_STRING ObjectName; OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName }; DbgPrint("%s[<%wZ>]\n", prefix, poa->ObjectName); #ifdef _REAL_DELETE_ if (FileAttributes & FILE_ATTRIBUTE_READONLY) { if (0 <= NtOpenFile(&oa.RootDirectory, FILE_WRITE_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT|FILE_OPEN_REPARSE_POINT)) { static FILE_BASIC_INFORMATION fbi = { {}, {}, {}, {}, FILE_ATTRIBUTE_NORMAL }; NtSetInformationFile(oa.RootDirectory, &iosb, &fbi, sizeof(fbi), FileBasicInformation); NtClose(oa.RootDirectory); } } #endif//_REAL_DELETE_ if (0 <= (status = NtOpenFile(&oa.RootDirectory, FILE_GENERIC_READ, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|USE_DELETE_ON_CLOSE))) { if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (PVOID buffer = ExAllocatePool(PagedPool, ALLOCSIZE)) { union { PVOID pv; PBYTE pb; PFILE_DIRECTORY_INFORMATION DirInfo; }; while (0 <= (status = NtQueryDirectoryFile(oa.RootDirectory, NULL, NULL, NULL, &iosb, pv = buffer, ALLOCSIZE, FileDirectoryInformation, 0, NULL, FALSE))) { ULONG NextEntryOffset = 0; do { pb += NextEntryOffset; ObjectName.Buffer = DirInfo->FileName; switch (ObjectName.Length = (USHORT)DirInfo->FileNameLength) { case 2*sizeof(WCHAR): if (ObjectName.Buffer[1] != '.') break; case sizeof(WCHAR): if (ObjectName.Buffer[0] == '.') continue; } ObjectName.MaximumLength = ObjectName.Length; #ifndef _REAL_DELETE_ if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) #endif { ntTraverse(&oa, DirInfo->FileAttributes, nLevel + 1, prefix - 1); } #ifndef _REAL_DELETE_ else #endif { DbgPrint("%s%8I64u <%wZ>\n", prefix, DirInfo->EndOfFile.QuadPart, &ObjectName); } } while (NextEntryOffset = DirInfo->NextEntryOffset); if (ALLOCSIZE - iosb.Information > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName[256])) { break;//NO_MORE_FILES } } ExFreePool(buffer); if (status == STATUS_NO_MORE_FILES) { status = STATUS_SUCCESS; } } } NtClose(oa.RootDirectory); } if (0 > status) { DbgPrint("---- %x %wZ\n", status, poa->ObjectName); } } void ntTraverse() { char prefix[MAXUCHAR + 1]; memset(prefix, '\t', MAXUCHAR); prefix[MAXUCHAR] = 0; STATIC_OBJECT_ATTRIBUTES(oa, "\\??\\c:\\users"); //STATIC_OBJECT_ATTRIBUTES(oa, "\\systemroot"); ntTraverse(&oa, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_READONLY, 0, prefix + MAXUCHAR); }