Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何以编程方式确定windows可执行文件DLL依赖项?_C++_Windows_Dll_Dependencies_Executable - Fatal编程技术网

C++ 如何以编程方式确定windows可执行文件DLL依赖项?

C++ 如何以编程方式确定windows可执行文件DLL依赖项?,c++,windows,dll,dependencies,executable,C++,Windows,Dll,Dependencies,Executable,如何确定哪个DLL是二进制文件取决于使用编程方法 要明确的是,我不是在试图确定正在运行的exec的DLL依赖关系,而是确定任何任意exec(可能缺少所需的DLL)的DLL依赖关系。我正在寻找一个在C/C++应用程序中实现的解决方案。这需要我的应用程序在运行时完成,而第三方应用程序(如依赖)无法完成。这是无法确定的。至少不是没有大量的工作。任何二进制文件都可以调用LoadLibrary来加载DLL。即使要扫描代码以查找对LoadLibrary的所有调用,也必须确定使用了哪些字符串来标识库。跟踪字符

如何确定哪个DLL是二进制文件取决于使用编程方法


要明确的是,我不是在试图确定正在运行的exec的DLL依赖关系,而是确定任何任意exec(可能缺少所需的DLL)的DLL依赖关系。我正在寻找一个在C/C++应用程序中实现的解决方案。这需要我的应用程序在运行时完成,而第三方应用程序(如依赖)无法完成。

这是无法确定的。至少不是没有大量的工作。任何二进制文件都可以调用LoadLibrary来加载DLL。即使要扫描代码以查找对LoadLibrary的所有调用,也必须确定使用了哪些字符串来标识库。跟踪字符串在动态内存中的位置将比您想要解决的困难。

看看API。它将返回指向结构的指针,您可以使用该指针访问PE文件的各个部分

您可以找到一些描述结构布局的文章,以及。您可以下载文章的源代码

我想这会给你你需要的一切

更新:


我刚刚下载了这篇文章的源代码。如果打开
EXEDUMP.CPP
并查看
DumpImportsSection
它应该有您需要的代码。

简而言之,您需要为可执行文件使用的每个DLL扫描PE文件的导入部分。然后递归地定位和扫描每个dll,直到找到所有依赖项


当然,应用程序可以使用LoadLibrary系列函数实现必需或可选功能。使用此方法无法检测到这些信息。

您可以调用一个DLL为您计算所有这些信息,并将答案作为CString数组传回,怎么样


我能为你做这件事。提供源代码,没有GPL限制。PE文件资源管理器是一个GUI应用程序,使用DLL,也提供源代码(无GPL)

76行代码(别忘了添加Imagehlp.lib作为依赖项):

#包括
#包括“windows.h”//不要删除它
#包括“ImageHlp.h”
#包括“stdafx.h”
模板PIMAGE\U SECTION\U HEADER GetEnclosuringSeCTIONHEADER(DWORD rva,T*pNTHeader)/‘T’==PIMAGE\U NT\U HEADER
{
PIMAGE_SECTION_HEADER SECTION=图像_FIRST_SECTION(pNTHeader);
未签名的i;
对于(i=0;iFileHeader.NumberOfSections;i++,section++)
{
//这三行的愚蠢是因为Watcom的链接器实际上设置了
//Misc.VirtualSize字段为0。(!!!-延迟…!!)
DWORD大小=节->杂项虚拟化;
如果(0==大小)
尺寸=截面->尺寸框架数据;
//RVA是否在此区域内?
如果((rva>=节->虚拟服装)和
(rva<(节->虚拟服装+尺寸)))
返回段;
}
返回0;
}
模板LPVOID GetPtrFromRVA(DWORD rva,T*pNTHeader,PBYTE imageBase)/“T”=PIMAGE\u NT\u头
{
PIMAGE_段_标题段HDR;
内特三角洲;
pSectionHdr=GetEnclosuringSectionHeader(rva,pNTHeader);
如果(!pSectionHdr)
返回0;
增量=(INT)(pSectionHdr->VirtualAddress pSectionHdr->指针到数据);
返回(PVOID)(imageBase+rva-增量);
}
void DumpDllFromPath(wchar\u t*path){
字符名[300];
wcstombs(名称、路径,300);
PLOADED_IMAGE=ImageLoad(名称,0);
如果(图像->文件头->可选头.NumberOfVandSizes>=2){
PIMAGE\u IMPORT\u描述符importDesc=
(PIMAGE\u IMPORT\u描述符)GetPtrFromRVA(
image->FileHeader->OptionalHeader.DataDirectory[1]。VirtualAddress,
图像->文件头,图像->映射地址);
而(1)
{
//查看是否已到达空图像\u导入\u描述符
如果((importDesc->TimeDateStamp==0)和&(importDesc->Name==0))
打破
printf(“%s\n”),GetPtrFromRVA(importDesc->Name,
图像->文件头,
图像->映射地址);
importDesc++;
}
}
图像卸载(图像);
}
//将exe或dll作为参数传递
int _tmain(int argc,_TCHAR*argv[]
{
DumpDllFromPath(argv[1]);
返回0;
}
如果您有目标可执行文件,则可以使用配置文件菜单执行此操作。只需加载可执行文件,告诉它开始评测,它就会列出执行程序时加载的所有模块


为什么在这里投票给我?就我所知,这个答案在技术上是准确的。关于这个答案被否决的原因,我的猜测是:它没有区分隐式依赖(可以确定,请参阅alex2k8的链接)和显式依赖(这就是您所说的)。别灰心,答案是对的一半@jdigital:这个答案不完全正确。这是一个问题的正确答案,要求以编程方式查找可执行映像的所有依赖项。问题是询问一般情况,因此在实例化COM对象时,您必须使用
LoadLibrary
或隐式加载的模块来说明运行时动态链接。Dependency Walker有一种分析模式,它试图解释在运行时加载的二进制文件,但您不能保证100%的代码覆盖率,所以即使这样也不行。不管你喜欢与否,这是正确的答案。谢谢你的建议。特别是源代码示例的链接。这正是我要找的。检查这个。分析只会看到那些模块的加载,而这些模块恰好是您触发的。除非您能保证100%的代码覆盖率,否则您不能确保找到所有依赖项。然后,您还将看到加载的模块,这些模块不是您的程序严格要求的(例如,打开文件保存对话框时的shell扩展名)。
#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;
}