更多导入表内容

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;