1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2017-12-16

遅延インポート関数

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

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

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

IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

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

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

ImgDelayDescr

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

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

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

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

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

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

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);
			}
		}
	}
}

1
2
0

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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?