一、流程
1、打开文件
2、将文件读取到缓冲区
3、判断空闲区是否有足够的空间存储一个新节
4、将NT头到节表往上提
5、新增一个节表
6、修改节表名
7、修改内存中的偏移地址
8、修改新增的节在文件中对齐的大小
9、修改新增节的真实大小
10、修改新增节在文件中的偏移
11、修改新增节属性(可执行)
12、修改节表的数量
13、修改程序在内存中的大小
14、在新增节表后面添加1个节表的0
15、存盘
二、 完整代码
#include "stdafx.h"
#include <windows.h>
#include "stdlib.h"
#define FILEPATH_IN "C:/notepad.exe"
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer )
{
FILE *pFile = NULL;
DWORD fileSize = 0; //文件大小
LPVOID pTempFileBuffer = NULL; //缓冲区首地址
pFile = fopen(lpszFile,"rb"); //打开文件
if(!pFile)
{
printf("打开文件失败");
return NULL;
}
//读取文件大小
fseek(pFile,0,SEEK_END); //将指针从开始的位置移动到末尾
fileSize = ftell(pFile); //获取数据大小
//分配缓冲区(申请内存)
pTempFileBuffer = malloc(fileSize);
if(!pTempFileBuffer)
{
printf("分配空间失败");
fclose(pFile);
return NULL;
}
//将文件数据读取到缓冲区
fseek(pFile,0,SEEK_SET); //将指针指向开始
size_t n = fread(pTempFileBuffer,fileSize,1,pFile); //将数据读取到缓冲区中
if(!n)
{
printf("读取数据失败");
free(pTempFileBuffer); //释放内存
pTempFileBuffer = NULL;
fclose(pFile); //关闭文件
return NULL;
}
//关闭文件
*pFileBuffer = pTempFileBuffer;
pTempFileBuffer = NULL;
fclose(pFile); //关闭文件
return fileSize;
}
//**********************************************************************
BOOL MemeryTOFile(LPVOID pMemBuffer,size_t size)
{
FILE *fp = NULL;
fp = fopen("C:/copyxx1.exe","wb");
if(!fp)
{
return FALSE;
}
fwrite(pMemBuffer,size,1,fp); //向磁盘写入数据
fclose(fp); //关闭文件
fp = NULL;
return TRUE;
}
//**********************************************************************
BOOL AddSection()
{
DWORD Size = 0; //用来接收数据大小
BOOL isok = FALSE; //用来接收写入磁盘是否成功
LPVOID pFileBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL; //用来接收DOS头信息
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_SECTION_HEADER pNewSec = NULL; //新节表结构
//File-> FileBuffer
Size = ReadPEFile(FILEPATH_IN,&pFileBuffer); //调用函数读取文件数据
if(!pFileBuffer || !Size)
{
printf("File-> FileBuffer失败");
return FALSE;
}
//DOS头地址
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x4);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
if((DWORD)pNTHeader - (DWORD)(pDosHeader->e_lfanew) < sizeof(IMAGE_SECTION_HEADER))
{
printf("没有多余空间");
free(pFileBuffer);
return FALSE;
}
memcpy((void*)((DWORD)pDosHeader + 0x40),
pNTHeader,
(DWORD)(pSectionHeader + pPEHeader->NumberOfSections) - (DWORD)pNTHeader);
pDosHeader->e_lfanew = 0x40;
//DOS头地址
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x4);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//新增节表结构
pNewSec = (PIMAGE_SECTION_HEADER)(pSectionHeader + pPEHeader->NumberOfSections);
//修改节表内容
memcpy(pNewSec->Name,".export",8);//修改节表名
PIMAGE_SECTION_HEADER upSecHeader = (PIMAGE_SECTION_HEADER)(pSectionHeader + pPEHeader->NumberOfSections-1);
if(upSecHeader->Misc.VirtualSize > upSecHeader->SizeOfRawData) //修改节表VrituallAddress
{
pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->Misc.VirtualSize;
}else{
pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->SizeOfRawData;
}
pNewSec->SizeOfRawData = pOptionHeader->FileAlignment;//新增的节区的大小
pNewSec->Misc.VirtualSize = pOptionHeader->FileAlignment;
pNewSec->PointerToRawData = upSecHeader->PointerToRawData + upSecHeader->SizeOfRawData;//文件中的偏移
pNewSec->Characteristics = 0x60000020;//修改属性(可执行)
//在新增节表后增加40个字节的空白区
memset(pNewSec+1, 0, sizeof(IMAGE_SECTION_HEADER));
pPEHeader->NumberOfSections += 1;//修改NumberOfSection数量
pOptionHeader->SizeOfImage += pOptionHeader->SectionAlignment;//修改SizeOfImage大小
isok = MemeryTOFile(pFileBuffer,Size+pOptionHeader->FileAlignment);
if(isok)
{
printf("存盘成功");
return true;
}
//释放内存
free(pFileBuffer);
pFileBuffer = NULL;
return 0;
}
//**********************************************************************
int main(int argc, char* argv[])
{
AddSection();
getchar();
return 0;
}