滴水三期:day33.1-新增节、扩大节-添加代码

一、新增节思路 1.满足新增节条件
,根据文件对齐粒度来修正这个值,比如上面如果设定了的值为,说明这个节的这字节都是有用数据,那么此节在硬盘上时也应该有这字节的数据,所以此时根据文件对齐粒度来修正这个值,如果为0x200或者,就不用修改,因为已经满足是文件对齐的整数倍了
,文件对齐后的文件地址,我们可以通过上一个节表的 + 计算得到此值
,按照我们想要的属性来修改即可(可读、可写、可执行等)
如图所示:

滴水三期:day33.1-新增节、扩大节-添加代码

文章插图
的值不要随便改变,因为如果这个值变了,后面的节都要跟着往后或者往前跟着变,但是这些节当中凡是涉及到地址的计算相关的就会改变,比如说我们昨天加的E8和E9后面的值 , 是通过其他的地址计算出来的,如果变了 , 节地址跟着变,那么这些值也要改变 , 所以代价很高 , 不建议修改
2.如果节表后面有编译器添加的数据3.整体上移后空间还不够大4.注意事项二、手动新增节添加代码 1.条件都满足时
滴水三期:day33.1-新增节、扩大节-添加代码

文章插图
现在将我们要在文件末添加新节,选中文件最后一个数据 , 右键–edit–paste zero bytes–输入新节的大小 , 由于只能输入十进制数,所以要将转换成4096再输入?。。ㄕ饫镆状恚?
滴水三期:day33.1-新增节、扩大节-添加代码

文章插图
新增节后我们将要添加的代码加到新节中,这里就使用day32的,就是运行飞鸽后先弹一个框,再正常运行,但是此时还要计算一下E8和E9后面的值:
最后将OEP的值改为
【滴水三期:day33.1-新增节、扩大节-添加代码】保存,运行后发现先弹框再正常打开程序,成功
2.节表结尾有数据整体上移的情况3.整体上移后空间还不够,扩大最后一个节
此时就可以在最后一个节的末尾到结束这之间添加代码了
滴水三期:day33.1-新增节、扩大节-添加代码

文章插图
三、代码实现 1.编程实现:新增一个节 , 并添加代码
下面是最简单的新增节并添加代码,满足新增节的条件;注意问题:如果我们增加节或者扩大节,在中操作更方便,而且==一定要新申请一块内存来存储新增或扩大后的PE文件的数据==,不能直接在原有的的内存中操作 , 因为这块内存是动态分配的,大小是指定过的(size),不能修改或者新增 。
#include "stdafx.h"#include #include typedef unsigned short WORD;typedef unsigned int DWORD;typedef unsigned char BYTE;#define MZ 0x5A4D#define PE 0x4550#define IMAGE_SIZEOF_SHORT_NAME 8#define MessageBox_Address 0x77D36476 //宏定义记事本的MessageBox内存地址//shellcodeBYTE shellcode[] = {0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xE8,0x00,0x00,0x00,0x00,0xE9,0x00,0x00,0x00,0x00};//DOS头struct _IMAGE_DOS_HEADER {WORD e_magic;//MZ标记WORD e_cblp;WORD e_cp;WORD e_crlc;WORD e_cparhdr;WORD e_minalloc;WORD e_maxalloc;WORD e_ss;WORD e_sp;WORD e_csum;WORD e_ip;WORD e_cs;WORD e_lfarlc;WORD e_ovno;WORD e_res[4];WORD e_oemid;WORD e_oeminfo;WORD e_res2[10];DWORD e_lfanew;//PE文件真正开始的偏移地址};//标准PE头struct _IMAGE_FILE_HEADER {WORD Machine;//文件运行平台WORD NumberOfSections;//节数量DWORD TimeDateStamp;//时间戳DWORD PointerToSymbolTable;DWORD NumberOfSymbols;WORD SizeOfOptionalHeader;//可选PE头大小WORD Characteristics;//特征值};//可选PE头struct _IMAGE_OPTIONAL_HEADER {WORD Magic;//文件类型BYTE MajorLinkerVersion;BYTE MinorLinkerVersion;DWORD SizeOfCode;//代码节文件对齐后的大小DWORD SizeOfInitializedData;//初始化数据文件对齐后的大小DWORD SizeOfUninitializedData;//未初始化数据文件对齐后大小DWORD AddressOfEntryPoint;//程序入口点(偏移量)DWORD BaseOfCode;//代码基址DWORD BaseOfData;//数据基址DWORD ImageBase;//内存镜像基址DWORD SectionAlignment;//内存对齐粒度DWORD FileAlignment;//文件对齐粒度WORD MajorOperatingSystemVersion;WORD MinorOperatingSystemVersion;WORD MajorImageVersion;WORD MinorImageVersion;WORD MajorSubsystemVersion;WORD MinorSubsystemVersion;DWORD Win32VersionValue;DWORD SizeOfImage;//文件装入虚拟内存后大小DWORD SizeOfHeaders;//DOS、NT头和节表大小DWORD CheckSum;//校验和WORD Subsystem;WORD DllCharacteristics;DWORD SizeOfStackReserve;//预留堆栈大小DWORD SizeOfStackCommit;//实际分配堆栈大小DWORD SizeOfHeapReserve;//预留堆大小DWORD SizeOfHeapCommit;//实际分配堆大小DWORD LoaderFlags;DWORD NumberOfRvaAndSizes;//目录项数目//_IMAGE_DATA_DIRECTORY DataDirectory[16];//这个先不管};//NT头struct _IMAGE_NT_HEADERS {DWORD Signature;//PE签名_IMAGE_FILE_HEADER FileHeader;_IMAGE_OPTIONAL_HEADER OptionalHeader;};//节表struct _IMAGE_SECTION_HEADER{BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节表名union{DWORD PhysicalAddress;DWORD VirtualSize;//内存中未对齐大小}Misc;DWORD VirtualAddress;//该节在内存中偏移地址DWORD SizeOfRawData;//该节在硬盘上文件对齐后大小DWORD PointerToRawData;//该节在硬盘上文件对齐后偏移地址DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics;//该节特征属性};/*计算文件大小函数参数:文件绝对路径返回值:返回文件大?。ǖノ蛔纸冢?*/int compute_file_size(char* filePath){FILE* fp = fopen(filePath,"rb");if(!fp){printf("打开文件失败");exit(0);}fseek(fp,0,2);int size = ftell(fp);//fseek(fp,0,0); 单纯计算文件大小,就不需要还原指针了fclose(fp);return size;}/*将文件读入FileBuffer函数参数:文件绝对路径返回值:FileBuffer起始地址*/char* to_FileBuffer(char* filePath){FILE* fp = fopen(filePath,"rb");if(!fp){printf("打开文件失败");exit(0);}int size = compute_file_size(filePath);char* mp = (char*)malloc(sizeof(char) * size);//分配内存空间if(!mp){printf("分配空间失败");fclose(fp);exit(0);}int isSucceed = fread(mp,size,1,fp);if(!isSucceed){printf("读取数据失败");free(mp);fclose(fp);exit(0);}fclose(fp);return mp;}/*FileBuffer到ImageBuffer函数参数:FileBuffer起始地址返回值:ImageBuffer起始地址*/char* fileBuffer_to_ImageBuffer(char* fileBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);DWORD sizeofImage = _image_optional_header->SizeOfImage;char* imageBufferp = (char*)malloc(sizeofImage);if(NULL == imageBufferp){printf("动态申请ImageBuffer内存失败\n");exit(0);}for(DWORD i = 0;i < sizeofImage;i++){*(imageBufferp + i) = 0x00;}//strncpy(imageBufferp,fileBufferp,_image_optional_header->SizeOfHeaders); 因为imageBufferp,fileBufferp值会变,所以这个方法不太好for(i = 0;i < _image_optional_header->SizeOfHeaders;i++){*(imageBufferp + i) = *(fileBufferp + i);}for(i = 0;i < _image_file_header->NumberOfSections;i++){for(DWORD j = 0;j < _image_section_header->SizeOfRawData;j++){*(imageBufferp + _image_section_header->VirtualAddress + j) = *(fileBufferp + _image_section_header->PointerToRawData + j);}_image_section_header++;}return imageBufferp;}/*计算NewBuffer大小函数参数:NewBuffer起始地址返回值:unsigned int类型(单位:字节)*/DWORD compute_NewBuffer_size(char* newBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)newBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(newBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);_IMAGE_SECTION_HEADER* last_image_section_header = _image_section_header + _image_file_header->NumberOfSections - 1;DWORD sizeofNewBuffer = last_image_section_header->PointerToRawData + last_image_section_header->SizeOfRawData;return sizeofNewBuffer;}/*ImageBuffer到NewBuffer函数参数:ImageBuffer起始地址返回值:NewBuffer起始地址*/char* imageBuffer_to_NewBuffer(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//重新计算newBuffer需要大小/*方法一:SizeOfHEADER + 所有节的SizeOfRawData之和int sizeofSections = 0;_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;for(DWORD i = 0;i < _image_file_header->NumberOfSections;i++){sizeofSections += _image_section_header_temp->SizeOfRawData;_image_section_header_temp++;}char* newBufferp = (char*)malloc(_image_optional_header->SizeOfHeaders + sizeofSections);*///方法二:使用最后一个节的文件偏移地址 + 最后一个节对齐后的大小DWORD size = compute_NewBuffer_size(imageBufferp);char* newBufferp = (char*)malloc(size);if(NULL == newBufferp){printf("NewBuffer内存分配失败\n");exit(0);}for(DWORD i = 0;i < size;i++){*(newBufferp + i) = 0x00;}for(i = 0;i < _image_optional_header->SizeOfHeaders;i++){*(newBufferp + i) = *(imageBufferp + i);}for(i = 0;i < _image_file_header->NumberOfSections;i++){for(DWORD j = 0;j < _image_section_header->SizeOfRawData;j++){ //不用VirtualSize因为害怕会多复制覆盖下一个节*(newBufferp + _image_section_header->PointerToRawData + j) = *(imageBufferp + _image_section_header->VirtualAddress + j);}_image_section_header++;}return newBufferp;} /*NewBuffer存盘函数参数:需要写出数据的内存首地址 , 保存绝对路径,写出的数据大?。ǖノ唬鹤纸冢?返回值:成功返回1,失败返回0*/int save_to_disk(char* newBufferp,char* storagePath,DWORD size){FILE* fp = fopen(storagePath,"wb");if(!fp){printf("打开文件失败");return 0;}int isSucceed = fwrite(newBufferp,size,1,fp);if(!isSucceed){free(newBufferp);fclose(fp);return 0;}fclose(fp);return 1;}/*向新增节中注入shellcode函数参数:要注入的可执行文件的ImageBuffer起始地址返回值:0为注入失败、1为注入成功*/int add_shellcode_to_new_section(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//定位到新节表起始地址_IMAGE_SECTION_HEADER* target_image_section_header = _image_section_header + _image_file_header->NumberOfSections - 1;//判断新节是否存的下shellcodeif((int)(target_image_section_header->Misc.VirtualSize) < (int)(sizeof(shellcode) / sizeof(shellcode[0]))){printf("新节大小不够,添加失败");return 0;}//将shellcode注入到新节char* shellcodep = imageBufferp + target_image_section_header->VirtualAddress;char* newOEP = shellcodep;//此shellcode注入起始地址即为新的OEP地址memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值?。?/修改call MessageBox的硬编码E8后面的4字节DWORD E8_fill_value = http://www.kingceram.com/post/MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);*(DWORD*)(shellcodep + 9) = E8_fill_value;//修改jmp 原OEP的硬编码E9后面的4字节DWORD E9_fill_value = http://www.kingceram.com/post/_image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);*(DWORD*)(shellcodep + 14) = E9_fill_value;//修改OEP指向shellcode_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);return 1;}/*计算最小公倍数函数参数:传入要计算的两个数返回值:两数的最小公倍数*/int least_common_multiple(int a,int b){if(a <= 0 || b <= 0)return -1;int max = (a > b ? a : b);while(1){if(max % a == 0 && max % b == 0){break;}max++;}return max;}/*在文件最后新增节函数参数:要新增节的可执行文件的ImageBuffer起始地址返回值:新增节后的NewImageBuffer内存的起始地址*/char* add_one_section(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;//定义原来的ImageBuffer几个指针(因为要用到几个值用于创建新的NewImageBuffer内存)_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);//先计算添加新节后的NewImageBuffer的大小,并初始化内存int expand_value = http://www.kingceram.com/post/least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);//这里为了方便直接把新节大小设为文件对齐粒度和内存对齐粒度的最小公倍数即可char* newImageBufferp = (char*)malloc(_image_optional_header->SizeOfImage + expand_value);for(int i = 0;i < (int)_image_optional_header->SizeOfImage + expand_value;i++){*(newImageBufferp + i) = 0x00;}memcpy(newImageBufferp,imageBufferp,_image_optional_header->SizeOfImage);//不改变指针哦_image_dos_header = (_IMAGE_DOS_HEADER*)newImageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(newImageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//判断节表末尾是否有空间新增节表if(_image_optional_header->SizeOfHeaders - _image_dos_header->e_lfanew - 4 - 20 - _image_file_header->SizeOfOptionalHeader - _image_file_header->NumberOfSections * 40 < 80){printf("空间不足,无法新增节表");getchar();exit(0);}for(i = 0;i < 80;i++){if(*((char*)(_image_section_header + _image_file_header->NumberOfSections)+ i) != 0){printf("节表后80字节数据不全为0x00 , 有文件数据,无法新增节表");getchar();exit(0);}}//新增节DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage_image_optional_header->SizeOfImage += expand_value;//新增节表_IMAGE_SECTION_HEADER* _image_section_header_new = (_IMAGE_SECTION_HEADER*)(char*)_image_section_header + _image_file_header->NumberOfSections;for(i = 0;i < 40;i++){*((char*)_image_section_header_new + i) = *((char*)_image_section_header + i);}_image_file_header->NumberOfSections++;//修改新增节表信息char* name = (char*)_image_section_header_new->Name;char* newName = ".newsec";strncpy(name,newName,IMAGE_SIZEOF_SHORT_NAME);_image_section_header_new->Misc.VirtualSize = expand_value;_image_section_header_new->VirtualAddress = original_SizeOfImage;_image_section_header_new->SizeOfRawData = http://www.kingceram.com/post/expand_value;_image_section_header_new->PointerToRawData = http://www.kingceram.com/post/(_image_section_header_new - 1)->PointerToRawData + (_image_section_header_new - 1)->SizeOfRawData;_image_section_header_new->Characteristics = 0x60000020;return newImageBufferp;}int main(int argc,char* argv[]){//char* filePath = "D:/C-language/file/notepad.exe";//你要打开的PE文件绝对路径//char* storagePath = "D:/C-language/file/notepad_new.exe"; //保存路径char* filePath = "D:/IPMsg/ipmsg.exe";//你要打开的PE文件绝对路径char* storagePath = "D:/IPMsg/ipmsg_new.exe"; //保存路径char* fileBufferp = to_FileBuffer(filePath);char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);char* newImageBufferp = add_one_section(imageBufferp);if(!add_shellcode_to_new_section(newImageBufferp)){printf("在新节中注入shellcode失败");getchar();return 0;}char* newBufferp = imageBuffer_to_NewBuffer(newImageBufferp);DWORD size = compute_NewBuffer_size(newBufferp);int isSucceed = save_to_disk(newBufferp,storagePath,size);if(!isSucceed){printf("存盘失败");getchar();}elseprintf("存盘成功");free(fileBufferp);free(imageBufferp);free(newImageBufferp);free(newBufferp);return 0;}
2.编程实现:扩大最后一个节,并添加代码
一定要新申请一块内存,来存储扩大后的PE文件 , 不能在原有的上面扩大
#include "stdafx.h"#include #include typedef unsigned short WORD;typedef unsigned int DWORD;typedef unsigned char BYTE;#define MZ 0x5A4D#define PE 0x4550#define IMAGE_SIZEOF_SHORT_NAME 8#define MessageBox_Address 0x77D36476 //宏定义记事本的MessageBox内存地址//shellcodeBYTE shellcode[] = {0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xE8,0x00,0x00,0x00,0x00,0xE9,0x00,0x00,0x00,0x00};//DOS头struct _IMAGE_DOS_HEADER {WORD e_magic;//MZ标记WORD e_cblp;WORD e_cp;WORD e_crlc;WORD e_cparhdr;WORD e_minalloc;WORD e_maxalloc;WORD e_ss;WORD e_sp;WORD e_csum;WORD e_ip;WORD e_cs;WORD e_lfarlc;WORD e_ovno;WORD e_res[4];WORD e_oemid;WORD e_oeminfo;WORD e_res2[10];DWORD e_lfanew;//PE文件真正开始的偏移地址};//标准PE头struct _IMAGE_FILE_HEADER {WORD Machine;//文件运行平台WORD NumberOfSections;//节数量DWORD TimeDateStamp;//时间戳DWORD PointerToSymbolTable;DWORD NumberOfSymbols;WORD SizeOfOptionalHeader;//可选PE头大小WORD Characteristics;//特征值};//可选PE头struct _IMAGE_OPTIONAL_HEADER {WORD Magic;//文件类型BYTE MajorLinkerVersion;BYTE MinorLinkerVersion;DWORD SizeOfCode;//代码节文件对齐后的大小DWORD SizeOfInitializedData;//初始化数据文件对齐后的大小DWORD SizeOfUninitializedData;//未初始化数据文件对齐后大小DWORD AddressOfEntryPoint;//程序入口点(偏移量)DWORD BaseOfCode;//代码基址DWORD BaseOfData;//数据基址DWORD ImageBase;//内存镜像基址DWORD SectionAlignment;//内存对齐粒度DWORD FileAlignment;//文件对齐粒度WORD MajorOperatingSystemVersion;WORD MinorOperatingSystemVersion;WORD MajorImageVersion;WORD MinorImageVersion;WORD MajorSubsystemVersion;WORD MinorSubsystemVersion;DWORD Win32VersionValue;DWORD SizeOfImage;//文件装入虚拟内存后大小DWORD SizeOfHeaders;//DOS、NT头和节表大小DWORD CheckSum;//校验和WORD Subsystem;WORD DllCharacteristics;DWORD SizeOfStackReserve;//预留堆栈大小DWORD SizeOfStackCommit;//实际分配堆栈大小DWORD SizeOfHeapReserve;//预留堆大小DWORD SizeOfHeapCommit;//实际分配堆大小DWORD LoaderFlags;DWORD NumberOfRvaAndSizes;//目录项数目//_IMAGE_DATA_DIRECTORY DataDirectory[16];//这个先不管};//NT头struct _IMAGE_NT_HEADERS {DWORD Signature;//PE签名_IMAGE_FILE_HEADER FileHeader;_IMAGE_OPTIONAL_HEADER OptionalHeader;};//节表struct _IMAGE_SECTION_HEADER{BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节表名union{DWORD PhysicalAddress;DWORD VirtualSize;//内存中未对齐大小}Misc;DWORD VirtualAddress;//该节在内存中偏移地址DWORD SizeOfRawData;//该节在硬盘上文件对齐后大小DWORD PointerToRawData;//该节在硬盘上文件对齐后偏移地址DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics;//该节特征属性};/*计算文件大小函数参数:文件绝对路径返回值:返回文件大?。ǖノ蛔纸冢?*/int compute_file_size(char* filePath){FILE* fp = fopen(filePath,"rb");if(!fp){printf("打开文件失败");exit(0);}fseek(fp,0,2);int size = ftell(fp);//fseek(fp,0,0); 单纯计算文件大?。?就不需要还原指针了fclose(fp);return size;}/*将文件读入FileBuffer函数参数:文件绝对路径返回值:FileBuffer起始地址*/char* to_FileBuffer(char* filePath){FILE* fp = fopen(filePath,"rb");if(!fp){printf("打开文件失败");exit(0);}int size = compute_file_size(filePath);char* mp = (char*)malloc(sizeof(char) * size);//分配内存空间if(!mp){printf("分配空间失败");fclose(fp);exit(0);}int isSucceed = fread(mp,size,1,fp);if(!isSucceed){printf("读取数据失败");free(mp);fclose(fp);exit(0);}fclose(fp);return mp;}/*FileBuffer到ImageBuffer函数参数:FileBuffer起始地址返回值:ImageBuffer起始地址*/char* fileBuffer_to_ImageBuffer(char* fileBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);DWORD sizeofImage = _image_optional_header->SizeOfImage;char* imageBufferp = (char*)malloc(sizeofImage);if(NULL == imageBufferp){printf("动态申请ImageBuffer内存失败\n");exit(0);}for(DWORD i = 0;i < sizeofImage;i++){*(imageBufferp + i) = 0x00;}//strncpy(imageBufferp,fileBufferp,_image_optional_header->SizeOfHeaders); 因为imageBufferp,fileBufferp值会变,所以这个方法不太好for(i = 0;i < _image_optional_header->SizeOfHeaders;i++){*(imageBufferp + i) = *(fileBufferp + i);}for(i = 0;i < _image_file_header->NumberOfSections;i++){for(DWORD j = 0;j < _image_section_header->SizeOfRawData;j++){*(imageBufferp + _image_section_header->VirtualAddress + j) = *(fileBufferp + _image_section_header->PointerToRawData + j);}_image_section_header++;}return imageBufferp;}/*计算NewBuffer大小函数参数:NewBuffer起始地址返回值:unsigned int类型(单位:字节)*/DWORD compute_NewBuffer_size(char* newBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)newBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(newBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);_IMAGE_SECTION_HEADER* last_image_section_header = _image_section_header + _image_file_header->NumberOfSections - 1;DWORD sizeofNewBuffer = last_image_section_header->PointerToRawData + last_image_section_header->SizeOfRawData;return sizeofNewBuffer;}/*ImageBuffer到NewBuffer函数参数:ImageBuffer起始地址返回值:NewBuffer起始地址*/char* imageBuffer_to_NewBuffer(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//重新计算newBuffer需要大小/*方法一:SizeOfHEADER + 所有节的SizeOfRawData之和int sizeofSections = 0;_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;for(DWORD i = 0;i < _image_file_header->NumberOfSections;i++){sizeofSections += _image_section_header_temp->SizeOfRawData;_image_section_header_temp++;}char* newBufferp = (char*)malloc(_image_optional_header->SizeOfHeaders + sizeofSections);*///方法二:使用最后一个节的文件偏移地址 + 最后一个节对齐后的大小DWORD size = compute_NewBuffer_size(imageBufferp);char* newBufferp = (char*)malloc(size);if(NULL == newBufferp){printf("NewBuffer内存分配失败\n");exit(0);}for(DWORD i = 0;i < size;i++){*(newBufferp + i) = 0x00;}for(i = 0;i < _image_optional_header->SizeOfHeaders;i++){*(newBufferp + i) = *(imageBufferp + i);}for(i = 0;i < _image_file_header->NumberOfSections;i++){for(DWORD j = 0;j < _image_section_header->SizeOfRawData;j++){ //不用VirtualSize因为害怕会多复制覆盖下一个节*(newBufferp + _image_section_header->PointerToRawData + j) = *(imageBufferp + _image_section_header->VirtualAddress + j);}_image_section_header++;}return newBufferp;} /*NewBuffer存盘函数参数:需要写出数据的内存首地址,保存绝对路径,写出的数据大?。ǖノ唬鹤纸冢?返回值:成功返回1,失败返回0*/int save_to_disk(char* newBufferp,char* storagePath,DWORD size){FILE* fp = fopen(storagePath,"wb");if(!fp){printf("打开文件失败");return 0;}int isSucceed = fwrite(newBufferp,size,1,fp);if(!isSucceed){free(newBufferp);fclose(fp);return 0;}fclose(fp);return 1;}/*向新增节中注入shellcode函数参数:要注入的可执行文件的ImageBuffer起始地址返回值:0为注入失败、1为注入成功*//*int add_shellcode_to_new_section(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//定位到新节表起始地址_IMAGE_SECTION_HEADER* target_image_section_header = _image_section_header + _image_file_header->NumberOfSections - 1;//判断新节是否存的下shellcodeif((int)(target_image_section_header->Misc.VirtualSize) < (int)(sizeof(shellcode) / sizeof(shellcode[0]))){printf("新节大小不够,添加失败");return 0;}//将shellcode注入到新节char* shellcodep = imageBufferp + target_image_section_header->VirtualAddress;char* newOEP = shellcodep;//此shellcode注入起始地址即为新的OEP地址memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值?。?/修改call MessageBox的硬编码E8后面的4字节DWORD E8_fill_value = http://www.kingceram.com/post/MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);*(DWORD*)(shellcodep + 9) = E8_fill_value;//修改jmp 原OEP的硬编码E9后面的4字节DWORD E9_fill_value = http://www.kingceram.com/post/_image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);*(DWORD*)(shellcodep + 14) = E9_fill_value;//修改OEP指向shellcode_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);return 1;}*//*计算最小公倍数函数参数:传入要计算的两个数返回值:两数的最小公倍数*/int least_common_multiple(int a,int b){if(a <= 0 || b <= 0)return -1;int max = (a > b ? a : b);while(1){if(max % a == 0 && max % b == 0){break;}max++;}return max;}/*在文件最后新增节函数参数:要新增节的可执行文件的ImageBuffer起始地址返回值:新增节后的NewImageBuffer内存的起始地址*//*char* add_one_section(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;//定义原来的ImageBuffer几个指针(因为要用到几个值用于创建新的NewImageBuffer内存)_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);//先计算添加新节后的NewImageBuffer的大?。?并初始化内存int expand_value = http://www.kingceram.com/post/least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);//这里为了方便直接把新节大小设为文件对齐粒度和内存对齐粒度的最小公倍数即可char* newImageBufferp = (char*)malloc(_image_optional_header->SizeOfImage + expand_value);for(int i = 0;i < (int)_image_optional_header->SizeOfImage + expand_value;i++){*(newImageBufferp + i) = 0x00;}memcpy(newImageBufferp,imageBufferp,_image_optional_header->SizeOfImage);//不改变指针哦_image_dos_header = (_IMAGE_DOS_HEADER*)newImageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(newImageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//判断节表末尾是否有空间新增节表if(_image_optional_header->SizeOfHeaders - _image_dos_header->e_lfanew - 4 - 20 - _image_file_header->SizeOfOptionalHeader - _image_file_header->NumberOfSections * 40 < 80){printf("空间不足,无法新增节表");getchar();exit(0);}for(i = 0;i < 80;i++){if(*((char*)(_image_section_header + _image_file_header->NumberOfSections)+ i) != 0){printf("节表后80字节数据不全为0x00,有文件数据,无法新增节表");getchar();exit(0);}}//新增节DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage_image_optional_header->SizeOfImage += expand_value;//新增节表_IMAGE_SECTION_HEADER* _image_section_header_new = (_IMAGE_SECTION_HEADER*)(char*)_image_section_header + _image_file_header->NumberOfSections;for(i = 0;i < 40;i++){*((char*)_image_section_header_new + i) = *((char*)_image_section_header + i);}_image_file_header->NumberOfSections++;//修改新增节表信息char* name = (char*)_image_section_header_new->Name;char* newName = ".newsec";strncpy(name,newName,IMAGE_SIZEOF_SHORT_NAME);_image_section_header_new->Misc.VirtualSize = expand_value;_image_section_header_new->VirtualAddress = original_SizeOfImage;_image_section_header_new->SizeOfRawData = http://www.kingceram.com/post/expand_value;_image_section_header_new->PointerToRawData = http://www.kingceram.com/post/(_image_section_header_new - 1)->PointerToRawData + (_image_section_header_new - 1)->SizeOfRawData;_image_section_header_new->Characteristics = 0x60000020;return newImageBufferp;}*//*扩大最后一个节函数参数:要扩大节的可执行文件的ImageBuffer起始地址返回值:扩大节后的NewImageBuffer内存的起始地址*/char* expand_last_section(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);//计算扩大多少 , 并初始化NewImageBufferint expand_value = http://www.kingceram.com/post/least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);//这里为了方便直接把需要扩大的大小设为文件对齐粒度和内存对齐粒度的最小公倍数即可char* newImageBufferp = (char*)malloc(_image_optional_header->SizeOfImage + expand_value);for(int i = 0;i < (int)_image_optional_header->SizeOfImage + expand_value;i++){*(newImageBufferp + i) = 0x00;}memcpy(newImageBufferp,imageBufferp,_image_optional_header->SizeOfImage);//不改变指针哦_image_dos_header = (_IMAGE_DOS_HEADER*)newImageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(newImageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//修改SizeofImage:原来的SizeOfImage + Ex(因为原来的SizeOfImage是内存对齐的整数倍 , Ex也是通过内存对齐和文件对齐的最小公倍数算出来的,所以相加一定还是内存对齐的整数倍)DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage_image_optional_header->SizeOfImage += expand_value;//修改节表信息_IMAGE_SECTION_HEADER* _image_section_header_last = _image_section_header + _image_file_header->NumberOfSections - 1;_image_section_header_last->Misc.VirtualSize = original_SizeOfImage - _image_section_header_last->VirtualAddress + expand_value;_image_section_header_last->SizeOfRawData = http://www.kingceram.com/post/_image_section_header_last->Misc.VirtualSize;//修改节属性,保证可执行_image_section_header_last->Characteristics = _image_section_header_last->Characteristics | 0x60000020;return newImageBufferp;}/*向扩大的节中注入shellcode函数参数:要注入的可执行文件的ImageBuffer起始地址返回值:0表示注入失败 , 1表示注入成功*/int add_shellcode_to_expanded_section(char* imageBufferp){_IMAGE_DOS_HEADER* _image_dos_header = NULL;_IMAGE_FILE_HEADER* _image_file_header = NULL;_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;_IMAGE_SECTION_HEADER* _image_section_header = NULL;_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);//判断是否存的下shellcode,这里直接在Ex区域内注入 , 不考虑原来的空白区if((int)(least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment)) < (int)(sizeof(shellcode) / sizeof(shellcode[0]))){printf("新节大小不够,添加失败");return 0;}//将shellcode注入到Exchar* shellcodep = imageBufferp + _image_optional_header->SizeOfImage - least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);char* newOEP = shellcodep;//此shellcode注入起始地址即为新的OEP地址memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值?。?/修改call MessageBox的硬编码E8后面的4字节DWORD E8_fill_value = http://www.kingceram.com/post/MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);*(DWORD*)(shellcodep + 9) = E8_fill_value;//修改jmp 原OEP的硬编码E9后面的4字节DWORD E9_fill_value = http://www.kingceram.com/post/_image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);*(DWORD*)(shellcodep + 14) = E9_fill_value;//修改OEP指向shellcode_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);return 1;}int main(int argc,char* argv[]){char* filePath = "D:/C-language/file/notepad.exe";//你要打开的PE文件绝对路径char* storagePath = "D:/C-language/file/notepad_new.exe"; //保存路径//char* filePath = "D:/IPMsg/ipmsg.exe";//你要打开的PE文件绝对路径//char* storagePath = "D:/IPMsg/ipmsg_new.exe"; //保存路径char* fileBufferp = to_FileBuffer(filePath);char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);char* newImageBufferp = expand_last_section(imageBufferp);/*if(!add_shellcode_to_new_section(newImageBufferp)){printf("在新节中注入shellcode失败");getchar();return 0;}*/if(!add_shellcode_to_expanded_section(newImageBufferp)){printf("在新节中注入shellcode失败");getchar();return 0;}char* newBufferp = imageBuffer_to_NewBuffer(newImageBufferp);DWORD size = compute_NewBuffer_size(newBufferp);int isSucceed = save_to_disk(newBufferp,storagePath,size);if(!isSucceed){printf("存盘失败");getchar();}elseprintf("存盘成功");free(fileBufferp);free(imageBufferp);free(newImageBufferp);free(newBufferp);return 0;}