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

用户名

我正在使用小型antirootkit,需要添加以下功能:

  • 删除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;
    }

那么,该怎么做呢?

在此先感谢您的帮助或建议。


-------------------------------------------------- - - - 编辑: - - - - - - - - - - - - - - - - - - - - - --------------------------

我找到了可能的解决方案,但在此行中出现蓝屏死机

if ( (*pDir)->NextEntryOffset)

KernelFindNextFile方法中。

有什么建议吗?

这是我发现的代码:

#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);
    }
}

蓝屏死机:

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: 
RbMm

好的,这里是经过测试工作的代码如果某人无法使用它或获得BSOD,则可能不是代码问题,而是某人的技能问题

一些注意事项-如果您具有以前的模式内核-请使用Nt*api(导出时),而不要使用Zw*api。Io*api。如果您不了解原因或先前的模式,最好甚至不要尝试在内核中进行编程。

强制使用FILE_OPEN_REPARSE_POINT选项,或者如果不理解这是什么以及为什么需要使用,甚至不要尝试运行此代码

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

您自己的代码使用了最深文件夹中x64中的<= 0x1800字节的堆栈,例如c:\Users-因此对于内核来说是可以的,但始终使用以下命令检查堆栈空间IoGetRemainingStackSize

如果您自己不能这样做,我将不正确您代码中的每个逗号

#define ALLOCSIZE PAGE_SIZE

#ifdef _REAL_DELETE_
#define USE_DELETE_ON_CLOSE FILE_DELETE_ON_CLOSE
#define FILE_ACCESS FILE_GENERIC_READ|DELETE
#else
#define USE_DELETE_ON_CLOSE FILE_DIRECTORY_FILE
#define FILE_ACCESS FILE_GENERIC_READ
#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)
    {
        DbgPrint("!nLevel\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_ACCESS, 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);
                }

                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, MAXUCHAR, prefix + MAXUCHAR);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在/ dev /子目录(内核驱动程序)中创建多个设备

如何使用Shell脚本备份目录和文件,包括所有子目录和文件?

如何在java中打印所有目录和文件以及所有子目录和文件

如何添加递归循环以删除包含所有子目录和文件的目录?

如何使用nodeJS列出所有子目录和文件?

如何在一个会话中记录对目录,子目录和文件的所有修改?

如何在Windows中的目录和子目录中查找所有头文件

在目录中查找所有匹配模式的文件并复制找到的子目录和文件

复制具有匹配字符串的目录以及所有子目录和文件

已审核-auditctl规则仅监视目录(不是所有子目录和文件等)。

已审核-auditctl规则仅监视目录(不是所有子目录和文件等)。

将目录中的所有子目录和文件递归添加到数组中

将组访问权限更改为目录以及所有子目录和文件

如何遍历所有子目录中的文件?

如何报告所有子目录中的文件数?

更改所有子目录的文件夹和文件权限

递归输出所有子目录的文件名和文件大小?

列出子目录中所有文件的创建日期和文件名

重命名所有子目录中的文件和文件夹以删除字符

如何删除Windows中与给定通配符匹配的子目录中的所有文件?

如何按名称递归查找目录并删除其内容(包括所有子目录和文件),同时保留目录本身?

如何更改当前目录,子目录以及子目录的子目录中的文件所有权?

如何使用vim打开当前目录和所有子目录中的所有文件?

如何更改目录/所有子目录中所有文件的x00权限?

如何动态从给定目录和所有子目录导入所有* .py文件?

如何从某个目录中删除所有文件,但该目录的子目录除外?

如何建立目录中所有文件的索引,包括子目录和ZIP文件的内容?

如何删除所有子目录中具有给定名称的所有文件?

将所有文件和目录移动到Windows中的新子目录