1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

IATを列挙

Last updated at Posted at 2021-05-30

諸注意

自分用なのでもしかしたら間違ってるかもしれない…

IATの概要

IATの場所

image.png
インポートセクションのインポートテーブルは IMAGE_IMPORT_DESCRIPTOR 構造体の配列として表現されていて、インポートしているDLLごとに用意されてる( IMAGE_IMPORT_DESCRIPTORName メンバを見れば何の名前のDLLの IMAGe_IMPORT_DESCRIPTOR なのかわかる)。
その中の FirstThunk メンバがIATのアドレスを保持している。

IATの状態について

IATはプログラムがロードされる前と後で入ってるものが違う。

  • ロード前:IMAGE_THUNK_DATA 構造体の配列でILTと同じ
  • ロード後:IMAGE_IMPORT_DESCRIPTOR->Name のDLLからの各関数のアドレス

Visual Studio を立ち上げる

新しいプロジェクトの作成をしたあと、以下の 空のプロジェクト を選ぶ。
image.png
次に、下記の所でx64用に変更する。
image.png
次に、ALT-Enterを押してソリューションのプロパティ画面を表示し、リンカー > システム の所でサブシステムを Windows ... に変更する。
image.png
続いて同じプロパティ画面で、詳細 を見て、文字セットを マルチバイト文字セットを使用する に変更する(これしないと文字化けした)。
image.png
これでOKして閉じた後、C++コードを以下のようにして追加する。
image.png
image.png
これで準備が整った。

使ってるDLLの列挙

いきなりIATを列挙するのはキツイので、まずはインポートしてるDLLを列挙してみる。
IATの先ほどの内容を振り返ると、DLL事にインポートテーブルがあり、インポートテーブル( IMAGE_IMPORT_DESCRIPTOR )の Name メンバにそのDLLの名前がある。これを全て列挙する。

ListDll.cpp
# include <windows.h>
# include <dbghelp.h>
# include <stdlib.h>
# include <iostream>
# include <sstream>
# pragma comment(lib, "dbghelp.lib")

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow
) {
	ULONG cbSize;
	TCHAR szMyPath[MAX_PATH];
	HMODULE hModule;
	PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor = NULL;

	GetModuleFileName(NULL, szMyPath, _countof(szMyPath));
	hModule = GetModuleHandle((LPCSTR)szMyPath);

	pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &cbSize);

	if (pImageImportDescriptor == NULL)
		MessageBox(NULL, TEXT("error"), TEXT("null"), MB_OK);
	else {
		while (pImageImportDescriptor->Name != NULL) {
			LPCSTR pszDllName = (LPCSTR)((PBYTE)(hModule)+pImageImportDescriptor->Name);
			MessageBox(NULL, pszDllName, TEXT("DLL name"), MB_OK);
			pImageImportDescriptor++;
		}
	}

	CloseHandle(hModule);
	return 0;
}

ここで、最初の方に

GetModuleFileName(NULL, szMyPath, _countof(szMyPath));
hModule = GetModuleHandle((LPCSTR)szMyPath);

があるのは、実は先ほどFirstChunkにはIATへのアドレスがあるといったが、これは具体的には相対アドレスであり、最初の図の OptionalHeaderImageBase からの相対アドレスになっている。なんで相対アドレスなのかというと、ImageBase はプログラムがメモリ上にロードされる際の先頭の位置であり、ここがいつも固定ではないため、ここからの相対アドレスとして全部指定するようになってる。
所々、(LBYTE)hModule + ... のような計算があるのはそういう理由。

実際の処理として大事で押さえておけばいい所は以下の2点だけ、

// IMAGE_IMPORT_DESCRIPTORのポインタの取得
 pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &cbSize);

// IMAGE_IMPORT_DESCRIPTORのNameメンバを取得
LPCSTR pszDllName = (LPCSTR)((PBYTE)(hModule)+pImageImportDescriptor->Name);

これをでは、Visual Studio上で、Ctrl-b でビルドし、ビルドすると、
image.png
こんな感じでどこに実行ファイルができたか書いてあるので、これを実行する。

image.png

こんな感じで何度も MessageBox でDLLの名前が列挙されるはず。

IATの列挙(本題)

とりあえず、一番最初の Kernel32.dll からインポートされている関数のアドレスをIATから列挙したい。
ただ、アドレスだけ表示されても Kernel32.dll の何の関数かわからないので、関数名も列挙したい。
しかし、よく考えると、プログラムをロード後のIATにはアドレスはあっても関数の名前を表すメンバは存在しない。それなので関数名の方は、最初の図を思い出して、FirstThunk ではなく、OriginalFirstThunk が指しているILT(IMAGE_THUNK_DATAの集まり)の方の Name メンバから取ってくる。
実際のコードが以下。

List-IAT.cpp
# include <windows.h>
# include <dbghelp.h>
# include <stdlib.h>
# include <iostream>
# include <sstream>
# pragma comment(lib, "dbghelp.lib")

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow
) {
	ULONG cbSize;
	TCHAR szMyPath[MAX_PATH];
	HMODULE hModule;
	PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor = NULL;
	PIMAGE_THUNK_DATA pFirstThunk = NULL;
	PIMAGE_THUNK_DATA pOriginalFirstThunk = NULL;

	GetModuleFileName(NULL, szMyPath, _countof(szMyPath));
	hModule = GetModuleHandle((LPCSTR)szMyPath);
	pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &cbSize);
	pFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImageImportDescriptor->FirstThunk);
	pOriginalFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImageImportDescriptor->OriginalFirstThunk);
	
	LPCSTR pszDllName = (LPCSTR)((PBYTE)hModule + pImageImportDescriptor->Name);
	MessageBox(NULL, pszDllName, "will show imports func addr from this dll", MB_OK);

	while(pFirstThunk->u1.Function != NULL) {
		std::stringstream ss;
		ss << "0x" << std::hex << pFirstThunk->u1.Function << std::endl;

		PIMAGE_IMPORT_BY_NAME pImageImportByName = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hModule + pOriginalFirstThunk->u1.AddressOfData);
		LPCSTR pszFuncName = (LPCSTR)&pImageImportByName->Name[0];

		MessageBox(NULL, ss.str().c_str(), pszFuncName, MB_OK);
		pFirstThunk++;
		pOriginalFirstThunk++;
	}

	CloseHandle(hModule);
	return 0;
}

注意するべきなのは、IATはロード後はアドレスが入っているので、IMAGE_THUNK_DATA 型を使うのは変なのでは? と思うが、まぁプログラム上でこうしてるだけで、実際にIATの方から関数名を見つけようとしてもできなかったので、これであってる。

流れを把握する上で押さえておくべき行は以下。

// IMAGE_IMPORT_DESCRIPTORのFirstThunkとOriginalFirstThunkへのポインタを取得
pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &cbSize);
pFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImageImportDescriptor->FirstThunk);
pOriginalFirstThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModule + pImageImportDescriptor->OriginalFirstThunk);

// IMAGE_IMPORT_DESCRIPTORのNameからDLL名を取得(今回は最初のKernel32.dllだけ)
LPCSTR pszDllName = (LPCSTR)((PBYTE)hModule + pImageImportDescriptor->Name);

// これがIATのアドレス(ロード後の各関数の配置されてるアドレス)
pFirstThunk->u1.Function

// ILTのIMAGE_THUNK_DATA構造体のAddressOfDataメンバにIMAGE_IMPORT_BY_NAMEという構造体があり、
// そのName属性が関数名になってる。(ILTに直接関数名があるわけではないので注意)
PIMAGE_IMPORT_BY_NAME pImageImportByName = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hModule + pOriginalFirstThunk->u1.AddressOfData);

これで再びビルドして実行すると、
image.png
こんな感じで関数とそのアドレスが列挙されるので、IATが列挙されていることを確認できる。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?