IAT注入
来源:互联网 发布:无线云台网络摄像机 编辑:程序博客网 时间:2024/06/03 16:29
IAT 注入 的主要思路就是在PE 中增加一个节,然后将导入表拷贝到当前的节中,在导入表后面增加一个新的导入项,并将导入表重定向到当前的表中。
一般情况下,我们的节头到段的真正的开始位置是有一定的空闲区域的。
下图为我们的示例程序SimpleEXE.exe的节头,可以看出来,我们的第一个段的起始文件偏移为0x400
虽然IMAGE_OPTIONAL_HEADER32. SizeOfHeaders 总是与第一个段的大小相同,但是我们知道,其真实大小应该为:sizeof(_IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)*(IMAGE_FILE_HEADER. NumberOfSections+1),其中包括最后一个表示结束的IMPORT_BY_NAME结构。
如果加上pDosHeader->e_lfanew其大小就是第一个段之前的实际数据的大小,如图所示:
我们可以看到,其大小为0x310 有 0x90 字节的数据没有使用。
这样,我们在IAT 中添加一个IMAGE_SECTION_HEADER结构是完全没有问题的。
添加了一个节头结构之后,就是添加一个节的操作了。
定位到最后一个节的结构,查看其结构如下:
因此我们的新节的RawAddress为:0x6E00+0x600 对 0x200 对齐,为:0x7400
虚拟地址为:0x1A000+0x469 对 0x1000 对齐,为:0x1B000
然后我们来看新节保护属性的选择,因为我们新添加的段将来不仅仅会有导入表(可读,包含初始化数据),在我们添加了一个导入DLL 之后还会添加一个导入函数,而该导入函数对应的IAT 需要被修改,因此我们应该添加可写属性,因此其最终的保护属性为可读可写包含初始化的数据-----0xC0000040
有了新节之后,我们考虑节中的数据:
1. 原来的导入表结构
2. 新添加的PIMAGE_IMPORT_DESCRIPTOR结构
3. 新添加的两个IMAGE_THUNK_DATA(分别对应于OriginalFirstThunk和FirstThunk结构)
4. 新添加的两个IMAGE_THUNK_DATA结构末尾的两个为0 的IMAGE_THUNK_DATA结构,用于表示导入表的结束
解决了这些基本问题之后就是具体的编程过程了。
下面是核心代码以及一些核心注释
// 导入表定义
typedef struct _INJECT_STRUCT_
{
IMAGE_THUNK_DATA OriginalThunk;
IMAGE_THUNK_DATA OriginalThunk_ZERO;
IMAGE_THUNK_DATA FirstThunk;
IMAGE_THUNK_DATA FirstThunk_ZERO;
IMAGE_IMPORT_BY_NAME ImportByName;
CHAR szFuncName[16];
CHAR szDllName[MAX_PATH];
}INJECT_STRUCT, *PINJECT_STRUCT;
BOOLModifyPEImportTableInject(ULONG_PTR ulBaseAddress, char* szDllName){PIMAGE_DOS_HEADERpDosHeader = (PIMAGE_DOS_HEADER)ulBaseAddress;PIMAGE_NT_HEADERSpNTHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);PIMAGE_SECTION_HEADERsection = IMAGE_FIRST_SECTION(pNTHeader);PIMAGE_SECTION_HEADERpLastSection = (PIMAGE_SECTION_HEADER)(section + pNTHeader->FileHeader.NumberOfSections - 1);BYTE*pDelta = new BYTE[pNTHeader->OptionalHeader.FileAlignment];// 用于填充0数据memset(pDelta, 0, pNTHeader->OptionalHeader.FileAlignment);DWORD dwWriteSize = 0;DWORD dwReturnSize = 0;DWORD dwRet = 0;PVOID pWriteBuffer = NULL;DWORD dwFileAlignment = pNTHeader->OptionalHeader.FileAlignment;DWORD dwMemAlignment = pNTHeader->OptionalHeader.SectionAlignment;DWORD dwSectionHeaderSize = (pNTHeader->FileHeader.NumberOfSections + 2) * sizeof(IMAGE_SECTION_HEADER);PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0;PIMAGE_SECTION_HEADERpPreImportSectionHeader = (PIMAGE_SECTION_HEADER)RvaToSection(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,pNTHeader);PIMAGE_SECTION_HEADER pSection = 0;PIMAGE_THUNK_DATA pThunk, pThunkIAT = 0;DWORD dwTemp = 0;// 这里仅仅创建新文件HANDLE hTargetFile = CreateFileA("Injected.exe", FILE_ALL_ACCESS,FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hTargetFile == INVALID_HANDLE_VALUE){int a = GetLastError();printf("Create Virus Failed\r\n");return FALSE;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////写入Dos HeaderdwRet = WriteFile(hTargetFile, pDosHeader, sizeof(IMAGE_DOS_HEADER), &dwReturnSize, NULL);if (!dwRet){printf("Write Virus DosHeader Failed\r\n");delete[]pDelta;CloseHandle(hTargetFile);return FALSE;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////写入Dos StubdwWriteSize = pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER);dwRet = WriteFile(hTargetFile, (LPVOID)((DWORD)pDosHeader + sizeof(IMAGE_DOS_HEADER)), dwWriteSize, &dwReturnSize, NULL);if (!dwRet){printf("Write Virus DosStub Failed\r\n");delete[]pDelta;CloseHandle(hTargetFile);return FALSE;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////写入Nt HeaderdwWriteSize = sizeof(IMAGE_NT_HEADERS);pNTHeader->FileHeader.NumberOfSections ++;pNTHeader->OptionalHeader.SizeOfImage += 0x1000;// 增加的一个节的大小为0x1000dwTemp = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = Aligment(pLastSection->VirtualAddress + pLastSection->Misc.VirtualSize, dwMemAlignment);dwRet = WriteFile(hTargetFile, pNTHeader, dwWriteSize, &dwReturnSize, NULL);if (!dwRet){printf("Write Virus NtHeader Failed\r\n");delete[]pDelta;CloseHandle(hTargetFile);return FALSE;}pNTHeader->FileHeader.NumberOfSections --;// 保持后面的逻辑易于理解pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = dwTemp;pNTHeader->OptionalHeader.SizeOfImage -= 0x1000;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 得到导入表所在的节表,以及导入表个数pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress \- pPreImportSectionHeader->VirtualAddress + pPreImportSectionHeader->PointerToRawData + ulBaseAddress);// 取出导入的DLL的个数int nImportDllCount = 0;while (1){if ((pImportDesc->TimeDateStamp == 0) && (pImportDesc->Name == 0))break;pThunk = (PIMAGE_THUNK_DATA)(pImportDesc->Characteristics);pThunkIAT = (PIMAGE_THUNK_DATA)(pImportDesc->FirstThunk);if (pThunk == 0 && pThunkIAT == 0)return -1;nImportDllCount++;pImportDesc++;}// 恢复pImportDesc的值,方便下面的复制当前导入表的操作.pImportDesc -= nImportDllCount;// 原来的导入表,加上一个新结构体和一个0结束结构体。就是要写入文件的导入表的大小DWORD dwIATDESCSize = (nImportDllCount + 2) * sizeof(IMAGE_IMPORT_DESCRIPTOR);/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 复制旧的数据,并填充新添加的节的数据,将所有的节表头写入文件PIMAGE_SECTION_HEADER pUpdatedSection = (PIMAGE_SECTION_HEADER)new char[dwSectionHeaderSize];memset(pUpdatedSection, 0, dwSectionHeaderSize);CopyMemory(pUpdatedSection, section, sizeof(IMAGE_SECTION_HEADER)*pNTHeader->FileHeader.NumberOfSections);// 定位新节头的位置PIMAGE_SECTION_HEADER pNewSection = pUpdatedSection + pNTHeader->FileHeader.NumberOfSections;// 初始化为0,包括后面的那个为空的节头结构memset(pNewSection, 0, 2 * sizeof(IMAGE_SECTION_HEADER));char szNewSectionName[] = ".NewSec";StringCchCopyA((char*)(pNewSection->Name), 12, szNewSectionName);pNewSection->PointerToRelocations = 0;pNewSection->PointerToLinenumbers = 0;pNewSection->NumberOfRelocations = 0;pNewSection->NumberOfLinenumbers = 0;// 读写包含初始化数据pNewSection->Characteristics = 0xC0000040;// RVA 计算 内存粒度对齐pNewSection->VirtualAddress = Aligment(pLastSection->VirtualAddress + pLastSection->Misc.VirtualSize, dwMemAlignment);// RAW 计算 文件粒度对齐pNewSection->PointerToRawData = Aligment(pLastSection->PointerToRawData + pLastSection->SizeOfRawData, dwFileAlignment);// 下面的操作为写新节头表以及填充节表到第一个段的空白区域DWORD dwMiniPointer = 0;DWORD dwSizeDelta = 0;BOOL bNeedModify = FALSE;for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++){if (pUpdatedSection[i].Name){if (0 == dwMiniPointer)dwMiniPointer = (DWORD)(pUpdatedSection[i].PointerToRawData);if ((pUpdatedSection[i].PointerToRawData) < dwMiniPointer)dwMiniPointer = (DWORD)pUpdatedSection[i].PointerToRawData;}}DWORD dwTmp = (pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS) + dwSectionHeaderSize);// 写入文件后,没有超过第一个段的开始if (dwMiniPointer >= dwTmp){dwSizeDelta = dwMiniPointer - dwTmp;}// 超过了else{// 因为dwSizeDelta为需要填充的零的字节数,如果刚好与文件对齐粒度对齐,不需要填充dwSizeDelta = dwTmp % (pNTHeader->OptionalHeader.FileAlignment);if (dwSizeDelta != 0)dwSizeDelta = pNTHeader->OptionalHeader.FileAlignment - dwSizeDelta;else dwSizeDelta = 0;// 指示每个节表的文件偏移需要重新计算bNeedModify = TRUE;}dwMiniPointer = dwTmp;dwMiniPointer += dwSizeDelta;if (bNeedModify){for (int i = 1; i < (UINT)(pNTHeader->FileHeader.NumberOfSections+1); i++){if (1 != i){pUpdatedSection[i].PointerToRawData =pUpdatedSection[i - 1].PointerToRawData +pUpdatedSection[i - 1].SizeOfRawData;}else{pUpdatedSection[i].PointerToRawData = dwMiniPointer;}}}// 实际数据大小pNewSection->Misc.VirtualSize = sizeof(INJECT_STRUCT) + dwIATDESCSize;// 实际数据大小 文件粒度对齐pNewSection->SizeOfRawData = Aligment(sizeof(INJECT_STRUCT) + dwIATDESCSize,dwFileAlignment);// 写入新节表 (旧的+新的+{0}结构结尾)WriteFile(hTargetFile, pUpdatedSection, dwSectionHeaderSize, &dwReturnSize, NULL);// 写入空白数据 (满足文件粒度)WriteFile(hTargetFile, pDelta, dwSizeDelta, &dwReturnSize, NULL);////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////写入每个节的内容for (int i = 0; i < (UINT)(pNTHeader->FileHeader.NumberOfSections); i++){//SizeOfRawData 文件是按照这个值对齐的 VirtualSize反而是真实大小。这个一定要理解//就算是内存映射PE之后,整个节的大小也是SizeOfRawData,但是实际有数据的大小是VirtualSize。此处不理解一定要停。WriteFile(hTargetFile, (LPVOID)(ulBaseAddress + section[i].PointerToRawData), section[i].SizeOfRawData, &dwReturnSize, NULL);}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 写入最后一个节的内容PIMAGE_IMPORT_DESCRIPTOR pImportDescVector =(PIMAGE_IMPORT_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwIATDESCSize);if (pImportDescVector == NULL){printf("HeapAlloc() failed. --err: %d/n", GetLastError());return -1;}memset(pImportDescVector, 0, dwIATDESCSize);CopyMemory(pImportDescVector + 1, pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR) * (nImportDllCount + 1));// 新导入的DLL 的顺序比较靠前// OriginalThunk {0}// FirstThunk {0}INJECT_STRUCT iatTableContent = {0};StringCchCopyA(iatTableContent.szDllName, MAX_PATH, szDllName);StringCchCopyA((char*)(iatTableContent.ImportByName.Name), 64, "HelloShine");//Dll中写一个按名称导出的导出函数,如果没有导出函数,检验应该是会出错的。iatTableContent.ImportByName.Hint = 0;pImportDescVector->FirstThunk = (LONG_PTR)pNewSection->VirtualAddress + dwIATDESCSize + offsetof(INJECT_STRUCT, FirstThunk);pImportDescVector->OriginalFirstThunk = (LONG_PTR)pNewSection->VirtualAddress + dwIATDESCSize + offsetof(INJECT_STRUCT, OriginalThunk);pImportDescVector->Name = (LONG_PTR)pNewSection->VirtualAddress + dwIATDESCSize + offsetof(INJECT_STRUCT, szDllName);pImportDescVector->TimeDateStamp = 0;// 没有绑定pImportDescVector->ForwarderChain = -1;// 没有转发iatTableContent.FirstThunk.u1.Function = (LONG_PTR)pNewSection->VirtualAddress + dwIATDESCSize + offsetof(INJECT_STRUCT, ImportByName);iatTableContent.OriginalThunk.u1.AddressOfData = (LONG_PTR)pNewSection->VirtualAddress + dwIATDESCSize + offsetof(INJECT_STRUCT, ImportByName);// 在新节上写入新的导入表内容DWORD dwRetSize = 0;WriteFile(hTargetFile, pImportDescVector, dwIATDESCSize, &dwRetSize, NULL);WriteFile(hTargetFile, &iatTableContent, sizeof(INJECT_STRUCT), &dwRetSize, NULL);// 填充文件最后的字节,满足文件粒度dwSizeDelta = Aligment(dwIATDESCSize + sizeof(INJECT_STRUCT), dwFileAlignment) - dwIATDESCSize + sizeof(INJECT_STRUCT);WriteFile(hTargetFile, pDelta, dwSizeDelta, NULL, NULL);///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 修正SizeOfHeadersDWORD dwBuffer = dwMiniPointer;// PE头大小重造,即段起始地址的最小值DWORD lDistanceToMove = (ULONG_PTR)(&(pNTHeader->OptionalHeader.SizeOfHeaders)) - ulBaseAddress;SetFilePointer(hTargetFile, lDistanceToMove, NULL, FILE_BEGIN);WriteFile(hTargetFile, (PVOID)&dwBuffer, 4, NULL, NULL);//释放内存,完成操作,别忘了之前的文件映射都还没释放。HeapFree(GetProcessHeap(), 0, pImportDescVector);delete []pDelta;CloseHandle(hTargetFile);return TRUE;}
- IAT注入
- IAT HOOK 代码注入非DLL
- IAT HOOK 代码注入非DLL
- R3下远程线程注入/IAT Hook
- IAT
- IAT
- Win32汇编-实现注入进程进行IAT HOOK
- 使用IAT表注入模块到进程中 样例
- 内存注入之IAT Hook和Inline Hook综合程序
- 使用IAT表注入模块到进程中 样例
- 《逆向工程核心原理》<04-32> 通过DLL注入实现IAT钩取的技术
- 定位IAT
- IAT HOOK
- IAT HOOK
- HOOK IAT
- IAT hooking
- IAT HOOK
- IAT HOOK
- 计算机操作系统-进程篇
- 日志记录的作用和方法
- Activity启动模式
- <jsp:include>跟<%@include%>的区别
- easyUI的combobox选中无法显示
- IAT注入
- Zurmo开发的小技巧(2)
- vue+webpack构建项目过程
- proguard
- 图的综合问题
- 运动目标检测视频Dataset
- 更改CentOS7 默认网卡eno16777736为eth0
- Vim复制代码段
- 12. Integer to Roman