导入表注入原理和C语言实现
一、導(dǎo)入表注入的原理
注入是把DLL加載到另一個(gè)進(jìn)程的4GB地址空間中,實(shí)現(xiàn)方式有很多種,導(dǎo)入表注入是我學(xué)的第一種注入,是通過(guò)修改程序的導(dǎo)入表,把自己的DLL添加到導(dǎo)入表中,來(lái)實(shí)現(xiàn)這個(gè)目的。
導(dǎo)入表是連續(xù)存儲(chǔ)在節(jié)里的,它后面還有其他數(shù)據(jù),不能直接追加一個(gè)導(dǎo)入表,所以必須找一塊足夠大的內(nèi)存,把原來(lái)的所有導(dǎo)入表移動(dòng)過(guò)去,再追加我們DLL的導(dǎo)入表。新增節(jié)是比較簡(jiǎn)單的做法,我的代碼中也采用新增節(jié)。
導(dǎo)入表注入是讓系統(tǒng)根據(jù)EXE的導(dǎo)入表,幫我們實(shí)現(xiàn)加載DLL,需要知道一點(diǎn),DLL至少要有一個(gè)導(dǎo)出函數(shù),系統(tǒng)才會(huì)幫我們加載DLL。
新增節(jié)存儲(chǔ)如下數(shù)據(jù)(順序隨意安排):
原來(lái)的所有導(dǎo)出表 IMAGE_IMPORT_DESCRIPTOR
新增DLL的導(dǎo)出表 IMAGE_IMPORT_DESCRIPTOR
導(dǎo)出表結(jié)束標(biāo)記,sizeof(IMAGE_IMPORT_DESCRIPTOR) 個(gè)0
INT表
INT表結(jié)束標(biāo)記
IMPORT_BY_NAME 結(jié)構(gòu),包括Hint和導(dǎo)出函數(shù)名所占的字節(jié)數(shù)
IAT表
IAT表結(jié)束標(biāo)記
模塊名
這些數(shù)據(jù)都寫(xiě)入到內(nèi)存中后,根據(jù)他們的地址,給其中某些結(jié)構(gòu)的屬性賦值
導(dǎo)入表中的FirstThunk,OriginalFirstThunk分別存儲(chǔ)INT,IAT的RVA;
導(dǎo)入表的Name存儲(chǔ)模塊名的RVA;
INT,IAT的值是IMPORT_BY_NAME的RVA;
除此之外,完成了所有結(jié)構(gòu)的屬性設(shè)置后,不要忘了修改數(shù)據(jù)目錄項(xiàng),讓導(dǎo)入表指向新增節(jié)首字節(jié)。
二、注入代碼和運(yùn)行結(jié)果
// 導(dǎo)入表注入demo,通過(guò)修改導(dǎo)入表,將 InjectDll.dll 添加到導(dǎo)入表 // DLL只有一個(gè)導(dǎo)出函數(shù) ExportFunction,保證至少有一個(gè)導(dǎo)出函數(shù)DLL才會(huì)被加載 // DLL的主函數(shù)在加載和分離時(shí)會(huì)彈窗 DWORD ImportTableInjectDemo(LPVOID pFileBuffer, LPVOID *pNewFileBuffer, DWORD dwFileSize) {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));// 計(jì)算新增節(jié)的大小// 新增節(jié)存儲(chǔ)的內(nèi)容有:原來(lái)的所有導(dǎo)入表,新導(dǎo)入表,新INT, IAT, 模塊名,一個(gè)_IMAGE_IMPORT_BY_NAME// 上述容器按0為結(jié)束標(biāo)記的,也要包含結(jié)束標(biāo)記DWORD dwNewSectionSize = 0;DWORD dwNumberOfDll = 0;while (pImportTable->OriginalFirstThunk || pImportTable->FirstThunk){//printf("%s\n", (LPCSTR)(RvaToFoa(pFileBuffer, pImportTable->Name) + (DWORD)pFileBuffer));dwNumberOfDll++;pImportTable++;}dwNewSectionSize += (dwNumberOfDll + 2) * sizeof(IMAGE_IMPORT_DESCRIPTOR); // 原有的和新添加的導(dǎo)入表,以及結(jié)束標(biāo)記dwNewSectionSize += 16; // 這里包括一個(gè)INT,一個(gè)IAT和兩個(gè)結(jié)束標(biāo)記dwNewSectionSize += strlen("InjectDll.dll") + 1; // 模塊名dwNewSectionSize += 2 + strlen("ExportFunction") + 1; // _IMAGE_IMPORT_BY_NAME,包括Hint和函數(shù)名DWORD dwNewFileSize = AddCodeSection(pFileBuffer, pNewFileBuffer, dwFileSize, dwNewSectionSize);pDosHeader = (PIMAGE_DOS_HEADER)*pNewFileBuffer;pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)*pNewFileBuffer + \RvaToFoa(*pNewFileBuffer, pOptionHeader->DataDirectory[1].VirtualAddress));// 設(shè)置新增節(jié)屬性pSectionHeader[pPEHeader->NumberOfSections - 1].Characteristics = 0xC0000040; // 可讀寫(xiě),含已初始化數(shù)據(jù)// 定義指針指向新增節(jié)首字節(jié)LPVOID pNewSec = (LPVOID)((DWORD)*pNewFileBuffer + pSectionHeader[pPEHeader->NumberOfSections - 1].PointerToRawData);LPVOID pInsert = pNewSec; // 復(fù)制原有的導(dǎo)入表memcpy(pInsert, pImportTable, dwNumberOfDll * sizeof(IMAGE_IMPORT_DESCRIPTOR)); // 設(shè)置新導(dǎo)入表的時(shí)間戳,ForwarderChainpImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pInsert + dwNumberOfDll * sizeof(IMAGE_IMPORT_DESCRIPTOR)); pImportTable->TimeDateStamp = 0; // 表示不使用綁定導(dǎo)入pImportTable->ForwarderChain = -1;// 設(shè)置導(dǎo)入表結(jié)束標(biāo)記pInsert = (LPVOID)((DWORD)pImportTable + sizeof(IMAGE_IMPORT_DESCRIPTOR)); // 指向結(jié)束標(biāo)記memset(pInsert, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));// 指定INT表插入點(diǎn)pInsert = (LPVOID)((DWORD)pInsert + sizeof(IMAGE_IMPORT_DESCRIPTOR)); // 現(xiàn)在指向INT表PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)pInsert; // 定義指向INT表的指針// 設(shè)置INT結(jié)束標(biāo)志memset(pINT + 1, 0, sizeof(IMAGE_THUNK_DATA));// 設(shè)置 IMPORT_BY_NAME,INT表和IAT表共同指向這塊內(nèi)存PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pINT + 8); // IMPORT_BY_NAME插入點(diǎn)pImportByName->Hint = 0; // 設(shè)置沒(méi)有用的導(dǎo)出序號(hào)strcpy((char*)(pImportByName->Name), "ExportFunction"); // 設(shè)置函數(shù)名// INT表的值是 IMPORT_BY_NAME 的RVA*((PDWORD)pINT) = FoaToRva(*pNewFileBuffer, (DWORD)pImportByName - (DWORD)*pNewFileBuffer); // 設(shè)置INT的值// 設(shè)置IAT表pInsert = (LPVOID)((DWORD)pImportByName + 2 + strlen("ExportFunction") + 1); // 指向IAT表 PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)pInsert; // IAT插入點(diǎn)memcpy(pIAT, pINT, 8);// 分配模塊名的內(nèi)存,并完成導(dǎo)入表剩余屬性的賦值pInsert = (LPVOID)((DWORD)pInsert + 8); strcpy((char *)pInsert, "InjectDll.dll");// 設(shè)置導(dǎo)入表屬性pImportTable->FirstThunk = FoaToRva(*pNewFileBuffer, (DWORD)pINT - (DWORD)*pNewFileBuffer);pImportTable->OriginalFirstThunk = FoaToRva(*pNewFileBuffer, (DWORD)pIAT - (DWORD)*pNewFileBuffer);pImportTable->Name = FoaToRva(*pNewFileBuffer, (DWORD)pInsert - (DWORD)*pNewFileBuffer);// 更新目錄項(xiàng)中導(dǎo)入表的位置pOptionHeader->DataDirectory[1].VirtualAddress = FoaToRva(*pNewFileBuffer, ((DWORD)pNewSec - (DWORD)*pNewFileBuffer));return dwNewFileSize; }給ipmsg注入dll,雙擊運(yùn)行exe,先彈出對(duì)話框
然后才運(yùn)行程序
程序退出時(shí),再次彈出對(duì)話框
三、DLL的代碼
這是DLL的主函數(shù),加載時(shí)彈一次窗,分離時(shí)也彈一次窗。
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:Init();break;case DLL_PROCESS_DETACH:Destroy();break;}return TRUE; }四、完整代碼
至此,PE模塊的課程已經(jīng)結(jié)束,有很多PE的知識(shí)還沒(méi)涉及到,這些要在以后學(xué)習(xí)了相關(guān)知識(shí)后再了解。
PE所有課后作業(yè)的核心代碼都在這了!
https://blog.csdn.net/Kwansy/article/details/106234264
總結(jié)
以上是生活随笔為你收集整理的导入表注入原理和C语言实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 解析绑定导入表
- 下一篇: 使用资源文件绘制Win32对话框