在PE中,新增节,添加代码
在PE中,新增节,添加代码
一、先判断节表后是否有空闲位置,添加节表信息,必须多出两个节表位置,最后以零结尾。
二、新增节后,需要修改以下信息
1、添加一个新节,可以复制一份,最好是拥有可执行属性的节,如.text。
2、在节表区,新增节的后面,填充一个节,用零填充。
3、修改标准PE头中节的数量。
4、修改SizeOfImage的大小。
5、在原有数据的后面,新增一个节的数据(内存对齐的整倍数)。
6、修正新增节表的属性。
三、新节各个属性修改说明
1、Name:名字随便修改,不能超过八个字节。
2、VirtualSize:申请的新节空间大小,比如1000
3、VirtualAddress:等于上一个节的VirtualAddress + SizeOfRawData
4、SizeOfRawData:设置可以和VirtualSize一样,比如1000
5、PointerToRawData:等于上一个节的PointerToRawData+ SizeOfRawData
6、PointerToRelocation:设置成零
7、PointerToLineNumbers:设置成零
8、NumberOfLineRelocations:设置成零
9、NumberOfLineNumbers:设置成零
10、Characteristics:块属性0x20000060 可以取上一个节表和本节表的属性值,进行异或 如x|y
标志(属性块) 常用特征值对照表:
[值:00000020h] [IMAGE_SCN_CNT_CODE // Section contains code.(包含可执行代码)]
[值:00000040h] [IMAGE_SCN_CNT_INITIALIZED_DATA // Section contains initialized data.(该块包含已初始化的数据)]
[值:00000080h] [IMAGE_SCN_CNT_UNINITIALIZED_DATA // Section contains uninitialized data.(该块包含未初始化的数据)]
[值:00000200h] [IMAGE_SCN_LNK_INFO // Section contains comments or some other type of information.]
[值:00000800h] [IMAGE_SCN_LNK_REMOVE // Section contents will not become part of image.]
[值:00001000h] [IMAGE_SCN_LNK_COMDAT // Section contents comdat.]
[值:00004000h] [IMAGE_SCN_NO_DEFER_SPEC_EXC // Reset speculative exceptions handling bits in the TLB entries for this section.]
[值:00008000h] [IMAGE_SCN_GPREL // Section content can be accessed relative to GP.]
[值:00500000h] [IMAGE_SCN_ALIGN_16BYTES // Default alignment if no others are specified.]
[值:01000000h] [IMAGE_SCN_LNK_NRELOC_OVFL // Section contains extended relocations.]
[值:02000000h] [IMAGE_SCN_MEM_DISCARDABLE // Section can be discarded.]
[值:04000000h] [IMAGE_SCN_MEM_NOT_CACHED // Section is not cachable.]
[值:08000000h] [IMAGE_SCN_MEM_NOT_PAGED // Section is not pageable.]
[值:10000000h] [IMAGE_SCN_MEM_SHARED // Section is shareable(该块为共享块).]
[值:20000000h] [IMAGE_SCN_MEM_EXECUTE // Section is executable.(该块可执行)]
[值:40000000h] [IMAGE_SCN_MEM_READ // Section is readable.(该块可读)]
[值:80000000h] [IMAGE_SCN_MEM_WRITE // Section is writeable.(该块可写)]
-----------------------------------------------------------------------------------------------------
// mem.cpp : 定义控制台应用程序的入口点。 //PE文件从文件加载到内存,再从内存读取,然后存盘到文件 #include "stdafx.h" #include <windows.h> #include <winnt.h> //#define PATH "C:\\Windows\\System32\\notepad.exe" #define PATH "C:\\Users\\Administrator\\Desktop\\ipmsg.exe" #define MsgADD 0x75cffde6 char Shellcode[] = { 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00 }; int Filelength(FILE *fp); int _tmain(int argc, _TCHAR* argv[]) { FILE *Fp; fopen_s(&Fp, PATH, "rb"); int FileSize = Filelength(Fp);//获取文件大小 char * FileBuffer = (char *)malloc(FileSize);//申请存放文件的内存空间 if (FileBuffer == NULL) { printf("申请iImageBuffer失败"); } fread_s(FileBuffer, FileSize, 1, FileSize, Fp); //将文件复制到内存中 //定位一下内存中的数据 各个头表 //定位标准PE头 PIMAGE_FILE_HEADER MyFileHeader; MyFileHeader = (PIMAGE_FILE_HEADER)(char *)(FileBuffer + *(int *)(FileBuffer + 0x3c) + 0x4); //定位可选PE头 PIMAGE_OPTIONAL_HEADER MyOptionalHeader; MyOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((char *)MyFileHeader + 0x14); //定位节表 PIMAGE_SECTION_HEADER MySectionHeader; MySectionHeader = (PIMAGE_SECTION_HEADER)((char *)MyOptionalHeader + MyFileHeader->SizeOfOptionalHeader); //拉伸,也就是读到内存中的状态 char * ImageBuffer = (char *)malloc(MyOptionalHeader->SizeOfImage+0x1000);//给拉伸申请内存空间 ZeroMemory(ImageBuffer, MyOptionalHeader->SizeOfImage+0x1000); if (ImageBuffer == NULL) { printf("申请iImageBuffer失败"); } memcpy(ImageBuffer, FileBuffer, MyOptionalHeader->SizeOfHeaders); for (int i = 0; i < MyFileHeader->NumberOfSections; i++) { memcpy(ImageBuffer + MySectionHeader->VirtualAddress, FileBuffer + MySectionHeader->PointerToRawData, MySectionHeader->SizeOfRawData);// MySectionHeader++; } //新增节开始 PIMAGE_SECTION_HEADER AddSectionHeader; AddSectionHeader = MySectionHeader; MySectionHeader--; //AddSectionHeader->Name = "cyp"; //AddSectionHeader->Name = { 0 }; AddSectionHeader->Name[0] = '.'; AddSectionHeader->Name[1] = 'c'; AddSectionHeader->Name[2] = 'y'; AddSectionHeader->Name[3] = 'p'; AddSectionHeader->Misc.VirtualSize = 0x1000; AddSectionHeader->VirtualAddress = MySectionHeader->VirtualAddress + MySectionHeader->SizeOfRawData; AddSectionHeader->SizeOfRawData = 0x1000; AddSectionHeader->PointerToRawData = MySectionHeader->PointerToRawData + MySectionHeader->SizeOfRawData; int x = (MySectionHeader - (MyFileHeader->NumberOfSections-1))->Characteristics; AddSectionHeader->Characteristics = x; MyFileHeader->NumberOfSections += 1; MyOptionalHeader->SizeOfImage + 0x1000; //新增节结束 //添加代码到PE中 MyFileHeader = (PIMAGE_FILE_HEADER)(char *)(ImageBuffer + *(int *)(ImageBuffer + 0x3c) + 0x4); MyOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((char *)MyFileHeader + 0x14); MySectionHeader = (PIMAGE_SECTION_HEADER)((char *)MyOptionalHeader + MyFileHeader->SizeOfOptionalHeader);//重新指一下,前面动过了 //E8后面的硬编码地址 =真正要到的地址 - E8的下一行或E8本行 +0x5 char *CodeAdd = ImageBuffer + MySectionHeader->VirtualAddress + MySectionHeader->Misc.VirtualSize;//为要增加的代码确定位置 memcpy(CodeAdd, Shellcode, sizeof(Shellcode));//把硬编码复制到指定位置 int CallAdd = MsgADD - (MyOptionalHeader->ImageBase + ((int)(CodeAdd + 0xd) - (int)ImageBuffer)); *(int *)(CodeAdd + 0x9) = CallAdd;//定位CALL函数位置 int JmpAdd = MyOptionalHeader->ImageBase + MyOptionalHeader->AddressOfEntryPoint - (MyOptionalHeader->ImageBase + (CodeAdd + 0xd - ImageBuffer));//前面是真正要跳的地址 后面括号是下一条指令的地址 *(int *)(CodeAdd + 0xe) = JmpAdd;//定位JMP 跳回位置,也就是修改程序入口 MyOptionalHeader->AddressOfEntryPoint = CodeAdd - ImageBuffer;//重新定位程序入口处 //添加代码到PE结束 //压缩,为存盘做准备 char *NewBuffer = (char *)malloc(FileSize+0x1000);//给压缩申请内存空间 if (NewBuffer == NULL) { printf("申请iImageBuffer失败"); } memcpy(NewBuffer, ImageBuffer, MyOptionalHeader->SizeOfHeaders); MySectionHeader = (PIMAGE_SECTION_HEADER)((char *)MyOptionalHeader + MyFileHeader->SizeOfOptionalHeader);//重新指一下,前面动过了 for (int i = 0; i < MyFileHeader->NumberOfSections; i++) { memcpy(NewBuffer + MySectionHeader->PointerToRawData, ImageBuffer + MySectionHeader->VirtualAddress, MySectionHeader->SizeOfRawData); MySectionHeader++; } FILE *nFp; fopen_s(&nFp, "C:\\Users\\Administrator\\Desktop\\CYP.exe", "wb"); fwrite(NewBuffer, FileSize, 1, nFp); //getchar(); fclose(nFp); free(FileBuffer); free(ImageBuffer); free(NewBuffer); return 0; } //获取文件大小 int Filelength(FILE *fp) { int num; fseek(fp, 0, SEEK_END); num = ftell(fp); fseek(fp, 0, SEEK_SET); return num; }