日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

解析导入表和IAT表

發(fā)布時(shí)間:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解析导入表和IAT表 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、導(dǎo)入表的結(jié)構(gòu)

導(dǎo)入表的結(jié)構(gòu)看起來(lái)復(fù)雜,其實(shí)只是套娃,不要被它嚇到了。
導(dǎo)入表的定義如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {union {DWORD Characteristics; // 0 for terminating null import descriptorDWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)};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 forwardersDWORD Name;DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) } IMAGE_IMPORT_DESCRIPTOR;

其中比較重要的是 OriginalFirstThunk, Name 和 FirstThunk。
OriginalFirstThunk 是指向INT表的RVA,FirstThunk 是指向IAT表的RVA,Name是DLL的文件名。
INT表和IAT表在文件中是完全一樣的(前提是沒(méi)有綁定導(dǎo)入)。
INT表的結(jié)構(gòu)是這樣的:

IMAGE_THUNK_DATA 是一個(gè)4字節(jié)的數(shù)據(jù),如果最高位是1,那么低31位就是函數(shù)的導(dǎo)出序號(hào);如果最高位是0,那么它的值是一個(gè)RVA,指向一個(gè) IMAGE_IMPORT_BY_NAME 結(jié)構(gòu)。

typedef struct _IMAGE_IMPORT_BY_NAME {WORD Hint;BYTE Name[1]; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

其中低地址的Hint是導(dǎo)出序號(hào),然而這個(gè)值可能并不準(zhǔn)確,有些編譯器會(huì)把它設(shè)置成0,我們只需要關(guān)注 Name,這個(gè)是一個(gè)以0結(jié)尾的字符串,表示函數(shù)名。

如果沒(méi)有提前綁定函數(shù)地址,IAT表和INT表在文件中存儲(chǔ)的數(shù)據(jù)是完全一樣的。

二、導(dǎo)入表和IAT表的作用

EXE和DLL要使用其他DLL的函數(shù),需要說(shuō)明用到了哪些函數(shù),導(dǎo)入表就是存儲(chǔ)這些外部函數(shù)的函數(shù)名或?qū)С鲂蛱?hào)的結(jié)構(gòu)。使用了多少個(gè)DLL,就有多少個(gè)導(dǎo)入表。

IAT表可以認(rèn)為是導(dǎo)入表的“子表”,因?yàn)閷?dǎo)入表里的 FirstThunk 屬性就是IAT表的RVA。EXE如果調(diào)用了DLL的函數(shù),CALL 指令后面跟的地址其實(shí)是指向IAT表里的某個(gè)位置,運(yùn)行之前在文件中的時(shí)候,IAT表和INT表一樣,里面存儲(chǔ)的要么是函數(shù)名,要么是導(dǎo)出序號(hào)。加載的時(shí)候操作系統(tǒng)會(huì)把IAT表里的值修改成函數(shù)真正在DLL中的地址,具體步驟是:
操作系統(tǒng)首先將exe和所有dll加載到4GB虛擬內(nèi)存中,然后遍歷導(dǎo)入表,根據(jù)DLL名字調(diào)用LoadLibrary獲取模塊句柄HMODULE,然后調(diào)用GetProcAddress獲取函數(shù)地址,然后將函數(shù)地址寫(xiě)入到IAT表里。

三、解析導(dǎo)入表

編程打印導(dǎo)入表里的數(shù)據(jù),包括DLL文件名,INT表和IAT表的數(shù)據(jù)。

// 打印導(dǎo)入表 VOID PrintImportTable(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);PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[1].VirtualAddress));// 嚴(yán)格來(lái)說(shuō)應(yīng)該是 sizeof(IMAGE_IMPORT_DESCRIPTOR) 個(gè)字節(jié)為0表示結(jié)束while (pImportTable->OriginalFirstThunk || pImportTable->FirstThunk){// 打印模塊名printf("%s\n", (LPCSTR)(RvaToFoa(pFileBuffer, pImportTable->Name) + (DWORD)pFileBuffer));// 遍歷INT表(import name table)printf("--------------OriginalFirstThunkRVA:%x--------------\n", pImportTable->OriginalFirstThunk); PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pImportTable->OriginalFirstThunk));while (*((PDWORD)pThunkData) != 0){// IMAGE_THUNK_DATA32 是一個(gè)4字節(jié)數(shù)據(jù)// 如果最高位是1,那么除去最高位就是導(dǎo)出序號(hào)// 如果最高位是0,那么這個(gè)值是RVA 指向 IMAGE_IMPORT_BY_NAMEif ((*((PDWORD)pThunkData) & 0x80000000) == 0x80000000){printf("按序號(hào)導(dǎo)入 Ordinal:%04x\n", (*((PDWORD)pThunkData) & 0x7FFFFFFF));}else{PIMAGE_IMPORT_BY_NAME pIBN = (PIMAGE_IMPORT_BY_NAME)(RvaToFoa(pFileBuffer, *((PDWORD)pThunkData)) + \(DWORD)pFileBuffer);printf("按名字導(dǎo)入 Hint:%04x Name:%s\n", pIBN->Hint, pIBN->Name);}pThunkData++;}// 遍歷IAT表(import address table)printf("--------------FirstThunkRVA:%x--------------\n", pImportTable->FirstThunk); pThunkData = (PIMAGE_THUNK_DATA32)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pImportTable->FirstThunk));while (*((PDWORD)pThunkData) != 0){// IMAGE_THUNK_DATA32 是一個(gè)4字節(jié)數(shù)據(jù)// 如果最高位是1,那么除去最高位就是導(dǎo)出序號(hào)// 如果最高位是0,那么這個(gè)值是RVA 指向 IMAGE_IMPORT_BY_NAMEif ((*((PDWORD)pThunkData) & 0x80000000) == 0x80000000){printf("按序號(hào)導(dǎo)入 Ordinal:%04x\n", (*((PDWORD)pThunkData) & 0x7FFFFFFF));}else{PIMAGE_IMPORT_BY_NAME pIBN = (PIMAGE_IMPORT_BY_NAME)(RvaToFoa(pFileBuffer, *((PDWORD)pThunkData)) + \(DWORD)pFileBuffer);printf("按名字導(dǎo)入 Hint:%04x Name:%s\n", pIBN->Hint, pIBN->Name);}pThunkData++;}pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportTable + sizeof(IMAGE_IMPORT_DESCRIPTOR));} }

運(yùn)行結(jié)果:
打印ipmsg.exe的運(yùn)行結(jié)果

打印notepad.exe的結(jié)果

可以發(fā)現(xiàn)notepad在文件中IAT表和INT表是不一樣的,它已經(jīng)提前將DLL中的函數(shù)地址寫(xiě)死進(jìn)去了。這個(gè)是綁定導(dǎo)入。

四、完整代碼

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

總結(jié)

以上是生活随笔為你收集整理的解析导入表和IAT表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。