程序功能:在程序中新增一个节,并添加ShellCode
这里直接给出源码,供大家参考,自行理解遍会有更好的理解
PEFunction.h:
#include <stdio.h> #include <windows.h> //*************打开文件函数(将文件二进制读取到FileBuffer) ****************** //该函数需要一个char类型的指针,指向想要打开的文件路径 //该函数返回一个char类型的指针,指向FileBuffer //该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer //该函数读取完成后会将文件关闭,避免出现误操作 //该函数会通过移动文件指针获取文件大小 //获取的文件大小用于动态申请内存 //该函数会动态申请内存,用于存放FileBuffer //*************************************************************************** char* ReadToFileBuffer(char* filename); //***************************************获取文件大小函数********************************* //该函数返回文件大小 //**************************************************************************************** int SizeOfFile(char* filename); //*****************************获取PE导出表数据函数************************** //该函数需要一个指针,指向FileBuffer //该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表 //该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 //*************************************************************************** void ShowExportDirectory(char* FileBuffer); //*****************************RVA转换为FOA函数****************************** //该函数需要一个指针,指向FileBuffer //该函数需要一个整数,为要转换的RVA //该函数返回一个整数,为转换后的FOA地址 //*************************************************************************** int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva); //*************************根据函数名称查找函数地址函数********************** //该函数需要一个指针,指向要打开的文件路径 //该函数返回一个整数,指向得到的函数地址 //*************************************************************************** void GetAddressOfFunctionByName(char* filename); //*************************根据函数序号查找函数地址函数********************** //该函数需要一个指针,指向要打开的文件路径 //该函数返回一个整数,指向得到的函数地址 //*************************************************************************** void GetAddressOfFunctionByOrdinal(char* filename); //******************************打印PE重定位表函数*************************** //该函数需要一个指针,指向FIleBuffer //该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项 //*************************************************************************** void ShowBaseRelocation(char* FileBuffer); //**************************************新增节函数*************************************** //该函数需要一个指针,指向FileBuffer //该函数需要一个整数,表示FileBuffer大小 //该函数需要一个字符串,位原文件文件名 //该函数完成在PE文件中新增一个节 //该函数在新增节之前,PE头部是否足够新增一个节表 //若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 //该函数会生成一个exe文件,存放于调用该函数的程序源目录下 //该函数无返回值 //**************************************************************************************** void AddNewSection(char* FileBuffer,int SizeOfFile); //*****************************覆盖DOSstob,抬升NT头和原有节表**************************** //该函数需要一个指针,指向需要改动的FileBuffer //该函数将FileBuffer中的DOSstob覆盖 //该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 //抬升成功后会将最后两个节表的数据全初始化为0 //若头部抬升失败,则返回0 //若抬升成功,则返回1 //**************************************************************************************** int UpFile(char* FileBuffer); //******************************计算文件对齐后的值函数************************************ //Align:计算对齐后的值 //参数说明: //x 需要进行对齐的值 //Alignment 对齐大小 //返回值说明: //返回x进行Alignment值对齐后的值 //**************************************************************************************** int Align(int x, int Alignment);
PEFunction.c:
/**************************************************************/ //*********************自编PE函数库****************************/ #include "PEFunction.h" //********打开文件函数(将文件二进制读取到FileBuffer) ******* //函数说明: //该函数需要一个char类型的指针,指向想要打开的文件路径 //该数返回一个char类型的指针,指向FileBuffer //该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer //该函数读取完成后会将文件关闭,避免出现误操作 //该函数会通过移动文件指针获取文件大小 //获取的文件大小用于动态申请内存 //该函数会动态申请内存,用于存放FileBuffer //********************************************************* char* ReadToFileBuffer(char* filename){ FILE* fp; char* FileBuffer=NULL; int length; if((fp=fopen(filename,"rb"))==NULL){ printf("%s打开失败!",filename); exit(0); }else{ printf("文件打开成功,正在计算文件大小...\n"); } fseek(fp,0,SEEK_END); length=ftell(fp); fseek(fp,0,SEEK_SET); printf("文件大小:%d字节\n正在申请FileBuffer内存...\n",length); FileBuffer=(char*)malloc(length); if(FileBuffer!=NULL){ printf("FileBuffer内存申请成功。准备向FileBuffer写入数据...\n"); } if((fread(FileBuffer,length,1,fp))==0){ printf("写入数据失败!\n"); exit(0); }else{ printf("写入数据成功。\n"); } if(fclose(fp)){ printf("文件关闭失败!\n"); exit(0); }else{ printf("文件关闭成功。\n"); } return FileBuffer; } //***************************************获取文件大小函数********************************* //该函数返回文件大小 //**************************************************************************************** int SizeOfFile(char* filename){ FILE* fp; char* FileBuffer=NULL; int length; if((fp=fopen(filename,"rb"))==NULL){ printf("%s打开失败!",filename); exit(0); }else{ printf("文件打开成功,正在计算文件大小...\n"); } fseek(fp,0,SEEK_END); length=ftell(fp); fseek(fp,0,SEEK_SET); return length; } //**********************获取PE导出表数据函数************************************************ //该函数需要一个指针,指向FileBuffer //该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表 //该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 //******************************************************************************************** void ShowExportDirectory(char* FileBuffer){ IMAGE_DOS_HEADER* pDosHeader=NULL; IMAGE_FILE_HEADER* pFileHeader=NULL; IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL; IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL; pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer; if(*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew))!= IMAGE_NT_SIGNATURE){ printf("不是有效的PE标志!\n"); }else{ printf("检测到有效的PE标志。\n"); } pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4); pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20); pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress)); printf("导出表RVA:%x\n",pOptionalHeader->DataDirectory[0].VirtualAddress); printf("导出表大小:%x字节\n",pOptionalHeader->DataDirectory[0].Size); printf("导出表FOA:%d\n",RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress)); printf("*******************************导出表*********************************\n"); printf("TimeDataStamp(经加密):%d\n",pExportDirectory->TimeDateStamp); printf("Name(导出表文件名字符串):%s\n",FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->Name)); printf("Base(函数起始序号):%d\n",pExportDirectory->Base); printf("NumberOfFunction(导出函数总数):%d\n",pExportDirectory->NumberOfFunctions); printf("NumberOfNames(以名称导出函数的总数):%d\n",pExportDirectory->NumberOfNames); printf("*****************************函数地址表********************************\n"); int i=0; char* AddressOfFunction; AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions)); for(i=0;i<pExportDirectory->NumberOfFunctions;i++){ printf("下标:%d 函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunction+i*4)); } printf("*****************************函数名称表********************************\n"); int* AddressOfNames=NULL; char* name=NULL; AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames)); for(i=0;i<pExportDirectory->NumberOfNames;i++){ name=(char*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNames)); printf("下标:%d 函数名称:%s\n",i,name); AddressOfNames++; } printf("*******************************函数序号表*******************************\n"); char *AddressOfNameOrdinals=NULL; char *Ordinal=NULL; AddressOfNameOrdinals=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals)); for(i=0;i<pExportDirectory->NumberOfNames;i++){ Ordinal=(int*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNameOrdinals)); printf("下标:%d 函数序号(加Base):%d\n",i,*(AddressOfNameOrdinals+i*2)+pExportDirectory->Base); } } //***********************3.RVA转换为FOA函数************************* //该函数需要一个指针,指向FileBuffer //该函数需要一个整数,为要转换的RVA //该函数返回一个整数,为转换后的FOA地址 //****************************************************************** int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva) { PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_FILE_HEADER pFileHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; PIMAGE_SECTION_HEADER pNextSectionHeader = NULL; //DOS头 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; // 强转 DOS_HEADER 结构体指针 //PE头 pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4); //NT头地址 + 4 为 FileHeader 首址 //可选PE头 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中 if (dwRva < pOptionalHeader->SizeOfHeaders) //偏移小于头的大小,内存偏移则为文件偏移 { return dwRva; } //首个节表 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); //下一个节表 pNextSectionHeader = pSectionHeader + 1; //循环遍历节表 int i; for (i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++, pNextSectionHeader++)//注意这里i从1开始 i < NumberOfSections { //注意这里的pSectionHeader已经是加了基址的,不是偏移, 是绝对地址。而dwRva是偏移地址 if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pNextSectionHeader->VirtualAddress)//大于当前节的内存偏移而小于下一节的内存偏移 { //则dwRva属于当前节,则dwRva - VirtualAddress为dwRva基于当前节的偏移。此偏移加上当前节的文件起始偏移地址 则为dwRva在文件中的偏移 DWORD PointerToRawData = pSectionHeader->PointerToRawData; DWORD VirtualAddress = pSectionHeader->VirtualAddress; DWORD aa = pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress; return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress ; } } //出循环后pSectionHeader指向最后一个节表 //大于当前节(最后一节)的内存偏移且小于内存映射大小 if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pOptionalHeader->SizeOfImage) { //同上return return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress; } else //大于内存映射大小 { printf("dwRva大于内存映射大小\n"); return -1; } } //***********************4.根据函数名称查找函数地址函数*********************** //该函数需要一个指针,指向要打开的文件路径 //该函数返回一个整数,指向得到的函数地址 //**************************************************************************** void GetAddressOfFunctionByName(char* filename){ char* FileBuffer=NULL; char inname[5]; int i; FileBuffer=ReadToFileBuffer(filename); IMAGE_DOS_HEADER* pDosHeader=NULL; IMAGE_FILE_HEADER* pFileHeader=NULL; IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL; IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL; pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer; if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){ printf("检测到有效的PE标志。\n"); }else{ printf("未检测到有效的PE标志!\n"); exit(0); } pFileHeader=(IMAGE_FILE_HEADER*)((DWORD)FileBuffer+pDosHeader->e_lfanew+4); pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20); pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress)); int* AddressOfNames=NULL; char* name=NULL; AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames)); printf("请输入您需要查找的函数名:"); scanf("%s",inname); printf("正在查找中...\n"); for(i=0;i<pExportDirectory->NumberOfNames;i++){ name=(int*)(FileBuffer+RVAToFOA(FileBuffer,RVAToFOA(FileBuffer,*AddressOfNames))); if(!(strcmp("Plus",name))){ printf("下标为%d的函数名符合。\n",i); break; } AddressOfNames++; } char* Ordinal=NULL; Ordinal=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals)+i*2); char* AddressOfFunction=NULL; AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions)+*Ordinal*4); printf("Ordinal(函数导出序号(未加Base)):%d AddressOfFunction:0x%x",*Ordinal,*(PWORD)((DWORD)AddressOfFunction)); } //**********************5.根据函数序号查找函数地址函数*********************** //该函数需要一个指针,指向要打开的文件路径 //该函数返回一个整数,指向得到的函数地址 //*************************************************************************** void GetAddressOfFunctionByOrdinal(char* filename){ char* FileBuffer=NULL; int InOrdinal=0; IMAGE_DOS_HEADER* pDosHeader=NULL; IMAGE_FILE_HEADER* pFileHeader=NULL; IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL; IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL; FileBuffer=ReadToFileBuffer(filename); char* AddressOfFunction; pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer; if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){ printf("检测到PE标志。"); }else{ printf("未检测到PE标志!\n"); exit(0); } pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4); pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20); pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress)); printf("请输入您需要查找的函数导出序号:"); scanf("%d",&InOrdinal); InOrdinal=InOrdinal-pExportDirectory->Base; AddressOfFunction=(char*)FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions+InOrdinal*4); printf("函数导出序号(未加Base):%d 函数地址:0x%x",InOrdinal,*(PWORD)((DWORD)AddressOfFunction)); } //***********************6.打印PE重定位表函数********************************************* //该函数需要一个指针,指向FIleBuffer //该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项*/ //**************************************************************************************** void ShowBaseRelocation(char* FileBuffer){ int i=1; IMAGE_DOS_HEADER* pDosHeader=NULL; IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL; IMAGE_BASE_RELOCATION* pBaseRelocation=NULL; pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer; if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){ printf("检测到有效的PE标志。\n"); }else{ printf("未检测到有效的PE标志!\n"); exit(0); } pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)FileBuffer+pDosHeader->e_lfanew+24); pBaseRelocation=(IMAGE_BASE_RELOCATION*)((DWORD)FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[5].VirtualAddress)); printf("%x",pOptionalHeader->DataDirectory[5].VirtualAddress); while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){ printf("************ 第%d块 ************\n",i); printf("VirtulaAddress(重定位表在文件中的偏移):0x%x\n",RVAToFOA(FileBuffer,pBaseRelocation->VirtualAddress)); printf("Size(该块重定位表的大小):%d字节\n",pBaseRelocation->SizeOfBlock); printf("重定位表具体项数目:%d\n\n",(pBaseRelocation->SizeOfBlock-8)/2); pBaseRelocation = (IMAGE_BASE_RELOCATION*)(pBaseRelocation->SizeOfBlock + (DWORD)pBaseRelocation); i++; } } //**************************************新增节函数*************************************** //该函数需要一个指针,指向FileBuffer //该函数需要一个整数,表示FileBuffer大小 //该函数需要一个字符串,位原文件文件名 //该函数完成在PE文件中新增一个节 //该函数在新增节之前,PE头部是否足够新增一个节表 //若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 //该函数会生成一个exe文件,存放于调用该函数的程序源目录下 //该函数无返回值 //**************************************************************************************** void AddNewSection(char* FileBuffer,int SizeOfFileBuffer){ printf("新增节执行中...\n"); int choose1; unsigned char ShellCode[100]; int AddressOfShellCode=0; PIMAGE_DOS_HEADER pDosHeader=NULL; PIMAGE_FILE_HEADER pFileHeader=NULL; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL; PIMAGE_SECTION_HEADER pSectionHeader=NULL; PIMAGE_SECTION_HEADER pNewSectionHeader=NULL; int i,j; char* NewFileBuffer=NULL; pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer; if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){ printf("检测到有效的PE标志。\n"); }else{ printf("未检测到有效的PE标志!\n"); return 0; } pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4); pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20); pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader); for(i=0;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){ printf("移动节表指针中...\n"); printf("%s",pSectionHeader->Name); } pNewSectionHeader=pSectionHeader; for(i=0;i<IMAGE_SIZEOF_SECTION_HEADER*2;i++){ if((*(PWORD)((DWORD)pNewSectionHeader+i))!=0){ printf("%x",*(PWORD)((DWORD)pNewSectionHeader+i)); printf("PE文件头部内存空间不足,需要覆盖DOSstob抬升头部,以保证足够的空间新增节表!\n"); if(UpFile){ printf("更新头部指针中...\n"); pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer; pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4); pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20); pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pOptionalHeader->SizeOfHeaders); for(i=0;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){ printf("移动节表指针中...\n"); } pNewSectionHeader=pSectionHeader+1; break; }else{ printf("抬升失败!\n"); return 0; } }else{ printf("检测数据中...\n"); } } if(i==IMAGE_SIZEOF_SECTION_HEADER*2){ printf("数据检测完毕,未检测到数据,将新增节...\n"); } strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec"); printf("****** 请选择是否添加ShellCode ******\n"); printf("****** 0:不添加ShellCode ******\n"); printf("****** 1:添加ShellCode ******\n"); printf("请输入您的选择:"); scanf("%d",&choose1); switch (choose1){ case 0:{ strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec"); pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode); pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage; printf("FileAligment:%x\n",pOptionalHeader->FileAlignment); pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment); pNewSectionHeader->PointerToRawData = SizeOfFileBuffer; // pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData; pNewSectionHeader->PointerToRelocations = 0; pNewSectionHeader->PointerToLinenumbers = 0; pNewSectionHeader->NumberOfRelocations = 0; pNewSectionHeader->NumberOfLinenumbers = 0; pNewSectionHeader->Characteristics = 0x60000020; pFileHeader->NumberOfSections++; printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage); pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment); printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage); int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData; NewFileBuffer=(char*)malloc(SizeOfNewBuffer); memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer); memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData); FILE* fp=NULL; if((fp=(fopen("新增节程序.exe","wb")))==NULL){ printf("文件新建失败!\n"); exit(0); }else{ printf("文件新建成功,正在写入数据...\n"); if(fwrite(NewFileBuffer,SizeOfNewBuffer,1,fp)){ printf("数据写入成功。\n"); }else{ printf("数据写入失败!\n"); exit(0); } } if(!fclose(fp)){ printf("文件保存成功。\n"); }else{ printf("文件保存失败!"); exit(0); } free(NewFileBuffer); break; } case 1:{ int CallShellCode; int JmpShellCode; strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec"); pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode); pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode); pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage; printf("FileAligment:%x\n",pOptionalHeader->FileAlignment); pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment); pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData; pNewSectionHeader->PointerToRelocations = 0; pNewSectionHeader->PointerToLinenumbers = 0; pNewSectionHeader->NumberOfRelocations = 0; pNewSectionHeader->NumberOfLinenumbers = 0; pNewSectionHeader->Characteristics = 0x60000020; pFileHeader->NumberOfSections++; printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage); pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment); printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage); int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData; NewFileBuffer=(int*)malloc(SizeOfNewBuffer); DWORD OddAddressOfEntryPoint = pOptionalHeader->AddressOfEntryPoint; pOptionalHeader->AddressOfEntryPoint = pNewSectionHeader->VirtualAddress; memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer); memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData); printf("请输入ShellCode硬编码:\n"); printf("!!!特别注意:在输入硬编码后,应输入E8和该ShellCode执行时内存中的地址,程序会自动转换!!!暂时只支持输入100字节以内的硬编码\n"); for(i=0,j=0;i<100;i++){ scanf("%x ",ShellCode[i]); if(ShellCode[i]==0xE8){ j=i+1; } if(i=j+4){ CallShellCode=*(int*)(ShellCode[j]); CallShellCode = CallShellCode - (pOptionalHeader->ImageBase + pNewSectionHeader->VirtualAddress + j-1 + 5); *(int*)ShellCode[j] = CallShellCode; } if(i=j+9){ JmpShellCode = OddAddressOfEntryPoint - (pNewSectionHeader->VirtualAddress + j+5 + 5); *(int*)ShellCode[j+5] = JmpShellCode; } } memcpy((void*)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), ShellCode, sizeof(ShellCode)); FILE* fp=NULL; if((fp=(fopen("新增节程序.exe","wb")))==NULL){ printf("文件新建失败!\n"); exit(0); }else{ printf("文件新建成功,正在写入数据...\n"); if(fwrite(fp,SizeOfNewBuffer,1,NewFileBuffer)){ printf("数据写入成功。\n"); }else{ printf("数据写入失败!\n"); exit(0); } } free(NewFileBuffer); break; } } } //*****************************覆盖DOSstob,抬升NT头和原有节表**************************** //该函数需要一个指针,指向需要改动的FileBuffer //该函数将FileBuffer中的DOSstob覆盖 //该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 //抬升成功后会将最后两个节表的数据全初始化为0 //若头部抬升失败,则返回0 //若抬升成功,则返回1 //**************************************************************************************** int UpFile(char* FileBuffer){ PIMAGE_DOS_HEADER pDosHeader=NULL; PIMAGE_NT_HEADERS32 pNTHeader=NULL; PIMAGE_FILE_HEADER pFileHeader=NULL; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL; PIMAGE_SECTION_HEADER pSectionHeader=NULL; char* pNewSectionHeader=NULL; int i; pDosHeader=(PIMAGE_DOS_HEADER)((DWORD)FileBuffer); pNTHeader=(PIMAGE_NT_HEADERS32)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader); if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){ printf("检测到有效的PE标志。\n"); }else{ printf("未检测到有效的PE标志!\n"); return 0; } pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4); pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)FileBuffer+20); pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader); for(i=0;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){ printf("移动节表指针中...\n"); } pNewSectionHeader=pSectionHeader+1; if ((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER) - (DWORD)pNTHeader >= IMAGE_SIZEOF_SECTION_HEADER * 2) { printf("可抬升NT头\n抬升PE头部中...\n"); //开始拷贝,将NT头拷贝到DOS头结束之后,长度为NT头开始到最后一个节表结束时的长度,即pNewSectionHeader memcpy((void*)((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER)), pNTHeader, (DWORD)pNewSectionHeader - (DWORD)pNTHeader); //拷贝后重置e_lfanew位置 printf(" e_lfanew: %x\n", pDosHeader->e_lfanew); pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); printf("e_lfanew: %x\n", pDosHeader->e_lfanew); //抬升后更新所有被抬升的头指针 //NT头 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)FileBuffer + pDosHeader->e_lfanew); //PE头 pFileHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4); //NT头地址 + 4 为 FileHeader 首址 //可选PE头 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中 //首个节表 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); for(i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++) //注意这里i从1开始 i < NumberOfSections {} //出循环后pSectionHeader指向最后一个节表 pNewSectionHeader = pSectionHeader + 1; //验证代码,判断是否是有效的PE标志 if (*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) //基址pFileBuffer + lfanew 为 NTHeader首址 { printf("抬升后验证失败,不是有效的PE标志\n"); return ; } printf("抬升成功!\n"); //抬升成功后将最后一个节表后两个节表位置的空间置零 memset(pNewSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER * 2); } return 1; } //******************************计算文件对齐后的值函数************************************ //Align:计算对齐后的值 //参数说明: //x 需要进行对齐的值 //Alignment 对齐大小 //返回值说明: //返回x进行Alignment值对齐后的值 //**************************************************************************************** int Align(int x, int Alignment) { if (x%Alignment==0) { return x; } else { return (1 + (x / Alignment)) * Alignment; } }
main.c:
#include <stdio.h> #include "E:\个人\逆向\PEFunction.h" int main(int argc, char** argv) { printf("****** 欢迎PE新增节程序 ******\n"); printf("****** ******\n"); printf("****** -------版权所有:*****\n"); printf("****** https://blog.csdn.net/qq_73985089?type=sub&spm=1001.2014.3001.5348\n"); printf("****** 如需引用,请告知原作者!\n"); char filename[50]; char* FileBuffer=NULL; int sizeoffile=0; printf("请输入您要操作的文件路径:"); scanf("%s",filename); FileBuffer=ReadToFileBuffer(filename); sizeoffile=SizeOfFile(filename); AddNewSection(FileBuffer,sizeoffile); return 0; }