#include <stdio.h>
#include <windows.h>
int main(int argc,char* argv[]){
/*
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union{
DWORD Characteristics;
DWORD OriginalFirstThunk;
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; // DLL名称的RVA偏移
DWORD FirstThunk; // IAT真实地址的RVA偏移
}IMAGE_IMPORT_DESCRIPTOR;
*/
/*
typedef struct _IMAGE_THUNK_DATA32{
union{
DWORD ForwarderString;
DWORD Function;
DWORD Ordinal;
DWORD AddressOfData; // RVA指向_IMAGE_IMPORT_BY_NAME
}u1;
}IMAGE_THUNK_DATA32;
*/
/*
typedef struct _IMAGE_IMPORT_BY_NAME{
WORD Hint;
BYTE Name[1];
}IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
*/
HMODULE hmod;
PIMAGE_DOS_HEADER pdos;
PIMAGE_NT_HEADERS pnt;
PIMAGE_OPTIONAL_HEADER popt;
PIMAGE_IMPORT_DESCRIPTOR piid;
PIMAGE_THUNK_DATA pfuncname_addr,pfunc_addr;
hmod = GetModuleHandle(NULL); // HMODULE类型不能直接参与运算,要强制转换为字节流
pdos = (PIMAGE_DOS_HEADER)hmod;
pnt = (PIMAGE_NT_HEADERS)((BYTE *)hmod + pdos->e_lfanew); // NT_offset = dos.e_lfanew
popt = (PIMAGE_OPTIONAL_HEADER)(&(pnt->OptionalHeader));
piid = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hmod+popt->DataDirectory[1].VirtualAddress); // Base_addr + RVA_addr
while(piid->FirstThunk){
pfuncname_addr = (PIMAGE_THUNK_DATA)((BYTE *)hmod + piid->OriginalFirstThunk);
pfunc_addr = (PIMAGE_THUNK_DATA)((BYTE *)hmod + piid->FirstThunk);
char* pdll_name = (char *)((BYTE *)hmod + piid->Name);
printf("DLL:%s
",pdll_name);
printf("|
");
while(pfuncname_addr->u1.Function){
char* func_name = (char *)((BYTE *)hmod + pfuncname_addr->u1.AddressOfData+2);
DWORD lpAddr = pfunc_addr->u1.AddressOfData;
printf("Func_Name:%s ",func_name); // OriginalFirstThunk对应一个结构体数组,分别是每个函数的名称
printf("Addr:0x%04x
",lpAddr); // FirstThunk对应一个结构体数组,开始与OriginalFirstThunk相同,之后填入函数的真实地址
pfuncname_addr++;
pfunc_addr++;
}
printf("
");
piid++; // 每个DLL对应一个IID项
}
getchar();
return 0;
}
简单解释
通过获取本进程的模块句柄,从而定位到文件载入的内存区域!再用 DOS 头的 e_lfanew 偏移到 NT 头,用 NT 头找到 Optional 头。其中 Optional 的 DataDirectory 的第一个索引项就对应第一个 IID 项,再通过 IID 定位到 OriginalFirstThunk 和 FirstThunk,循环获取每一个函数的名称与内存地址!再外层循环每一个 DLL!最终打印出所有 DLL 的 IAT 函数名称与内存地址!
注意
OriginalFirstThunk
指向的 u1.AddressOfData 是 Hint/Name 所在的结构体
FirstThunk
指向的 u1.AddressOfData 此时已经填入函数在内存的真实地址