解析綁定導入表

一、綁定導入表的作用

有些windows程序,如notepad,爲了提高加載速度,會直接把DLL中的函數地址寫入到IAT表,省去了加載時的計算。但是這樣會有兩個問題,第一,當DLL沒有佔住ImageBase時,IAT中的地址就是錯的;第二,當鏈接的DLL被修改了,那IAT裏寫的地址也是錯的。遇到這兩種情形之一,加載時就必須修復IAT了。

對於第二種情形,DLL是否被修改,是根據比較DLL的時間戳和綁定導入表中的記錄的DLL時間戳來判斷的,如果不一致,說明DLL被修改了。

加載程序時,操作系統根據導入表中的時間戳來判斷程序是否使用了綁定導入。當時間戳爲0,表示不使用綁定導入表;當時間戳爲0xFFFFFFFF,說明該程序使用綁定導入。

對於使用綁定導入的程序,綁定導入表存儲在最後一個節表後面,如圖示:
在這裏插入圖片描述

二、綁定導入表的結構

在這裏插入圖片描述

綁定導入表結構:

typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    NumberOfModuleForwarderRefs;
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

TimeDateStamp 是時間戳,用於和DLL中的時間戳比較,判斷DLL是否已經發生變化;
OffsetModuleName 是當前模塊名距離第一個 _IMAGE_BOUND_IMPORT_DESCRIPTOR 的偏移。
NumberOfModuleForwarderRefs 是該模塊依賴的模塊數量;

依賴模塊結構:

typedef struct _IMAGE_BOUND_FORWARDER_REF {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    Reserved;
} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;

除了第三個屬性保留,其他與 _IMAGE_BOUND_IMPORT_DESCRIPTOR 相同。

三、打印綁定導入表

// 打印綁定導入表
VOID PrintBoundImportTable(LPVOID pFileBuffer)
{
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
	PIMAGE_SECTION_HEADER pSectionHeader = \
		(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

	// 判斷方式一
	/*if (NULL == pOptionHeader->DataDirectory[11].VirtualAddress)
	{
		printf("該程序綁定導入表爲空\n");
		return;
	}*/

	// 判斷方式二
	PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + \
		RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[1].VirtualAddress));
	if (pImportTable->TimeDateStamp == 0)
	{
		printf("該程序沒有綁定導入\n");
		return;
	}
	
	PIMAGE_BOUND_IMPORT_DESCRIPTOR pBoundImportTable = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + \
		RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[11].VirtualAddress));
	PIMAGE_BOUND_IMPORT_DESCRIPTOR pFirstBoundImportTable = pBoundImportTable;	
	
	while (pBoundImportTable->TimeDateStamp || pBoundImportTable->OffsetModuleName || pBoundImportTable->NumberOfModuleForwarderRefs)
	{
		// 打印時間戳、模塊名、依賴模塊數量
		puts("-------------------------------------------");
		printf("%s\n", (LPCSTR) ((DWORD)pFirstBoundImportTable + pBoundImportTable->OffsetModuleName));
		printf("TimeDateStamp:%x\n", pBoundImportTable->TimeDateStamp);		
		printf("NumberOfModuleForwarderRefs:%d\n", pBoundImportTable->NumberOfModuleForwarderRefs);
		// 遍歷依賴模塊
		PIMAGE_BOUND_FORWARDER_REF pBFR = (PIMAGE_BOUND_FORWARDER_REF)((DWORD)pBoundImportTable + \
			sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR));
		for (int i = 0; i < pBoundImportTable->NumberOfModuleForwarderRefs; i++)
		{
			printf("\t%s\n", (LPCSTR)((DWORD)pFirstBoundImportTable + pBFR[i].OffsetModuleName));
			printf("\tTimeDateStamp:%x\n", pBFR[i].TimeDateStamp);
		}
		pBoundImportTable = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((DWORD)pBoundImportTable + \
			sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR) + \
			pBoundImportTable->NumberOfModuleForwarderRefs * sizeof(IMAGE_BOUND_FORWARDER_REF));
	}

}

打印notepad的綁定導入表運行結果
在這裏插入圖片描述

四、完整代碼

https://blog.csdn.net/Kwansy/article/details/106234264

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章