c ++ - Windows-driverkerne: Hvordan opregner alle undermapper og filer?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg arbejder i en lille antirootkit, og jeg har brug for at tilføje en funktionalitet, der er:



  • Slet alle filer på mappen med rootkit og i dine mulige underdiretories.



Så er det for det første nødvendigt at kende alle disse mapper og filer, ikke?


Til dette har jeg kode nedenfor, der allerede gør halvdelen af ​​denne opgave. Han opregner alle mapper og filer i en bestemt mappe, men ikke 'se' undermapper (filer og mapper).


F.eks:


Indtast billedbeskrivelse her [15]


Produktion:


Indtast billedbeskrivelse her [16]


Kode:


#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
", szWellFormedFileName));
                    KdPrint((" \%S
", szWellFormedFileName));
                    ExFreePoolWithTag(szWellFormedFileName, '000');
                }
                if (pfbInfo->NextEntryOffset == 0) { break; }
                pfbInfo += pfbInfo->NextEntryOffset;
            }
        }
        ZwClose(hFile);
        ExFreePoolWithTag(pfbInfo, '000');
        return ntStatus;
    }


Så hvordan gør dette?


På forhånd takket være hjælp eller forslag.





----------------------------------------------- ---------REDIGERE:--------------------------------------- -----------------------------


Jeg fandt en mulig løsning, men jeg får en BSOD i denne linje:


if ( (*pDir)->NextEntryOffset)


I KernelFindNextFile metode.


Nogle forslag?


Her er koden, jeg fandt:


#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
",strFileName);
            }
            else
            {
                DbgPrint("[File]\%S
",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
",strFileName);
        } 
        else
        {
            DbgPrint("[File]\%S
",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
",strFileName);
        }
        else
        {
            DbgPrint("[File]\%S
",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: 

Bedste reference


ok, her kode som testet og virker . hvis nogen ikke kan bruge den eller har BSOD - sandsynligvis problem ikke i kode men i nogen færdigheder


flere noter - hvis du har tidligere moduskernel - brug Nt* api (når eksporteret) men ikke Zw* api. eller Io* api. hvis du ikke forstår hvorfor, eller hvad er din tidligere tilstand - bedre end ikke forsøge programmering i kernel.


obligatorisk brug FILE\_OPEN\_REPARSE\_POINT mulighed eller endda ikke prøv at køre denne kode, hvis du ikke forstår, hvad er dette og hvorfor brug for brug


for at slette - åbne filer med FILE\_DELETE\_ON\_CLOSE mulighed, kun til dumpning - med FILE\_DIRECTORY\_FILE mulighed i stedet.


kode dig selv brugt <=0x1800 bytes stack i x64 i dybeste mapper, som c:Users - så dette er ok for kerne, men kontroller altid stakplads med IoGetRemainingStackSize [17]


Jeg vil ikke rette alle komma i din kode, hvis du ikke kan gøre det selv


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

    if (!nLevel)
    {
        DbgPrint("!nLevel
");
        return ;
    }

    NTSTATUS status;
    IO\_STATUS\_BLOCK iosb;
    UNICODE\_STRING ObjectName;
    OBJECT\_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };

    DbgPrint("\%s[<\%wZ>]
", 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>
", 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
", status, poa->ObjectName);
    }
}

void ntTraverse()
{
    char prefix[MAXUCHAR + 1];
    memset(prefix, '	', 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);
}