12

How to determine what DLL's a binary depends on using programmatic methods?

To be clear, I am not trying to determine the DLL dependencies of the running exec, but of any arbitrary exec (that may be missing a required DLL). I'm looking for a solution to implement in a C/C++ application. This is something that needs to be done by my application at runtime and can't be done by a third party app (like depends).

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Check this [question](http://stackoverflow.com/questions/362560/how-do-i-detect-the-dlls-required-by-an-application). – alex2k8 Feb 28 '09 at 01:25

6 Answers6

10

Take a look at the IMAGE_LOAD_FUNCTION API. It will return a pointer to a LOADED_IMAGE structure, which you can use to access the various sections of a PE file.

You can find some articles that describe how the structures are laid out here, and here. You can download the source code for the articles here.

I think this should give you everything you need.

Update:

I just downloaded the source code for the article. If you open up EXEDUMP.CPP and take a look at DumpImportsSection it should have the code you need.

Scott Wisniewski
  • 24,561
  • 8
  • 60
  • 89
  • Thanks for you suggestion. Especially for the links to the source examples. Exactly what I was looking for. –  Mar 01 '09 at 05:40
7

76 lines to do that based on pedump code (don't forget to add Imagehlp.lib as dependancy):

#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;
}
benerone
  • 161
  • 1
  • 4
7

That's not possible to determine. At least not without a whole lot of work. Any binary can call LoadLibrary to load a DLL. Even if you were to scan the code for all calls to LoadLibrary, you would have to determine what strings were being used to ID the library. Tracking down where in dynamic memory the string has been placed is going to be harder than you want to tackle.

Steve Rowe
  • 19,411
  • 9
  • 51
  • 82
  • 1
    Why vote me down here? This answer is technically accurate as far as I can tell. – Steve Rowe Feb 28 '09 at 01:35
  • My guess on why this answer was voted down: it doesn't distinguish between implicit dependencies (which can be determined, see alex2k8's link) and explicit dependencies (which is what you're talking about). Don't be gloomy, the answer was half right! – jdigital Feb 28 '09 at 01:47
  • @jdigital: This answer isn't half right. It is the correct answer to a question, asking to programmatically find all dependencies of an executable image. The question is asking for the general case, so you have to account for runtime-dynamic linking, using `LoadLibrary`, or modules that are implicitly loaded, when instantiating a COM object. Dependency Walker has a profiling mode, that attempts to account for binaries, that are loaded at runtime, but you cannot guarantee 100% code coverage, so even that attempt won't do. Like it or not, this is the correct answer. – IInspectable Jul 25 '16 at 18:33
1

Dependency Walker can do this by using the profile menu, if you have a target executable. Simply load the executable, tell it to start profiling, and it'll list all the modules loaded while executing the program.

Dependency Walker FAQ (first question...)

squeegee
  • 762
  • 8
  • 10
  • Profiling only sees loading of those modules, that you happen to trigger. Unless you can guarantee 100% code coverage, you cannot be sure to find all dependencies. And then you'll also see modules getting loaded, that aren't strictly required by your program (e.g. shell extensions when opening a File Save dialog). – IInspectable Jul 25 '16 at 18:38
1

In a nutshell, you need to scan the PE file's imports section for each DLL used by the executable. Then recursively locate and scan each dll until you've found all the dependencies.

Of course, apps can use the LoadLibrary family of functions for required or optional functionality. That won't be detected with this method.

zildjohn01
  • 11,339
  • 6
  • 52
  • 58
0

How about a DLL that you can call to calculate all this information for you and pass back the answer as an array of CStrings?

PE Format DLL can do this for you. Supplied with source code, no GPL restrictions. PE File Explorer is a GUI app that uses the DLL, also supplied with source (no GPL).

Stephen Kellett
  • 3,078
  • 1
  • 22
  • 25