PE学习日记----导入表

导入表示PE数据组织的一个很重要的组成部分。通过分析导入表数据,可以获得诸如PE文件的指令中调用了多少外来的函数,以及这些外来函数都存在于哪些动态链接库里等信息。

导入表示数据目录中注册的数据类型之一,其描述信息位于数据目录的第2个目录项中。

导入表描述符IMAGE_IMPORT_DESCRIPTOR

导入表数据的起始是一组导入表描述结构,每组20个字节。最后一组为全0结构,表示导入表描述已经结束。Windows在查找导入表的时候并不一定要求最后一组的20个字节都为0,只要其中的字段Name是0就已经满足结束条件了。导入表的每一组都是一个结构,称为导入表描述符IMAGE_IMPORT_DESCRIPTOR,具体结构如下:

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;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;

OriginalFirstThunk:双字。因为它是指向另外数据结构的指针,该字段指向一个包含了一系列结构的数组。

指向的数组中的每个结构定义了一个导入函数的信息,最后以一个内容为全0的结构作为结束。指向的数组中每一项为一个结构,此结构名称为IMAGE_THUNK_DATA.该结构实际上只是一个双字,但在不同的时刻却拥有不同的解释。该字段有两种解释:

1 双字最高位为0,表示导入符号是一个数值,该数值是一个RVA。

2 双字最高位为1,表示导入符号是一个名称。

TimeDateStamp:双字。时间戳,一般不用,多为0.

ForwarderChain:双字。链表的前一个结构。

Name:双字。这里的Name是一个RVA,它指向该结构所对应的DLL文件的名称,而这个名称是以‘\0’结尾的ANSI字符串。

FirstThunk:双字。与OriginalFirstThunk相同,它指向的链表定义了针对name这个动态函数引入的所有动态函数。

IMAGE_THUNK_DATA结构如下:

struct _IMAGE_THUNK_DATA{
    union {
        DWORD ForwarderString;      // PBYTE
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA;

如果该结构最高位为0,表示导入符号是一个数值,该数值是一个RVA。根据RVA指向了另外一个结构IMAGE_IMPORT_BY_NAME,这个结构不确定,IMAGE_IMPORT_BY_NAME结构如下:

struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} ;

Hint:双字。函数的编号,在DLL中对每个函数都进行编号,访问函数时可以通过名称访问,也可以通过编号访问。

Name:大小不确定,函数名字字符串的具体内容,以“\0”作为字符串结束标志。

导入表编程代码如下:

/************************************************************************/
/* 
功能:打印导入表信息
参数:lpFileBuf:起始地址
返回:无
*/
/************************************************************************/
void PrintImport(PVOID lpFileBuf)
{
	//获取DOS头
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpFileBuf;
	//获取PE头
	size_t stPEHeadAddr = (size_t)lpFileBuf + pDos ->e_lfanew;
	PIMAGE_NT_HEADERS32 pNT = (PIMAGE_NT_HEADERS32)stPEHeadAddr;

	//数据目录
	PIMAGE_DATA_DIRECTORY pDir = pNT->OptionalHeader.DataDirectory;
	//获取数据目录表中入表地址
	PIMAGE_DATA_DIRECTORY pImportDir = (PIMAGE_DATA_DIRECTORY)&pDir[IMAGE_DIRECTORY_ENTRY_IMPORT];

	//获取导入
	PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)((size_t)lpFileBuf +
		RVAToOffset(pImportDir->VirtualAddress, lpFileBuf));

	//如果结束时,用name进行判断。
	while ( pImport->Name )
	{
		PCSTR szName = (PCSTR)((size_t)lpFileBuf + RVAToOffset(pImport->Name,lpFileBuf));
		printf("\n==========%s\t==========\n",szName);
		printf("OrginalFirstThunk:%08X\t",pImport->OriginalFirstThunk);
		printf("日期时间标志:%08X\t",pImport->TimeDateStamp);
		printf("ForwarderChain:%08X\t",pImport->ForwarderChain);
		printf("名称:%08X\t",pImport->Name);
		printf("FirstThunk:%08X\t",pImport->FirstThunk);

		//INT表
		PIMAGE_THUNK_DATA32 pINT = (PIMAGE_THUNK_DATA32)((size_t)lpFileBuf + RVAToOffset(pImport->OriginalFirstThunk,lpFileBuf));
		//如果结束时,pINT会是0
		while (pINT->u1.AddressOfData)
		{
			if (!IMAGE_SNAP_BY_ORDINAL32(pINT->u1.AddressOfData))
			{
				PIMAGE_IMPORT_BY_NAME pByName =(PIMAGE_IMPORT_BY_NAME)((size_t)lpFileBuf + RVAToOffset( pINT->u1.AddressOfData , lpFileBuf));
				printf("%08X\t%04X %s\n",pINT->u1.Function,pByName->Hint, pByName->Name);
			}
			else
			{
				printf("%04X[Null]\n",pINT->u1.Ordinal);
			}
			pINT++;
		}
		pImport++;
	}
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值