DLLのエクスポートディレクトリ

解決


forty-five  2011-03-28 18:23:18  No: 72524  IP: 192.*.*.*

DLLのエクスポートディレクトリを取得したいのですがうまくいきません。
DLLをロードすればうまくいくんですが、できれば
Dependency Walkerのようにロードしないで取得したいです。

下記のコードですと、exportDirectory->NumberOfNamesが
425297となり、この時点で明らかに異常な数値になってしまいます。
fileDataではなく、moduleを使うとちゃんと954になり、うまくいきます。
dosとntまでは正しい情報が取れているようです。
exportDirectoryからがおかしいようです。

ファイルデータとしてただ読み込んだだけでは
DLLの解析はできないのでしょうか?

環境はVC6 WinXP HomeEdition SP3です。
よろしくお願いします。

#define MAKE_PTR(type, ptr, offset) (type)((DWORD)(ptr)+(DWORD)(offset))

void dump(HMODULE module)
{
  // モジュールのパスを取得
  TCHAR path[MAX_PATH]; ::GetModuleFileName(module, path, MAX_PATH);
  // ファイルを開く
  HANDLE file = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  // ファイルサイズを取得する
  DWORD fileSize = ::GetFileSize(file, 0);
  // ファイルデータ用のバッファを確保する
  BYTE* fileData = new BYTE[fileSize];
  // ファイルデータを取得する
  ::ReadFile(file, fileData, fileSize, &fileSize, 0);
  // ファイルを閉じる
  ::CloseHandle(file);
  // イメージ情報を取得する
//  IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)module; // これだとうまくいく
  IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)fileData;
  IMAGE_NT_HEADERS* nt = MAKE_PTR(IMAGE_NT_HEADERS*, dos, dos->e_lfanew);
  IMAGE_EXPORT_DIRECTORY* exportDirectory = MAKE_PTR(IMAGE_EXPORT_DIRECTORY*, dos,
    nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  // エクスポートディレクトリの情報を取得する
  DWORD* nameTable = MAKE_PTR(DWORD*, dos, exportDirectory->AddressOfNames);
  WORD* ordinalTable = MAKE_PTR(WORD*, dos, exportDirectory->AddressOfNameOrdinals);
  DWORD* addressTable = MAKE_PTR(DWORD*, dos, exportDirectory->AddressOfFunctions);
  // エクスポートディレクトリをダンプする
  for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) {
    LPCSTR name = MAKE_PTR(LPCSTR, dos, nameTable[i]);
    WORD ordinal = ordinalTable[i];
    PROC proc = (PROC)addressTable[i];
    printf("%3d, %3d, %08X, %s\n", i, ordinal, proc, name);
  }
  // バッファを開放する
  delete[] fileData;
}

void main()
{
  dump(::GetModuleHandle(TEXT("kernel32.dll")));
}

編集 削除
n  2011-03-30 21:56:30  No: 72525  IP: 192.*.*.*

CreateFileMapping() の SEC_IMAGE を利用すれば、LoadLibrary() でロードした場合と同じようにデータが配置されます。

void dump(HMODULE module)
{
TCHAR path[MAX_PATH]; ::GetModuleFileName(module, path, MAX_PATH);
HANDLE file = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
HANDLE map = ::CreateFileMapping(file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
LPVOID view = ::MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)view;
IMAGE_NT_HEADERS* nt = MAKE_PTR(IMAGE_NT_HEADERS*, dos, dos->e_lfanew);
IMAGE_EXPORT_DIRECTORY* exportDirectory = MAKE_PTR(IMAGE_EXPORT_DIRECTORY*, dos,
nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* nameTable = MAKE_PTR(DWORD*, dos, exportDirectory->AddressOfNames);
WORD* ordinalTable = MAKE_PTR(WORD*, dos, exportDirectory->AddressOfNameOrdinals);
DWORD* addressTable = MAKE_PTR(DWORD*, dos, exportDirectory->AddressOfFunctions);
for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) {
LPCSTR name = MAKE_PTR(LPCSTR, dos, nameTable[i]);
WORD ordinal = ordinalTable[i];
PROC proc = (PROC)addressTable[i];
printf("%3d, %3d, %08X, %s\n", i, ordinal, proc, name);
}
::UnmapViewOfFile(view);
::CloseHandle(map);
::CloseHandle(file);
}

編集 削除
forty-five  2011-03-31 19:07:22  No: 72526  IP: 192.*.*.*

コピペするだけで完璧に動作しました。
非常に助かりました。ありがとうございました。

編集 削除
forty-five  2011-04-02 18:56:14  No: 72527  IP: 192.*.*.*

少しおかしいところがあったので修正しました。
これでDependency Walkerとほぼ同じになりました。

void dump(HMODULE module)
{
    TCHAR path[MAX_PATH]; ::GetModuleFileName(module, path, MAX_PATH);
    _tprintf(TEXT("dump %s\n"), path);

    HANDLE file = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    HANDLE map = ::CreateFileMapping(file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
    LPVOID view = ::MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);

    IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)view;
    IMAGE_NT_HEADERS* nt = MAKE_PTR(IMAGE_NT_HEADERS*, dos, dos->e_lfanew);
    IMAGE_EXPORT_DIRECTORY* exportDirectory = MAKE_PTR(IMAGE_EXPORT_DIRECTORY*, dos,
        nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    DWORD* nameTable = MAKE_PTR(DWORD*, dos, exportDirectory->AddressOfNames);
    WORD* ordinalTable = MAKE_PTR(WORD*, dos, exportDirectory->AddressOfNameOrdinals);
    DWORD* addressTable = MAKE_PTR(DWORD*, dos, exportDirectory->AddressOfFunctions);

    for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) {
        LPCSTR name = MAKE_PTR(LPCSTR, dos, nameTable[i]);
        WORD ordinal = ordinalTable[i];
        PROC proc = (PROC)addressTable[ordinal]; // 修正
        printf("%3d, %3d, %08X, %s\n", i, ordinal + exportDirectory->Base, proc, name); // 修正
    }

    ::UnmapViewOfFile(view);
    ::CloseHandle(map);
    ::CloseHandle(file);

    _tprintf(TEXT("\n"));
}

void main()
{
    dump(::LoadLibrary(TEXT("kernel32.dll")));
    dump(::LoadLibrary(TEXT("shell32.dll")));
}

編集 削除