2016-11-01 3 views
1

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

Это можно сделать, позвонив по номеру QueryFullProcessImageName, затем используя путь, возвращенный им, чтобы открыть файл и прочитать его.
Однако таким образом вводится окно между извлечением пути файла C:\my_program.exe и открытием файла с именем C:\my_program.exe. Во время этого окна исходный файл может быть заменен другим файлом, который я не хочу читать, т. Е. Происходит гонка файловой системы.
У меня есть требование, что эта раса не должна произойти.

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

От чтения источников ReactOS я узнал, что такая ручка, скорее всего, существует в Windows, а также и хранится в EPROCESS структуре (как часть SectionObject), и это на самом деле используется для реализации QueryFullProcessImageName.

Есть ли способ получить этот дескриптор с использованием WinAPI или, по крайней мере, NT API?
(GetModuleHandleEx кажется вернуться совершенно другой ручкой.)

+1

@ Жан-FrançoisFabre - это не так. файл можно переименовать во время работы. – RbMm

+0

@ RbMm: вы правы. В Windows 10 это можно сделать.Я был уверен в обратном, но на окнах 10 это кажется возможным! –

+0

@ Jean-FrançoisFabre - в чем проблема? запустите любой exe, а затем переименуйте в explorer или в любой браузер файлов. проверьте это и просмотрите результат. файл может быть восстановлен. удаленный не может – RbMm

ответ

1

предупреждение - все это не официально поддерживается. непризнанные функции!

существует 100% чистое решение, основанное на NtAreMappedFilesTheSame

NTSYSAPI 
NTSTATUS 
NTAPI 
NtAreMappedFilesTheSame (
    __in PVOID File1MappedAsAnImage, 
    __in PVOID File2MappedAsFile 
    ); 

так в общих словах мы должны сделать следующий

  1. получил File1MappedAsAnImage адрес EXE/DLL
  2. с ZwQueryVirtualMemory (, MemoryMappedFilenameInformation,) получить имя_файла (в собственном формате). примечания: MemoryMappedFilenameInformation всегда возвращают текущее имя файла в момент, когда называется - так что, если файл уже переименован - мы получили эти новое название
  3. открыть файл с помощью заданного имени
  4. файла карты и получил File2MappedAsFile
  5. вызова NtAreMappedFilesTheSame (File1MappedAsAnImage , File2MappedAsFile)
  6. если мы получили STATUS_SUCCESS мы открываем нужный файл - сделать здесь
  7. если мы получили STATUS_NOT_SAME_DEVICE потребности Unmap File2MappedAsFile и Гота 2
  8. , если мы получили другой статус - произошла какая-то ошибка

здесь полный рабочий пример

NTSTATUS MapModule(void* File1MappedAsAnImage, void** pFile2MappedAsFile) 
{ 
    static volatile UCHAR guz; 

    PVOID stack = alloca(guz); 
    union { 
     PVOID buf; 
     PUNICODE_STRING FileName; 
    }; 

    SIZE_T cb = 0, rcb = 256, ViewSize; 

    NTSTATUS status, s = STATUS_UNSUCCESSFUL; 

    BOOL bSame; 

    do 
    { 
     bSame = TRUE; 

     do 
     { 
      if (cb < rcb) 
      { 
       cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); 
      } 

      if (0 <= (status = NtQueryVirtualMemory(NtCurrentProcess(), File1MappedAsAnImage, MemoryMappedFilenameInformation, buf, cb, &rcb))) 
      { 
       DbgPrint("%wZ\n", FileName); 

       OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, FileName, OBJ_CASE_INSENSITIVE }; 

       HANDLE hFile, hSection; 
       IO_STATUS_BLOCK iosb; 

       if (0 <= (s = NtOpenFile(&hFile, FILE_GENERIC_READ, &oa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))) 
       { 
        s = ZwCreateSection(&hSection, SECTION_MAP_READ, 0, 0, PAGE_READONLY, SEC_COMMIT, hFile); 

        NtClose(hFile); 

        if (0 <= s) 
        { 
         *pFile2MappedAsFile = 0; 
         s = ZwMapViewOfSection(hSection, NtCurrentProcess(), pFile2MappedAsFile, 0, 0, 0, &(ViewSize = 0), ViewUnmap, 0, PAGE_READONLY); 

         NtClose(hSection); 

         if (0 <= s) 
         { 
          switch (s = NtAreMappedFilesTheSame(File1MappedAsAnImage, *pFile2MappedAsFile)) 
          { 
          case STATUS_SUCCESS: 
           DbgPrint("opened original file!"); 
           return STATUS_SUCCESS; 
          case STATUS_NOT_SAME_DEVICE: 
           DbgPrint("opened another file!"); 
           bSame = FALSE; 
           break; 
          default: 
           DbgPrint("status = %x\n", s); 

          } 

          ZwUnmapViewOfSection(NtCurrentProcess(), *pFile2MappedAsFile); 
         } 
        } 
       } 
      } 

     } while (status == STATUS_BUFFER_OVERFLOW); 

    } while (!bSame); 

    return status < 0 ? status : s; 
} 

void Demo() 
{ 
    PVOID BaseAddress; 
    if (0 <= MapModule(GetModuleHandle(0), &BaseAddress)) 
    { 
     ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 
    } 
} 

также вы можете посмотреть на этой topic

+0

Интересно! Я думал о проверке открытого файла post-factum, но не нашел способ сделать это без рас. (Мне нужно проверить и понять это более подробно, прежде чем принимать ответ.) – user2665887

+0

@ user2665887 - да, открыт файл post-factum check in loop - если не такие же файлы - снова запустите цикл. это возможно, потому что MemoryMappedFilenameInformation всегда возвращает текущее имя файла во время, когда вызывается. и NtAreMappedFilesTheSam делают постфактумную проверку без расчётов – RbMm

+0

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

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