3. 导入表
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 可忽略
DWORD ForwarderChain; // 可忽略
DWORD Name; // RVA,dll名,0指示结束,不再继续遍历了
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses),0也能指示结束,不再继续遍历了
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR,此结构图中有3个,全0代表结。
RVA 000020A4对应的FA是8A4,是INT部分,图中选中部分代表IMAGE_THUNK_DATA结构,此结构有16个,全0代表结尾。4字节的最高位是0,代表以字符串方式导入,如果最高位为1,代表以序号方式导入。如果08A4h处是00 00 00 00,表示IAT结束,则操作系统不导入此dll,继续遍历下一个。
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // PBYTE
DWORD Function; // PDWORD
DWORD Ordinal;
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
下图把08A4h处的36 21 00 00改为36 21 00 80,此时最高位是1,序号是2136。十六进制2136等于十进制8502,运行报错。
RVA 00002136对应的FA是936,下图选中的是IMAGE_IMPORT_BY_NAME结构。
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //可忽略
CHAR Name[1]; //导入函数名
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
RVA 00002014对应的FA是814,是IAT部分,运行时操作系统会将函数地址填入此处,文件中可以填其他值,但不能填0,0代表结束。
RVA 00002136对应的FA也是936
RVA 000021D6对应的FA是9D6,是dll名字。
.dll后缀不是必须的,修改后可正常运行。
下面把IMAGE_IMPORT_DESCRIPTOR的OriginalFirstThunk清零,代表没有INT表,再覆盖原INT表,也能正常运行。操作系统从IAT表中读取数据,查询函数地址,原地写入。
手工插入两个IMAGE_IMPORT_DESCRIPTOR,实现注入效果,选中部分是新插入的第1个IMAGE_IMPORT_DESCRIPTOR,紧接着是新插入的第2个。程序运行时,FA为800h的位置映射到RVA为2000h的位置。