遅延インポート関数
前回はインポート関数の列挙を解説しました。
このインポート関数は「静的」にインポートされる関数の一覧であり、
その関数を持つモジュールは起動する際同時に読み込まれます。
これに対して「動的」にインポートされる関数があり、
「遅延インポート」と呼ばれています。
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に関しては、インポートの時に解説した物と同じになりますので、
これを踏まえて列挙すると以下の様な形になります。
for (int i = 0; pDelay[i].rvaDLLName != 0; ++i)
{
ImgDelayDescr& tDelay = pDelay[i];
LPCSTR szOrg = (char*)&(pFile[tDelay.rvaDLLName - delta]);
_tprintf(TEXT("\n[%s]"), (LPCTSTR)CA2T(szOrg));
if (b64 == false)
{
IMAGE_THUNK_DATA32* pINT = (IMAGE_THUNK_DATA32*)&(pFile[tDelay.rvaINT - delta]);
IMAGE_THUNK_DATA32* pIAT = (IMAGE_THUNK_DATA32*)&(pFile[tDelay.rvaIAT - delta]);
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*)&(pFile[pINT[j].u1.AddressOfData - delta]));
_tprintf(TEXT("\n\t%s[%d]"), (LPCTSTR)CA2T(tName.Name), tName.Hint);
}
}
}
else
{
IMAGE_THUNK_DATA64* pINT = (IMAGE_THUNK_DATA64*)&(pFile[tDelay.rvaINT - delta]);
IMAGE_THUNK_DATA64* pIAT = (IMAGE_THUNK_DATA64*)&(pFile[tDelay.rvaIAT - delta]);
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*)&(pFile[pINT[j].u1.AddressOfData - delta]));
_tprintf(TEXT("\n\t%s[%d]"), (LPCTSTR)CA2T(tName.Name), tName.Hint);
}
}
}
}
問題点
基本上記のコードで正常に動作するのですが、一部デバッグモジュールを通すと
モジュール名(rvaDLLName)が正常な文字列として取得できません。
こちらに関しては現在確認中です。
#やり方が悪いのか、理解が足りてないのか…