web-dev-qa-db-ja.com

dllエクスポート関数を列挙するWin32API?

同様の質問が見つかりましたが、探しているものに対する答えはありませんでした。だからここに行きます:

ネイティブのWin32dllの場合、エクスポート関数名を列挙するWin32 APIはありますか?

36
user15071

dumpbin /exportsはほとんどあなたが望むものですが、それは開発者ツールであり、Win32APIではありません。

LoadLibraryEx with DONT_RESOLVE_DLL_REFERENCESは厳重に警告されていますが、この特定のケースではたまたま役に立ちます。DLLをメモリにマッピングするという非常に面倒な作業ですが、実際には何も必要としないか、使用したくありませんライブラリから)、ヘッダーを読むのは簡単です。LoadLibraryExによって返されるモジュールハンドルはそれを指します。

#include <winnt.h>
HMODULE lib = LoadLibraryEx("library.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
assert(((PIMAGE_DOS_HEADER)lib)->e_magic == IMAGE_DOS_SIGNATURE);
PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)((BYTE *)lib + ((PIMAGE_DOS_HEADER)lib)->e_lfanew);
assert(header->Signature == IMAGE_NT_SIGNATURE);
assert(header->OptionalHeader.NumberOfRvaAndSizes > 0);
PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)lib + header->
    OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
assert(exports->AddressOfNames != 0);
BYTE** names = (BYTE**)((int)lib + exports->AddressOfNames);
for (int i = 0; i < exports->NumberOfNames; i++)
    printf("Export: %s\n", (BYTE *)lib + (int)names[i]);

完全に未テストですが、多かれ少なかれ正しいと思います。 (有名な最後の言葉。)

45
ephemient

Microsoft Researchにアクセスして、DetoursLibraryを入手してください。その例の1つは、まさにあなたが求めていることを実行します。ライブラリ全体で、基本的にwin32関数呼び出しの迂回/再ルーティングが非常に簡単になります。そのかなりクールなもの。

回り道

編集:エクスポートテーブルだけを見たい場合は、(少なくともVisual Studioでは)プロジェクトのプロパティを設定して印刷できることにも注意してください。エクスポート/インポートテーブル。私は正確なオプションを思い出すことはできませんが、ググるのは簡単です.

** Edit2:**オプションは、[プロジェクトのプロパティ]-> [リンカー]-> [デバッグ]-> [MapFileの生成]-> [はい(/ MAP)]です。

8
DeusAduro

Ephemientは正しいですが、LoadLibraryExDONT_RESOLVE_DLL_REFERENCESはこのタスクを大幅に簡素化でき、彼が示すよりもさらに単純化できます。 DLLのエクスポートディレクトリを自分で見つけて列挙する代わりに、SymEnumerateSymbolsを使用してシンボルを一覧表示できます。

彼のコードよりもわずかに単純ですが(アサートなし、彼のコードはたったの数行です)、これは少なくとも理論的には、Microsoftがいつか実行可能形式を少し変更するか、正確に変更する必要がある場合に備えて、多少の柔軟性を追加します。 HMODULEが指しているものなので、彼は機能しなくなります(これらの詳細のほとんどはとにかく公式に文書化されていないため)。

3
Jerry Coffin

これを試して:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void EnumExportedFunctions (char *, void (*callback)(char*));
int Rva2Offset (unsigned int);

typedef struct {
    unsigned char Name[8];
    unsigned int VirtualSize;
    unsigned int VirtualAddress;
    unsigned int SizeOfRawData;
    unsigned int PointerToRawData;
    unsigned int PointerToRelocations;
    unsigned int PointerToLineNumbers;
    unsigned short NumberOfRelocations;
    unsigned short NumberOfLineNumbers;
    unsigned int Characteristics;
} sectionHeader;

sectionHeader *sections;
unsigned int NumberOfSections = 0;

int Rva2Offset (unsigned int rva) {
    int i = 0;

    for (i = 0; i < NumberOfSections; i++) {
        unsigned int x = sections[i].VirtualAddress + sections[i].SizeOfRawData;

        if (x >= rva) {
            return sections[i].PointerToRawData + (rva + sections[i].SizeOfRawData) - x;
        }
    }

    return -1;
}

void EnumExportedFunctions (char *szFilename, void (*callback)(char*)) {
    FILE *hFile = fopen (szFilename, "rb");

    if (hFile != NULL) {
        if (fgetc (hFile) == 'M' && fgetc (hFile) == 'Z') {
            unsigned int e_lfanew = 0;
            unsigned int NumberOfRvaAndSizes = 0;
            unsigned int ExportVirtualAddress = 0;
            unsigned int ExportSize = 0;
            int i = 0;

            fseek (hFile, 0x3C, SEEK_SET);
            fread (&e_lfanew, 4, 1, hFile);
            fseek (hFile, e_lfanew + 6, SEEK_SET);
            fread (&NumberOfSections, 2, 1, hFile);
            fseek (hFile, 108, SEEK_CUR);
            fread (&NumberOfRvaAndSizes, 4, 1, hFile);

            if (NumberOfRvaAndSizes == 16) {
                fread (&ExportVirtualAddress, 4, 1, hFile);
                fread (&ExportSize, 4, 1, hFile);

                if (ExportVirtualAddress > 0 && ExportSize > 0) {
                    fseek (hFile, 120, SEEK_CUR);

                    if (NumberOfSections > 0) {
                        sections = (sectionHeader *) malloc (NumberOfSections * sizeof (sectionHeader));

                        for (i = 0; i < NumberOfSections; i++) {
                            fread (sections[i].Name, 8, 1, hFile);
                            fread (&sections[i].VirtualSize, 4, 1, hFile);
                            fread (&sections[i].VirtualAddress, 4, 1, hFile);
                            fread (&sections[i].SizeOfRawData, 4, 1, hFile);
                            fread (&sections[i].PointerToRawData, 4, 1, hFile);
                            fread (&sections[i].PointerToRelocations, 4, 1, hFile);
                            fread (&sections[i].PointerToLineNumbers, 4, 1, hFile);
                            fread (&sections[i].NumberOfRelocations, 2, 1, hFile);
                            fread (&sections[i].NumberOfLineNumbers, 2, 1, hFile);
                            fread (&sections[i].Characteristics, 4, 1, hFile);
                        }

                        unsigned int NumberOfNames = 0;
                        unsigned int AddressOfNames = 0;

                        int offset = Rva2Offset (ExportVirtualAddress);
                        fseek (hFile, offset + 24, SEEK_SET);
                        fread (&NumberOfNames, 4, 1, hFile);

                        fseek (hFile, 4, SEEK_CUR);
                        fread (&AddressOfNames, 4, 1, hFile);

                        unsigned int namesOffset = Rva2Offset (AddressOfNames), pos = 0;
                        fseek (hFile, namesOffset, SEEK_SET);

                        for (i = 0; i < NumberOfNames; i++) {
                            unsigned int y = 0;
                            fread (&y, 4, 1, hFile);
                            pos = ftell (hFile);
                            fseek (hFile, Rva2Offset (y), SEEK_SET);

                            char c = fgetc (hFile);
                            int szNameLen = 0;

                            while (c != '\0') {
                                c = fgetc (hFile);
                                szNameLen++;
                            }

                            fseek (hFile, (-szNameLen)-1, SEEK_CUR);
                            char* szName = calloc (szNameLen + 1, 1);
                            fread (szName, szNameLen, 1, hFile);

                            callback (szName);

                            fseek (hFile, pos, SEEK_SET);
                        }
                    }
                }
            }
        }

        fclose (hFile);
    }
}

例:

void mycallback (char* szName) {
    printf ("%s\n", szName);
}

int main () {
    EnumExportedFunctions ("C:\\Windows\\System32\\user32.dll", mycallback);
    return 0;
}

出力:

ActivateKeyboardLayout
AddClipboardFormatListener
AdjustWindowRect
AdjustWindowRectEx
AlignRects
AllowForegroundActivation
AllowSetForegroundWindow
AnimateWindow
AnyPopup
AppendMenuA
AppendMenuW
ArrangeIconicWindows
AttachThreadInput
BeginDeferWindowPos
BeginPaint
BlockInput
BringWindowToTop
BroadcastSystemMessage
BroadcastSystemMessageA
BroadcastSystemMessageExA
BroadcastSystemMessageExW
BroadcastSystemMessageW
BuildReasonArray
CalcMenuBar
.....etc
2
user5588894

独自のコードを書く手間をかけたくなく、この目的のためにすでに存在するDLL)を使用したい場合は、 PEファイル形式DLL をお勧めします。 =。必要に応じて変更できるようにソースコードが付属しています。GPLについて心配する必要はありません。

DLLの使用方法を示すGUIアプリケーションも利用できます。

1
Stephen Kellett

DLLにエクスポートされている関数を見つける方法を探しているだけの場合は、Microsoftの dependency walker (depends.exe)を使用できます。ただし、実際にプログラムでエクスポートを検出する必要がある場合は、これは役に立ちません。

0
Ferruccio

私は間違っているかもしれませんし、正直に言うと二重にチェックしていませんが、プロセスとは異なるアーキテクチャでビルドされたモジュールでephemientのコードを使用すると互換性の問題が発生する可能性があります。 (繰り返しますが、私は今、完全に私のお尻から話しているかもしれません)

同じテクニックを使用する dll2def と呼ばれるプロジェクトがgithubにあります(それはそれ自体でファイルをメモリにロードしますが)のアーキテクチャに応じてエクスポートを見つけるためにいくつかのチェックが設定されているようですバイナリ。最も興味があると思われるコードは このファイル にあります。

0