PE 移动导出表
移动各种表的原因:
实现代码如下:
void MoveExportTable(PVOID pFileBuffer,PDWORD OldBufferSize,PVOID* pNewBuffer){ PIMAGE_DOS_HEADER pImageDosHeader = NULL; PIMAGE_FILE_HEADER pImageFileHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pImageOptionalHeader = NULL; PIMAGE_SECTION_HEADER pImageSectionHeaderGroup = NULL; PIMAGE_SECTION_HEADER NewSec = NULL; PIMAGE_EXPORT_DIRECTORY EXPORT_TABLE = NULL; PIMAGE_EXPORT_DIRECTORY EXPORT_TABLE_NewBuffer = NULL; PDWORD AddressFunctionName; DWORD RVA = 0; DWORD FOA = 0; PDWORD pTempAddress; int FunNameLen = 0; char FunName[10] = {0}; int i = 0; int j = 0; DWORD all_num = 0; DWORD isOk; DWORD NewLength=0; PVOID LastSection = NULL; PVOID CodeSection = NULL; pImageDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageDosHeader + pImageDosHeader->e_lfanew + 4); pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pImageFileHeader + sizeof(IMAGE_FILE_HEADER)); pImageSectionHeaderGroup = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader + pImageFileHeader->SizeOfOptionalHeader); /* 第一步:新增节 */ //判断是否可以容纳相应的节表 isOk = (DWORD)pImageOptionalHeader->SizeOfHeaders - ((DWORD)pImageDosHeader->e_lfanew + IMAGE_SIZEOF_FILE_HEADER + pImageFileHeader->SizeOfOptionalHeader + 40*pImageFileHeader->NumberOfSections); if(isOk < 80){ printf("空间太小 无法进行添加!"); return; } //申请对应的内存大小的空间 NewLength += *OldBufferSize + 0x1000; *pNewBuffer = (PVOID)malloc(NewLength); ZeroMemory(*pNewBuffer,NewLength); //拷贝之前内存空间 到 当前新生成的内存空间 memcpy(*pNewBuffer,pFileBuffer,*OldBufferSize); //获取新的空间中的PE结构体 pImageDosHeader = (PIMAGE_DOS_HEADER)(*pNewBuffer); pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageDosHeader + pImageDosHeader->e_lfanew + 4); pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pImageFileHeader + sizeof(IMAGE_FILE_HEADER)); pImageSectionHeaderGroup = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader + pImageFileHeader->SizeOfOptionalHeader); // pImageFileHeader->NumberOfSections修改 pImageFileHeader->NumberOfSections = pImageFileHeader->NumberOfSections + 1; // pImageOptionalHeader->SizeOfImage修改 pImageOptionalHeader->SizeOfImage = (DWORD)pImageOptionalHeader->SizeOfImage + 0x1000; // 复制代码段的节数据到 当前最后一个节数据后面 CodeSection = (PVOID)(&pImageSectionHeaderGroup[0]); LastSection = (PVOID)(DWORD)(&pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-1]); memcpy(LastSection,CodeSection,40); //修正相关属性 NewSec = (PIMAGE_SECTION_HEADER)LastSection; strcpy(NewSec,".NewSec"); NewSec->Misc.VirtualSize = 0x1000; NewSec->SizeOfRawData = 0x1000; NewSec->VirtualAddress = pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].VirtualAddress + pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].SizeOfRawData; NewSec->PointerToRawData = pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].PointerToRawData + pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].SizeOfRawData; //修改大小长度 *OldBufferSize = NewLength; //获取导出表的地址 RVA_TO_FOA(*pNewBuffer,pImageOptionalHeader->DataDirectory[0].VirtualAddress,&FOA); EXPORT_TABLE = (PIMAGE_EXPORT_DIRECTORY)((DWORD)*pNewBuffer + (DWORD)FOA); /* 第二步:复制AddressOfFunctions 长度:NumberOfFunctions*4 */ printf("AddressOfFunctions个数: %d 每个占4字节\n", EXPORT_TABLE->NumberOfFunctions); RVA_TO_FOA(*pNewBuffer,EXPORT_TABLE->AddressOfFunctions,&FOA); memcpy((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData, (PVOID)((DWORD)*pNewBuffer + FOA), ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4); /* 第三步:复制AddressOfNameOrdinals 长度:NumberOfNames*2 */ printf("AddressOfNameOrdinals个数: %d 每个占2字节\n", EXPORT_TABLE->NumberOfNames); RVA_TO_FOA(*pNewBuffer, EXPORT_TABLE->AddressOfNameOrdinals,&FOA); memcpy((PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4), (PVOID)((DWORD)*pNewBuffer + FOA), ((DWORD)EXPORT_TABLE->NumberOfNames)*2); /* 第四步:复制AddressOfNames 长度:NumberOfNames*4 */ printf("AddressOfNames个数: %d 每个占4字节\n", EXPORT_TABLE->NumberOfNames); RVA_TO_FOA(*pNewBuffer, EXPORT_TABLE->AddressOfNames,&FOA); memcpy((PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2), (PVOID)((DWORD)*pNewBuffer + FOA), (DWORD)EXPORT_TABLE->NumberOfNames*4); /* 第五步:复制所有的函数名 长度不确定,复制时直接修复AddressOfNames */ for(j=0;j<EXPORT_TABLE->NumberOfNames;j++){ //获得函数名称表的RVA,将其转换为FOA printf("%x\n", EXPORT_TABLE->AddressOfNames); RVA_TO_FOA(*pNewBuffer, EXPORT_TABLE->AddressOfNames,&FOA); // 每个函数的RVA转换为FOA RVA_TO_FOA(*pNewBuffer, *(PDWORD)((DWORD)*pNewBuffer + (DWORD)FOA), &FOA); //获取当前函数名称的偏移地址,将当前的函数名称的偏移地址 + pNewBuffer 得到对应的内存地址 AddressFunctionName = (PDWORD)(*(PDWORD)((DWORD)*pNewBuffer + (DWORD)FOA + (DWORD)all_num)); printf("%d\n",all_num); //printf("%x",AddressFunctionName); //通过strcpy来获取当前地址保存的函数名称 strcpy(FunName,&AddressFunctionName); //printf("%s",FunName); //得到当前函数名称的长度 FunNameLen = strlen(FunName) + 1; //最后结尾需要+1,原因\0 空字节 //拿到函数的长度和名称之后需要进行复制 memcpy((PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num) //这里到时候加循环来进行偏移复制 ,((PVOID)&AddressFunctionName) ,FunNameLen); //接下来需要进行修复 //过程:每次复制完 还需要修复下之前刚复制AddressOfNames中的对应的地址 让它里面的值 保存为当前复制的函数地址 //通过all_num来进行偏移 从而获得当前的地址是指向第j个函数的地址 pTempAddress = (PDWORD)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + (DWORD)all_num); //上面获得的地址是VA 还需要减去pNewBuffer变成FOA 然后再转换为RVA 最后存储到新复制的函数名称表对应的地址当中 FOA_TO_RVA(*pNewBuffer ,((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num) -(DWORD)*pNewBuffer ,&RVA); printf("%d\n", ((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num) -(DWORD)*pNewBuffer); //修改当前pTempAddress指向的地址中的值,修改为之前每个函数名称的的地址 *pTempAddress = RVA; // all_num用来保存复制函数名称的时候一共用了多少个字节 all_num += FunNameLen; } /* 第六步:复制IMAGE_EXPORT_DIRECTORY结构 */ memcpy((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num ,EXPORT_TABLE ,40 ); /* 第七步:修复IMAGE_EXPORT_DIRECTORY结构中的 AddressOfFunctions AddressOfNameOrdinals AddressOfNames */ EXPORT_TABLE_NewBuffer = (PIMAGE_EXPORT_DIRECTORY)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num); //将新的缓冲区中的三个表中存储的地址都进行修改为上面移动好的位置 FOA_TO_RVA(*pNewBuffer,(DWORD)NewSec->PointerToRawData,&RVA); EXPORT_TABLE_NewBuffer->AddressOfFunctions = RVA; FOA_TO_RVA(*pNewBuffer,(DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4,&RVA); EXPORT_TABLE_NewBuffer->AddressOfNameOrdinals = RVA; FOA_TO_RVA(*pNewBuffer,(DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2,&RVA); EXPORT_TABLE_NewBuffer->AddressOfNames = RVA; /* 第八步:修复目录项中的值,指向新的IMAGE_EXPORT_DIRECTORY */ FOA_TO_RVA(*pNewBuffer,(DWORD)EXPORT_TABLE_NewBuffer - (DWORD)*pNewBuffer,&RVA); pImageOptionalHeader->DataDirectory[0].VirtualAddress = RVA; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY