当前位置 博文首页 > KOOKNUT的博客:PE文件学习--导入表

    KOOKNUT的博客:PE文件学习--导入表

    作者:[db:作者] 时间:2021-07-02 18:36

    写在前面的话:今年疫情在家,才开始在CSDN与各位大佬们分享交流技术,最近一个月返校之后,一直忙碌于学校课设和期末考试的备考(毕竟平时不怎么听课),所以博客几乎一个多月没有更新,最近只剩下一门考试了,今天小库又回来了。
    之前有关PE文件的知识好像更新到了导出表,今日来看看导入表。
    我们提到导入表,最常说的就是导入表的双桥结构
    先来看一下导入表描述符结构体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;
    

    老规矩,其中各字段的简单介绍。。
    @Characteristics:属性
    @OriginalFirstThunk:指向的是一个数组,数组中每个结构定义了一个导入函数的信息,最后以一个内容为全0的结构最为结束。指向的数组中每一项为一个IMAGE_THUNK_DATA结构,这是一个结构体,32位下大小是双字(DWORD,64位下为ULONGLONG),最高位0时,表示一个数值RVA,为1时,表示导入符号是一个名称。这也是经常说的桥1。
    @TimeDateStamp:时间戳,一般为0。如果该导入表项被绑定,那么绑定后的这个时间戳就被设置对应DLL文件的时间戳。
    @ForwarderChain:链表的前一个结构,如果没有,则为-1.
    @Name:指向链接库名字的指针’\0’结尾的Ansi字符串。
    @FirstThunk:我们所说的桥2,也是一个IMAGE_THUNK_DATA结构,指向当前导入动态库引入的所有导入函数。
    导入表中最重要的结构莫不是双桥结构,桥1和桥2最终指向了同一个地方,是一个PIMAGE_IMPORT_BY_NAME结构体,但是这是在桥2没有发生断裂的前提下。
    桥1指向的是INT(Import Name Table)表,其中的每一个成员都是一个RVA,指向PIMAGE_IMPORT_BY_NAME,这个结构体中两个成员分别表示函数编号和函数名称的字符串。直到遇到内容全0,INT表遍历结束。
    桥2指向的是IAT(Import Address Table)表,在PE文件装入内存之前,它里面的成员和INT中指向的是一样的,直到PE文件被加载进虚拟内存空间之后,会发生断裂,其中指向的是函数的VA。
    有关桥1桥2,在恢复导入表钩子的代码中有使用举例。
    值得注意的一点是,单桥结构无法执行绑定导入操作,因为当PE文件加载进内存,如果不存在桥1,则无法重新找到VA到底调用了哪个函数,自然无法实施绑定。
    下面给一个我自己写的枚举导入表信息的关键代码:

    BOOL EnumImportTableAsDataFileInternal32(PVOID ModuleBase, list<IMPORT_DATA>& DataList,list<IMPORT>& DataList2)
    {
    	DWORD Size = 0;
    	PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = NULL;
    	PIMAGE_THUNK_DATA32 pImportProcNameList = NULL;
    	PIMAGE_THUNK_DATA32 pImportProcAddressList = NULL;
    	PIMAGE_IMPORT_BY_NAME pINTItem = NULL;
    
    	DWORD FOA = 0;
    
    	BOOL IsBind = FALSE;
    	int Index = 0;
    	ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)PEGetMemberInModule((HMODULE)ModuleBase, &Size, IMAGE_DIRECTORY_ENTRY_IMPORT, FALSE, TRUE);
    
    	// 时间戳
    	if (ImportDescriptor->TimeDateStamp == 0)
    	{
    		IsBind = FALSE;
    	}
    	else
    	{
    		IsBind = TRUE;
    	}
    
    	while (TRUE)
    	{
    		IMPORT Data2 = { 0 };
    		Index = 0;
    		// 空项结尾
    		if (ImportDescriptor->Characteristics == 0)
    		{
    			break;
    		}
    
    		GetFOA32((PBYTE)ModuleBase, ImportDescriptor->FirstThunk, &FOA);
    		// IAT
    		pImportProcAddressList = (PIMAGE_THUNK_DATA32)((PBYTE)ModuleBase + FOA);
    		Data2.ImportProcAddress = (DWORD)pImportProcAddressList;
    		Data2.FOAImportProcAddress = FOA;
    
    		GetFOA32((PBYTE)ModuleBase, ImportDescriptor->OriginalFirstThunk, &FOA);
    		// INT
    		pImportProcNameList = (PIMAGE_THUNK_DATA32)((PBYTE)ModuleBase + FOA);
    		Data2.ImportProcName = (DWORD)pImportProcNameList;
    		Data2.FOAImportProcName = FOA;
    
    		while (TRUE)
    		{
    			// 遍历到尽头了
    			if (pImportProcNameList[Index].u1.Function == NULL)
    			{
    				
    				break;
    			}
    			else
    			{
    				if (pImportProcNameList[Index].u1.Function & IMAGE_ORDINAL_FLAG)
    				{
    					// 索引导入
    				}
    				else
    				{
    					GetFOA32((PBYTE)ModuleBase, pImportProcNameList[Index].u1.AddressOfData, &FOA);
    					pINTItem = (PIMAGE_IMPORT_BY_NAME)(FOA + (PBYTE)ModuleBase);
    				}
    				IMPORT_DATA Data = { 0 };
    				// 序号,便于修正地址时查询
    				WORD Hint = pINTItem->Hint;
    				Data.Ordinals = Hint;
    
    
    
    				// 名称
    				PCHAR Name = (PCHAR)pINTItem->Name;
    				Data.FunctionName = Name;
    
    
    				// Dll名称
    				GetFOA32((PBYTE)ModuleBase, ImportDescriptor->Name, &FOA);
    				PCHAR DllName = (PCHAR)(FOA + (PBYTE)ModuleBase);
    				Data.DllName = DllName;
    				Data2.DllName = DllName;
    				
    
    				if (IsBind)
    				{
    					// 指向函数地址
    					GetFOA32((PBYTE)ModuleBase, pImportProcAddressList[Index].u1.Function, &FOA);
    				}
    				DataList.push_back(Data);
    				Index++;
    			}
    		}
    		Data2.NumberOfFunction = Index;
    		Data2.TimeDateStamp = ImportDescriptor->TimeDateStamp;
    		BOOL IsOk = FALSE;
    		for (list<IMPORT>::iterator i = DataList2.begin();i != DataList2.end();i++)
    		{
    			if (Data2.DllName == i->DllName)
    			{
    				IsOk = TRUE;
    			}
    		}
    		if (IsOk == FALSE)
    		{
    			DataList2.push_back(Data2);
    		}
    		
    		ImportDescriptor++;
    
    		
    	}
    
    	return TRUE;
    }
    
    BOOL EnumImportTableAsDataFileInternal64(PVOID ModuleBase, list<IMPORT_DATA>& DataList, list<IMPORT>& DataList2)
    {
    	DWORD Size = 0;
    	PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = NULL;
    	PIMAGE_THUNK_DATA64 pImportProcNameList = NULL;
    	PIMAGE_THUNK_DATA64 pImportProcAddressList = NULL;
    	PIMAGE_IMPORT_BY_NAME pINTItem = NULL;
    	IMPORT_DATA Data = { 0 };
    	DWORD FOA = 0;
    
    	BOOL IsBind = FALSE;
    	int Index = 0;
    	ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)PEGetMemberInModule((HMODULE)ModuleBase, &Size, IMAGE_DIRECTORY_ENTRY_IMPORT, TRUE, TRUE);
    
    	// 时间戳
    	if (ImportDescriptor->TimeDateStamp == 0)
    	{
    		IsBind = FALSE;
    	}
    	else
    	{
    		IsBind = TRUE;
    	}
    
    	while (TRUE)
    	{
    		IMPORT Data2 = { 0 };
    		Index = 0;
    		// 空项结尾
    		if (ImportDescriptor->Characteristics == 0)
    		{
    			break;
    		}
    
    		GetFOA64((PBYTE)ModuleBase, ImportDescriptor->FirstThunk, &FOA);
    		// IAT
    		pImportProcAddressList = (PIMAGE_THUNK_DATA64)((PBYTE)ModuleBase + FOA);
    		Data2.ImportProcAddress = (DWORD)pImportProcAddressList;
    		Data2.FOAImportProcAddress = FOA;
    
    		GetFOA64((PBYTE)ModuleBase, ImportDescriptor->OriginalFirstThunk, &FOA);
    		// INT
    		pImportProcNameList = (PIMAGE_THUNK_DATA64)((PBYTE)ModuleBase + FOA);
    		Data2.ImportProcName = (DWORD)pImportProcNameList;
    		Data2.FOAImportProcName = FOA;
    
    		while (TRUE)
    		{
    			// 遍历到尽头了
    			if (pImportProcNameList[Index].u1.Function == NULL)
    			{
    				
    				break;
    			}
    			else
    			{
    				if (pImportProcNameList[Index].u1.Function & IMAGE_ORDINAL_FLAG)
    				{
    					// 索引导入
    				}
    				else
    				{
    					GetFOA64((PBYTE)ModuleBase, pImportProcNameList[Index].u1.AddressOfData, &FOA);
    					pINTItem = (PIMAGE_IMPORT_BY_NAME)(FOA + (PBYTE)ModuleBase);
    				}
    
    				// 序号,便于修正地址时查询
    				WORD Hint = pINTItem->Hint;
    				Data.Ordinals = Hint;
    
    				// 名称
    				PCHAR Name = (PCHAR)pINTItem->Name;
    				Data.FunctionName = Name;
    
    				// Dll名称
    				GetFOA64
    
    下一篇:没有了