如何使用编程方法确定二进制文件依赖的DLL?
需要澄清的是,我不是在尝试确定运行中exe的DLL依赖性,而是任意一个可能缺少所需DLL的exe。我正在寻找一种在C/C++应用程序中实现的解决方案。这是需要由我的应用程序在运行时完成,并且不能由第三方应用程序(如depends)完成。
如何使用编程方法确定二进制文件依赖的DLL?
需要澄清的是,我不是在尝试确定运行中exe的DLL依赖性,而是任意一个可能缺少所需DLL的exe。我正在寻找一种在C/C++应用程序中实现的解决方案。这是需要由我的应用程序在运行时完成,并且不能由第三方应用程序(如depends)完成。
IMAGE_LOAD_FUNCTION
API。它将返回一个指向LOADED_IMAGE
结构的指针,您可以使用该结构来访问PE文件的各个部分。EXEDUMP.CPP
并查看DumpImportsSection
,它应该有您需要的代码。基于pedump代码,需要76行代码来实现这个功能(不要忘记添加Imagehlp.lib作为依赖项):
#include <stdio.h>
#include "windows.h" //DONT REMOVE IT
#include "ImageHlp.h"
#include "stdafx.h"
template <class T> PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, T* pNTHeader) // 'T' == PIMAGE_NT_HEADERS
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// This 3 line idiocy is because Watcom's linker actually sets the
// Misc.VirtualSize field to 0. (!!! - Retards....!!!)
DWORD size = section->Misc.VirtualSize;
if ( 0 == size )
size = section->SizeOfRawData;
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + size)))
return section;
}
return 0;
}
template <class T> LPVOID GetPtrFromRVA( DWORD rva, T* pNTHeader, PBYTE imageBase ) // 'T' = PIMAGE_NT_HEADERS
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT delta;
pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
return (PVOID) ( imageBase + rva - delta );
}
void DumpDllFromPath(wchar_t* path) {
char name[300];
wcstombs(name,path,300);
PLOADED_IMAGE image=ImageLoad(name,0);
if (image->FileHeader->OptionalHeader.NumberOfRvaAndSizes>=2) {
PIMAGE_IMPORT_DESCRIPTOR importDesc=
(PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA(
image->FileHeader->OptionalHeader.DataDirectory[1].VirtualAddress,
image->FileHeader,image->MappedAddress);
while ( 1 )
{
// See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR
if ( (importDesc->TimeDateStamp==0 ) && (importDesc->Name==0) )
break;
printf(" %s\n", GetPtrFromRVA(importDesc->Name,
image->FileHeader,
image->MappedAddress) );
importDesc++;
}
}
ImageUnload(image);
}
//Pass exe or dll as argument
int _tmain(int argc, _TCHAR* argv[])
{
DumpDllFromPath(argv[1]);
return 0;
}
这是不可能确定的。至少不需要大量的工作。任何二进制文件都可以调用LoadLibrary来加载DLL。即使您要扫描所有对LoadLibrary的调用代码,您也必须确定正在使用哪些字符串来标识库。追踪动态内存中字符串放置的位置将比您想象的更困难。
LoadLibrary
或在实例化COM对象时隐式加载的模块。Dependency Walker有一个分析模式,试图解决在运行时加载的二进制文件的问题,但你不能保证100%的代码覆盖率,所以即使使用那个尝试也不行。无论你喜不喜欢,这就是正确的答案。 - IInspectableDependency Walker可以通过使用配置文件菜单来实现,如果您有一个目标可执行文件。只需加载可执行文件,告诉它开始分析,它就会列出在执行程序时加载的所有模块。
你觉得使用一个DLL来计算所有这些信息并将答案作为CStrings数组返回如何?
PE格式DLL可以为您完成此操作。附带源代码,没有GPL限制。 PE文件资源管理器是一个使用该DLL的GUI应用程序,同样附带源代码(无GPL)。