解析绑定导入表
一、綁定導(dǎo)入表的作用
有些windows程序,如notepad,為了提高加載速度,會(huì)直接把DLL中的函數(shù)地址寫入到IAT表,省去了加載時(shí)的計(jì)算。但是這樣會(huì)有兩個(gè)問題,第一,當(dāng)DLL沒有占住ImageBase時(shí),IAT中的地址就是錯(cuò)的;第二,當(dāng)鏈接的DLL被修改了,那IAT里寫的地址也是錯(cuò)的。遇到這兩種情形之一,加載時(shí)就必須修復(fù)IAT了。
對(duì)于第二種情形,DLL是否被修改,是根據(jù)比較DLL的時(shí)間戳和綁定導(dǎo)入表中的記錄的DLL時(shí)間戳來判斷的,如果不一致,說明DLL被修改了。
加載程序時(shí),操作系統(tǒng)根據(jù)導(dǎo)入表中的時(shí)間戳來判斷程序是否使用了綁定導(dǎo)入。當(dāng)時(shí)間戳為0,表示不使用綁定導(dǎo)入表;當(dāng)時(shí)間戳為0xFFFFFFFF,說明該程序使用綁定導(dǎo)入。
對(duì)于使用綁定導(dǎo)入的程序,綁定導(dǎo)入表存儲(chǔ)在最后一個(gè)節(jié)表后面,如圖示:
二、綁定導(dǎo)入表的結(jié)構(gòu)
綁定導(dǎo)入表結(jié)構(gòu):
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 是時(shí)間戳,用于和DLL中的時(shí)間戳比較,判斷DLL是否已經(jīng)發(fā)生變化;
OffsetModuleName 是當(dāng)前模塊名距離第一個(gè) _IMAGE_BOUND_IMPORT_DESCRIPTOR 的偏移。
NumberOfModuleForwarderRefs 是該模塊依賴的模塊數(shù)量;
依賴模塊結(jié)構(gòu):
typedef struct _IMAGE_BOUND_FORWARDER_REF {DWORD TimeDateStamp;WORD OffsetModuleName;WORD Reserved; } IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;除了第三個(gè)屬性保留,其他與 _IMAGE_BOUND_IMPORT_DESCRIPTOR 相同。
三、打印綁定導(dǎo)入表
// 打印綁定導(dǎo)入表 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("該程序綁定導(dǎo)入表為空\(chéng)n");return;}*/// 判斷方式二PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[1].VirtualAddress));if (pImportTable->TimeDateStamp == 0){printf("該程序沒有綁定導(dǎo)入\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){// 打印時(shí)間戳、模塊名、依賴模塊數(shù)量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的綁定導(dǎo)入表運(yùn)行結(jié)果
四、完整代碼
https://blog.csdn.net/Kwansy/article/details/106234264
總結(jié)
- 上一篇: 解析导入表和IAT表
- 下一篇: 导入表注入原理和C语言实现