プログラムによる方法を使用して、バイナリがどのDLLに依存しているかを判断するにはどうすればよいですか?
明確にするために、実行中のexecのDLL依存関係を特定しようとはしていませんが、任意のexec(必要なDLLが欠落している可能性があります)の依存関係を特定しようとしています。C /C++アプリケーションに実装するソリューションを探しています。これは、実行時にアプリケーションで実行する必要があり、サードパーティのアプリでは実行できないものです(依存など)。
プログラムによる方法を使用して、バイナリがどのDLLに依存しているかを判断するにはどうすればよいですか?
明確にするために、実行中のexecのDLL依存関係を特定しようとはしていませんが、任意のexec(必要なDLLが欠落している可能性があります)の依存関係を特定しようとしています。C /C++アプリケーションに実装するソリューションを探しています。これは、実行時にアプリケーションで実行する必要があり、サードパーティのアプリでは実行できないものです(依存など)。
IMAGE_LOAD_FUNCTION
APIを見てみましょう。LOADED_IMAGE
PE ファイルのさまざまなセクションにアクセスするために使用できる構造体へのポインターを返します。
構造がどのように配置されているかを説明した記事は、こちらおよび ここ にあります。記事のソース コードは、こちらからダウンロードできます。
これにより、必要なものがすべて提供されるはずだと思います。
アップデート:
記事のソースコードをダウンロードしました。開いてEXEDUMP.CPP
見てみると、DumpImportsSection
必要なコードが含まれているはずです。
それを判断することはできません。少なくとも、多くの作業が必要です。どのバイナリでも LoadLibrary を呼び出して DLL をロードできます。LoadLibrary へのすべての呼び出しのコードをスキャンしたとしても、ライブラリの ID に使用されている文字列を特定する必要があります。文字列が動的メモリのどこに配置されているかを追跡することは、あなたが取り組むよりも難しくなります。
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;
}
対象の実行可能ファイルがある場合、Dependency Walkerはプロファイル メニューを使用してこれを行うことができます。実行可能ファイルをロードし、プロファイリングを開始するように指示するだけで、プログラムの実行中にロードされたすべてのモジュールが一覧表示されます。
簡単に言えば、実行可能ファイルで使用される各 DLL について、PE ファイルのimports セクションをスキャンする必要があります。次に、すべての依存関係が見つかるまで、各 dll を再帰的に見つけてスキャンします。
もちろん、アプリは LoadLibrary ファミリの関数を必須またはオプションの機能として使用できます。この方法では検出されません。
このすべての情報を計算し、CStringの配列として答えを返すために呼び出すことができるDLLはどうですか?
PEフォーマットDLLはあなたのためにこれを行うことができます。ソースコードが付属しており、GPLの制限はありません。PEファイルエクスプローラーは、DLLを使用するGUIアプリであり、ソース(GPLなし)も付属しています。