C ++:获取本机dll依赖项而无需在进程中加载它
C++: get native dll dependencies without loading it in process
我需要以编程方式获取 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 加载到进程中。而我运行在这个地方遇到了问题:LoadLibraryEx
returnsnullptr
if process already has loaded DLL with same name.
我不确定是否允许将两个同名(但位置不同)的 DLL 加载到同一个进程中?我相信是的。那为什么LoadLibraryEx
returnsnullptr
呢?是否可以在不加载 DLL 的情况下以某种方式获取 DLL 依赖项?
您会发现 Matt Pietrek 的这篇文章很有趣。特别是,请查看 "PE File Imports".
段落中的 IMAGE_IMPORT_DESCRIPTOR
数组
Peering Inside the PE: A Tour of the Win32 Portable Executable File Format
此解决方案在 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;
}
我需要以编程方式获取 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 加载到进程中。而我运行在这个地方遇到了问题:LoadLibraryEx
returnsnullptr
if process already has loaded DLL with same name.
我不确定是否允许将两个同名(但位置不同)的 DLL 加载到同一个进程中?我相信是的。那为什么LoadLibraryEx
returnsnullptr
呢?是否可以在不加载 DLL 的情况下以某种方式获取 DLL 依赖项?
您会发现 Matt Pietrek 的这篇文章很有趣。特别是,请查看 "PE File Imports".
段落中的IMAGE_IMPORT_DESCRIPTOR
数组
Peering Inside the PE: A Tour of the Win32 Portable Executable File Format
此解决方案在 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;
}