草庐IT

c++ - Windows 驱动内核 : How enumerate all subdirectories and files?

coder 2024-06-04 原文

我在一个小型的 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: 

最佳答案

好的,这里是测试过并且有效的代码。如果有人无法使用它或出现 BSOD - 可能问题不在代码中,而是在某些人的技能中

一些注意事项 - 如果您有以前的模式内核 - 使用 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
#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);
}

关于c++ - Windows 驱动内核 : How enumerate all subdirectories and files?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41854736/

有关c++ - Windows 驱动内核 : How enumerate all subdirectories and files?的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  4. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  7. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  8. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

随机推荐