【问题标题】:C++: get native dll dependencies without loading it in processC ++:获取本机dll依赖项而不在进程中加载​​它
【发布时间】:2017-07-31 16:27:43
【问题描述】:

我需要以编程方式获取 DLL 的依赖项列表。以下是我尝试解决此任务的方法:

BSTR GetDllDependencies(const wchar_t* dllPath)
{
    std::wstring dependencies;

    struct LibDeleter
    {
        typedef HMODULE pointer;
        void operator()(HMODULE hMod) { FreeLibrary(hMod); }
    };

    auto hModRaw = LoadLibraryExW(dllPath, NULL, DONT_RESOLVE_DLL_REFERENCES); //(*)nullptr nere
    auto hMod = std::unique_ptr<HMODULE, LibDeleter>();

    auto imageBase = (DWORD_PTR)hMod.get();

    auto header = ImageNtHeader(hMod.get());
    auto importRVA = header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    auto importTable = (PIMAGE_IMPORT_DESCRIPTOR)(DWORD_PTR)(importRVA + imageBase);

    while (importRVA && importTable->OriginalFirstThunk)
    {
        auto importedModuleName = (char*)(DWORD_PTR)(importTable->Name + imageBase);
        dependencies
            .append(importedModuleName, importedModuleName + std::strlen(importedModuleName))
            .append(L",");

        importTable++;
    }

    auto result = SysAllocString(dependencies.c_str());

    return result;
}

它有效。但是,如您所见,它将 DLL 加载到进程中。我在这个地方遇到了一个问题:如果进程已经加载了同名的 DLL,LoadLibraryEx 返回nullptr

我不确定是否允许将两个同名(但位置不同)的 DLL 加载到同一个进程中?我相信是的。那为什么LoadLibraryEx 返回nullptr?是否有可能在不加载 DLL 的情况下以某种方式获取 DLL 依赖项?

【问题讨论】:

标签: c++ dll portable-executable loadlibrary systems-programming


【解决方案1】:

您会发现 Matt Pietrek 的这篇文章很有趣。特别是,请查看 “PE 文件导入” 段落中的 IMAGE_IMPORT_DESCRIPTOR 数组。

Peering Inside the PE: A Tour of the Win32 Portable Executable File Format

【讨论】:

    【解决方案2】:

    此解决方案在 DLL 文件中使用手动导航。该解决方案的基础是 RVAtoRAW 函数,它将 RVA 地址转换为 RAW 地址(文件内的地址)。

    //Defining in which section particular RVA address actually located (section number)
    DWORD RVAtoRAW(DWORD rva, PIMAGE_SECTION_HEADER sectionHeaderRAW, WORD sectionsCount)
    {
        int sectionNo;
        for (sectionNo = 0; sectionNo < sectionsCount; ++sectionNo)
        {
            auto sectionBeginRVA = sectionHeaderRAW[sectionNo].VirtualAddress;
            auto sectionEndRVA = sectionBeginRVA + sectionHeaderRAW[sectionNo].Misc.VirtualSize;
            if (sectionBeginRVA <= rva && rva <= sectionEndRVA)
                break;
        }
        //Evaluating RAW address from section & RVA
        auto sectionRAW = sectionHeaderRAW[sectionNo].PointerToRawData;
        auto sectionRVA = sectionHeaderRAW[sectionNo].VirtualAddress;
        auto raw = sectionRAW + rva - sectionRVA;
    
        return raw;
    }
    
    BSTR GetDllDependencies(const wchar_t* dllPath)
    {
        auto buffer = ReadFile(dllPath);
        if (buffer.empty())
            return SysAllocString(L"");
    
        //RAW - offset from beginnig of the file (absolute "address" within file)
        auto baseRAW = buffer.data();
        auto dosHeaderRAW = (PIMAGE_DOS_HEADER)baseRAW;
        auto peHeaderRAW = (PIMAGE_NT_HEADERS)(baseRAW + dosHeaderRAW->e_lfanew);
        auto sectionHeaderRAW = (PIMAGE_SECTION_HEADER)(baseRAW + dosHeaderRAW->e_lfanew + sizeof(IMAGE_NT_HEADERS));
    
        auto sectionsCount = peHeaderRAW->FileHeader.NumberOfSections;
    
        //RVA - Relative Virtual Address - relative (to ImageBase) address within virtual address space of the process which loads this DLL
        auto importTableRVA = peHeaderRAW->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
        auto importTableRAW = RVAtoRAW(importTableRVA, sectionHeaderRAW, sectionsCount);
        auto importTable = (PIMAGE_IMPORT_DESCRIPTOR)(baseRAW + importTableRAW);
    
        std::wstring dependencies;
        while (importTableRVA && importTable->OriginalFirstThunk)
        {
            auto nameRAW = RVAtoRAW(importTable->Name, sectionHeaderRAW, sectionsCount);
    
            auto importedModuleName = (char*)(DWORD_PTR)(nameRAW + baseRAW);
            dependencies
                .append(importedModuleName, importedModuleName + std::strlen(importedModuleName))
                .append(L",");
    
            importTable++;
        }
    
        auto result = SysAllocString(dependencies.c_str());
    
        return result;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 2020-05-18
      • 2021-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多