C++ C++;:获取本机dll依赖项,而无需在进程中加载它

C++ C++;:获取本机dll依赖项,而无需在进程中加载它,c++,dll,portable-executable,loadlibrary,systems-programming,C++,Dll,Portable Executable,Loadlibrary,Systems Programming,我需要以编程方式获取DLL的依赖项列表。以下是我试图解决此任务的方法: BSTR GetDllDependencies(常量wchar\u t*dllPath) { std::wstring依赖; 结构LibDeleter { typedef模块指针; void操作符()(HMODULE hMod){freellibrary(hMod);} }; auto-hModRaw=LoadLibraryExW(dllPath,NULL,不解析DLL引用);/(*)nullptr nere auto hM

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

BSTR GetDllDependencies(常量wchar\u t*dllPath)
{
std::wstring依赖;
结构LibDeleter
{
typedef模块指针;
void操作符()(HMODULE hMod){freellibrary(hMod);}
};
auto-hModRaw=LoadLibraryExW(dllPath,NULL,不解析DLL引用);/(*)nullptr nere
auto hMod=std::unique_ptr();
auto imageBase=(DWORD_PTR)hMod.get();
自动标头=ImageNtHeader(hMod.get());
auto importRVA=header->OptionalHeader.DataDirectory[IMAGE\u DIRECTORY\u ENTRY\u IMPORT].VirtualAddress;
自动导入=(PIMAGE\u IMPORT\u DESCRIPTOR)(DWORD\u PTR)(importRVA+imageBase);
while(importRVA&&importable->OriginalFirstThunk)
{
自动导入模块名=(字符*)(DWORD_PTR)(可导入->名称+图像库);
依赖关系
.append(importedModuleName,importedModuleName+std::strlen(importedModuleName))
.附加(L“,”);
可导入++;
}
自动结果=SysAllocString(dependencies.c_str());
返回结果;
}
它起作用了。但是,正如您所看到的,它将DLL加载到进程中。我在这里遇到了一个问题:
LoadLibraryEx
如果进程已经加载了同名的DLL,则返回
nullptr


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

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


此解决方案在DLL文件中使用手动导航。解决方案的基础是将RVA地址转换为原始地址(文件中的地址)的
rvatraw
函数

//定义特定RVA地址实际位于哪个节(节号)
DWORD RVAtoRAW(DWORD rva、PIMAGE\U SECTION\U HEADER SECTION HEADERRAW、WORD SECTIONSCONT)
{
int段编号;
用于(sectionNo=0;sectionNoFileHeader.NumberOfSections;
//RVA-相对虚拟地址-加载此DLL的进程的虚拟地址空间内的相对(相对于ImageBase)地址
auto ImportableRVA=peHeaderRAW->OptionalHeader.DataDirectory[IMAGE\u DIRECTORY\u ENTRY\u IMPORT].VirtualAddress;
auto ImportableRaw=RVAtoRAW(ImportableRva、sectionHeaderRAW、SectionScont);
自动导入=(PIMAGE\u IMPORT\u描述符)(baseRAW+importableraw);
std::wstring依赖;
while(importablerva&&importablet->OriginalFirstThunk)
{
自动命名raw=rvataraw(可导入->名称,sectionHeaderRAW,SectionScont);
自动导入模块名=(字符*)(DWORD_PTR)(nameRAW+baseRAW);
依赖关系
.append(importedModuleName,importedModuleName+std::strlen(importedModuleName))
.附加(L“,”);
可导入++;
}
自动结果=SysAllocString(dependencies.c_str());
返回结果;
}

您需要解析PE(可移植可执行文件)文件(即.dll或.exe)的导入部分。如文档中所述,您需要改为以数据文件的形式加载。
LoadLibraryEx返回nullptr如果进程已经加载了同名的DLL
这不是真的
那么为什么LoadLibraryEx返回nullptr
-那么为什么不调用
GetLastError
RtlGetLastNtStatus