如何在不引入文件系统竞争的情况下获取当前可执行文件的文件句柄?

时间:2016-11-01 20:54:28

标签: c windows winapi nt

我需要从当前可执行文件中读取一些数据(即调试信息)。

通过调用QueryFullProcessImageName,然后使用它返回的路径打开文件并从中读取,这很简单。
但是,这种方式会在检索文件路径C:\my_program.exe和打开名为C:\my_program.exe的文件之间引入一个窗口。在该窗口期间,原始文件可以替换为我不想阅读的其他文件,即文件系统竞争发生。
我有一个外部强制要求,这场比赛不应该发生。

基本上,我需要一些不存在的QueryFullProcessImageHandle而不是QueryFullProcessImageName,所以我可以在不按名称打开文件的情况下从中读取。

通过阅读ReactOS来源,我了解到这样的句柄很可能也存在于Windows上并保存在EPROCESS结构中(作为SectionObject的一部分)并且它实际上用于实现QueryFullProcessImageName

有没有办法使用WinAPI或至少NT API获取此句柄?
GetModuleHandleEx似乎返回完全不同的句柄。)

1 个答案:

答案 0 :(得分:1)

警告 - 这些都不是官方支持的。使用了未经处理的函数!

基于NtAreMappedFilesTheSame

存在100%清洁解决方案
NTSYSAPI
NTSTATUS
NTAPI
NtAreMappedFilesTheSame (
    __in PVOID File1MappedAsAnImage,
    __in PVOID File2MappedAsFile
    );

所以一般来说我们需要做下一步

  1. 获得了exe / dll的
  2. 的File1MappedAsAnImage地址
  3. ZwQueryVirtualMemory(,MemoryMappedFilenameInformation,) 获取FileName(以原生格式)。 注意:MemoryMappedFilenameInformation总是在调用时返回当前文件名 - 所以如果文件已经重命名 - 我们得到了新名称
  4. 按名称打开文件
  5. 映射文件并获得了File2MappedAsFile
  6. 调用NtAreMappedFilesTheSame(File1MappedAsAnImage,File2MappedAsFile)
  7. 如果我们STATUS_SUCCESS我们打开了正确的文件 - 在这里完成
  8. 如果我们STATUS_NOT_SAME_DEVICE需要取消映射File2MappedAsFile和 转到2
  9. 如果我们获得其他状态 - 发生了一些错误
  10. 这里有完整的工作示例

    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