Как получить дескриптор файла для текущего исполняемого файла без представления гонки файловой системы?
Мне нужно прочитать некоторые данные из текущего исполняемого файла (а именно, отладочную информацию).
Это просто сделать, позвонив по телефону QueryFullProcessImageName
затем, используя возвращенный им путь, откройте файл и прочитайте его.
Тем не менее, этот способ вводит окно между получением пути к файлу C:\my_program.exe
и открыв файл с именем C:\my_program.exe
, В этом окне исходный файл может быть заменен другим файлом, который я не хочу читать, то есть происходит гонка файловой системы.
У меня есть внешне навязанное требование, чтобы эта гонка не состоялась.
В принципе мне нужно что-то вроде несуществующего QueryFullProcessImageHandle
вместо QueryFullProcessImageName
так что я мог читать с него, не открывая файл по имени.
Из чтения источников ReactOS я узнал, что такой дескриптор, скорее всего, существует и в Windows и хранится в EPROCESS
структура (как часть SectionObject
) и это на самом деле используется для реализации QueryFullProcessImageName
,
Есть ли способ получить этот дескриптор, используя WinAPI или хотя бы NT API?
(GetModuleHandleEx
похоже, возвращает совершенно другую ручку.)
1 ответ
предупреждение - ничего из этого официально не поддерживается.используются функции без разделов!
существует 100% чистый раствор на основеNtAreMappedFilesTheSame
NTSYSAPI
NTSTATUS
NTAPI
NtAreMappedFilesTheSame (
__in PVOID File1MappedAsAnImage,
__in PVOID File2MappedAsFile
);
так в общих словах нам нужно сделать дальше
- получил адрес File1MappedAsAnImage для exe/dll
- с
ZwQueryVirtualMemory
(,MemoryMappedFilenameInformation
) получить имя файла (в собственном формате).нота:MemoryMappedFilenameInformation
всегда возвращать текущее имя файла при вызове - поэтому, если файл уже переименован, мы получаем новое имя - открыть файл по имени
- файл карты и получил File2MappedAsFile
- вызовите NtAreMappedFilesTheSame(File1MappedAsAnImage, File2MappedAsFile)
- если мы получили
STATUS_SUCCESS
открываем правильный файл - сделано здесь - если мы получили
STATUS_NOT_SAME_DEVICE
нужно распаковать File2MappedAsFile и перейти к 2 - если мы получили другой статус - произошла ошибка
вот полный рабочий пример
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);
}
}
также вы можете посмотреть эту тему