更多导入表内容
IAT dll包含
可以通过IMAGE_IMPORT_DESCRIPTOR访问PE文件中DLL名称,INT,IAT的地址
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 表示结构数组的结束
DWORD OriginalFirstThunk; // 指向 INT (Import Name Table)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 时间戳
DWORD ForwarderChain; // 转发链
DWORD Name; // DLL名称的RVA
DWORD FirstThunk; // 指向 IAT (Import Address Table)
} IMAGE_IMPORT_DESCRIPTOR;
// PE文件的导入表可能是这样的:
导入表
├── Import Descriptor 1 (kernel32.dll)
│ ├── Name: "kernel32.dll" //DLL的名称
│ ├── OriginalFirstThunk: -> [函数1, 函数2, ...] //INT的RVA
│ └── FirstThunk: -> [地址1, 地址2, ...]//IAT的RVA
├── Import Descriptor 2 (user32.dll)
│ ├── Name: "user32.dll"
│ ├── OriginalFirstThunk: -> [函数1, 函数2, ...]
│ └── FirstThunk: -> [地址1, 地址2, ...]
└── Import Descriptor 3 (NULL 结束标记)
可以通过循环访问IAT导入表的IMAGE_IMPORT_DESCRIPTOR:
for (SIZE_T i = 0; i < pEntryImportDataDir->Size; i += sizeof(IMAGE_IMPORT_DESCRIPTOR))
//pEntryImportDataDir->Size 表示整个导入目录的大小
//这个大小等于所有 IMAGE_IMPORT_DESCRIPTOR 结构的总大小
{
//这里是DLL名称
LPSTR cDllName = (LPSTR)(pPeBaseAddress + pImgDescriptor->Name);
//这里是INT
ULONG_PTR uOriginalFirstThunkRVA = pImgDescriptor->OriginalFirstThunk;
//这里是IAT
ULONG_PTR uFirstThunkRVA = pImgDescriptor->FirstThunk;
//这里通过LoadLibraryA获取DLL
if (!(hModule = LoadLibraryA(cDllName))) {
PRINT_WINAPI_ERR("LoadLibraryA");
return FALSE;
}
}
INT和IAT的关系:
// INT 包含了函数的名称信息
struct {
union {
DWORD Name; // 指向函数名称
WORD Ordinal; // 或者函数序号
} u1;
} ImportNameTable[];
// IAT 最终会包含函数的实际地址
struct {
union {
DWORD Function; // 将被替换为函数的实际地址
} u1;
} ImportAddressTable[];
INT里又包含一个u1数据结构:
typedef struct _IMAGE_THUNK_DATA64 {
union {
ULONGLONG ForwarderString; // 不使用
ULONGLONG Function; // 函数地址
ULONGLONG Ordinal; // 函数Ordinal
ULONGLONG AddressOfData; // RVA to PIMAGE_IMPORT_BY_NAME - used only if the function is imported by name rather by ordinal.
} u1;
} IMAGE_THUNK_DATA64;
然后再在for循环内部增加一个while循环,获取IMAGE_IMPORT_DESCRIPTOR每个数据结构中的具体地址:
// 如果是ordinal函数,通过GetProcAddress(dllName,ordinal)获取函数地址
if (IMAGE_SNAP_BY_ORDINAL(pOriginalFirstThunk->u1.Ordinal)) {
//pOriginalFirstThunk指向INT里面的u1数据结构
if ( !(pFuncAddress = (ULONG_PTR)GetProcAddress(hModule, IMAGE_ORDINAL(pOriginalFirstThunk->u1.Ordinal))) ) {
printf("[!] Could Not Import !%s#%d \n", cDllName, (int)pOriginalFirstThunk->u1.Ordinal);
return FALSE;
}
}
//通过函数名称获取
else {
pImgImportByName = (PIMAGE_IMPORT_BY_NAME)(pPeBaseAddress + pOriginalFirstThunk->u1.AddressOfData);
if ( !(pFuncAddress = (ULONG_PTR)GetProcAddress(hModule, pImgImportByName->Name)) ) {
printf("[!] Could Not Import !%s.%s \n", cDllName, pImgImportByName->Name);
return FALSE;
}
}
// 最后把函数地址patch到IAT上
pFirstThunk->u1.Function = (ULONGLONG)pFuncAddress;