2017-01-25 43 views
1

Я работаю в небольшой AntiRootkit и мне нужно добавить функциональность, которая:Ядро драйвера Windows: как перечислять все подкаталоги и файлы?

  • Удалить все файлы директории руткита и в ваших возможных subdiretories.

Итак, во-первых, необходимо знать все эти каталоги и файлы, не так ли?

Для этого у меня есть код ниже, который уже выполняет половину этой задачи. Он перечисляет все каталоги и файлы определенного каталога, но не «видит» подкаталоги (файлы и папки).

Например:

enter image description here

Выход:

enter image description here

Код:

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

Итак, как это сделать?

Заранее благодарю любую помощь или предложение.


------------------------------------------ ----- --------------РЕДАКТИРОВАТЬ:---------------------------------- ----------------------------------

Я нашел возможное решение, но я получаю BSOD в этой строке:

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

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: 
+1

в общем нужна функция, которая принимает имя каталога в качестве аргумента, а затем для каждого подкаталога он встречает в каталоге, создает имя пути, и рекурсивно вызывает себя с построенный путь. –

+1

Если бы это был Linux, я бы сказал: «Остерегайтесь жестких ссылок на узлы предков» - что было бы неплохим способом руткита взорвать вас. Руткит * может * сделать что-то подобное с узлами и точками подключения. –

+0

Наверное, лучше всего избежать рекурсии в драйвере ядра. Пространство стека может быть чрезвычайно ограничено (в некоторых случаях), и если вы переполняете стек, то происходят плохие вещи. (Даже больше, чем в пользовательском режиме, я имею в виду!) Но преобразование рекурсивного кода в нерекурсивный код - это просто базовое программирование, вам не нужно ничего делать специально, потому что это драйвер ядра. –

ответ

2

нормально, вот код, который испытания и работы. если кто-то не может использовать его или получил BSOD - , вероятно, проблема не в коде, а в кого-нибудь навыки

несколько нот - если у вас есть предыдущий режим ядра - использовать Nt* API (при экспорте), но не Zw* апи. или Io* api. если вы не понимаете, почему, или каков ваш предыдущий режим - лучше даже не пытаться программировать в ядре.

обязательным использование FILE_OPEN_REPARSE_POINT вариант или даже не пытаться запустить этот код, если не понять, что это и почему нужно использовать

для Delete - открытых файлов с FILE_DELETE_ON_CLOSE опции только для дампа - с FILE_DIRECTORY_FILE вариант вместо.

код сам использовал < = 0x1800 байты стеки в 64 в глубоких папках, как 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); 

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

большое спасибо! но каково ваше определение для переменных 'STATIC_OBJECT_ATTRIBUTES' и' oa' в 'ntTraverse()'? – Saulo

+0

@Saulo это только макрос (мой собственный) для статического инициализации 'OBJECT_ATTRIBUTES', конечно же, это путь жесткого кода, в реальном приложении - вы сами инициализируете его во время выполнения. и теперь - трудно использовать, например, инициализировать просто структуру? однако я use' # определить STATIC_OBJECT_ATTRIBUTES (OA, имя) \ \t STATIC_UNICODE_STRING (метка (м), имя); \ \t статической OBJECT_ATTRIBUTES оа = {SizeOf габаритных, 0, (PUNICODE_STRING) & этикетка (м), OBJ_CASE_INSENSITIVE} ' внутренние макросы, которые вы уже видели. и совет не копировать/вставлять это, но понимать. если не могу понять - не использовать, это необязательно. – RbMm

+0

@Saulo - 'и oa variable' - я называю' ntTraverse (& oa, .. 'первый параметр функции объявлен как' POBJECT_ATTRIBUTES poa' - так что такое 'oa' type? Так трудно угадать, что такое' STATIC_OBJECT_ATTRIBUTES (oa, «\\ systemroot»); «например», и это не является частью функции, но часть демонстрации вызывает эту функцию с помощью ** hardcoded ** path '\\ systemroot' - вы во всех случаях будете динамическими или жесткими. себя, как вы можете – RbMm

 Смежные вопросы

  • Нет связанных вопросов^_^