PEファイルのバイナリ構造(8) 遅延インポート関数の列挙

# 遅延インポート関数

前回はインポート関数の列挙を解説しました。

このインポート関数は「静的」にインポートされる関数の一覧であり、
その関数を持つモジュールは起動する際同時に読み込まれます。

これに対して「動的」にインポートされる関数があり、
「遅延インポート」と呼ばれています。

# IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

セクションに関してはもうお馴染みの手順で、
配列の添え字だけ「IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT」として確認します。

```cpp
IMAGE_DATA_DIRECTORY& tData = tNT.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
DWORD nOffset = tData.VirtualAddress;
```

# ImgDelayDescr

インポートの時と同じ手順でセクションまで確認後、ImgDelayDescrのポインタへとキャストします。

ImpDelayDescrを使う際には「delayimp.h」をインクルードしておきます。

```cpp
ImgDelayDescr* pDelay = (ImgDelayDescr*)&(pFile[nOffset - delta]);
```

ImgDelayDescr は以下の様に定義されています。

```cpp:
typedef DWORD RVA;
typedef struct ImgDelayDescr {  
    DWORD        grAttrs;        // attributes  
    RVA          rvaDLLName;     // RVA to dll name  
    RVA          rvaHmod;        // RVA of module handle  
    RVA          rvaIAT;         // RVA of the IAT  
    RVA          rvaINT;         // RVA of the INT  
    RVA          rvaBoundIAT;    // RVA of the optional bound IAT  
    RVA          rvaUnloadIAT;   // RVA of optional copy of original IAT  
    DWORD        dwTimeStamp;    // 0 if not bound,  
                                 // O.W. date/time stamp of DLL bound to (Old BIND)  
} ImgDelayDescr, * PImgDelayDescr;  
```

後は構造体の配列として定義されていますので、
rvaDLLNameが0になるまでループします。

rvaIATとrvaINTに関しては、インポートの時に解説した物と同じになりますので、
これを踏まえて列挙すると以下の様な形になります。

ただし、これまではrvaに対してdeltaとして一定の差分をとっていましたが、各ポインタに対して逐次計算をする必要があります。
＃これまでは偶々同一セクションでしたが、本来は逐次全ポインタに対して確認を取った方が良さそう

```cpp:
inline DWORD rva2address(DWORD rva, PIMAGE_SECTION_HEADER sec)
{
	DWORD delta = sec->VirtualAddress - sec->PointerToRawData;
	return rva - delta;
}

```

```cpp:
for (int i = 0; pDelay[i].rvaDLLName != 0; ++i)
{
	ImgDelayDescr& tDelay = pDelay[i];
	LPCSTR szOrg = (char*)(rva2address(pFile[tDelay.rvaDLLName], sec));
	_tprintf(TEXT("\n[%s]"), (LPCTSTR)CA2T(szOrg));
	if (b64 == false)
	{
		IMAGE_THUNK_DATA32* pINT = (IMAGE_THUNK_DATA32*)(rva2address(pFile[tDelay.rvaINT], sec)));
		IMAGE_THUNK_DATA32* pIAT = (IMAGE_THUNK_DATA32*)(rva2address(pFile[tDelay.rvaIAT], sec)));
		for (int j = 0; pINT[j].u1.AddressOfData != 0 && pIAT[j].u1.Function != 0; ++j)
		{
			if (IMAGE_SNAP_BY_ORDINAL32(pINT[j].u1.Ordinal))
			{
				_tprintf(TEXT("\n\t(NONAME)[%d]"), (int)IMAGE_ORDINAL32(pINT[j].u1.Ordinal));
			}
			else
			{
				IMAGE_IMPORT_BY_NAME& tName = (*(IMAGE_IMPORT_BY_NAME*)(rva2address(pFile[pINT[j].u1.AddressOfData], sec))));
				_tprintf(TEXT("\n\t%s[%d]"), (LPCTSTR)CA2T(tName.Name), tName.Hint);
			}
		}
	}
	else
	{
		IMAGE_THUNK_DATA64* pINT = (IMAGE_THUNK_DATA64*)(rva2address(pFile[tDelay.rvaINT], sec));
		IMAGE_THUNK_DATA64* pIAT = (IMAGE_THUNK_DATA64*)(rva2address(pFile[tDelay.rvaIAT], sec);
		for (int j = 0; pINT[j].u1.AddressOfData != 0 && pIAT[j].u1.Function != 0; ++j)
		{
			if (IMAGE_SNAP_BY_ORDINAL64(pINT[j].u1.Ordinal))
			{
				_tprintf(TEXT("\n\t(NONAME)[%d]"), (int)IMAGE_ORDINAL64(pINT[j].u1.Ordinal));
			}
			else
			{
				IMAGE_IMPORT_BY_NAME& tName = (*(IMAGE_IMPORT_BY_NAME*)rva2address(pFile[pINT[j].u1.AddressOfData], sec));
				_tprintf(TEXT("\n\t%s[%d]"), (LPCTSTR)CA2T(tName.Name), tName.Hint);
			}
		}
	}
}

```