准备工作:
1、判断是否有足够的空间可以添加一个节表.
判断条件:SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小
2、需要修改的数据
- 添加一个新的节(可以copy一份)
- 在新增节后面 填充一个节大小的000
- 修改PE头中节的数量
- 修改sizeOfImage的大小
- 再原有数据的最后,新增一个节的数据(内存对齐的整数倍).
- 修正新增节表的属性
手动实现:
复制一个exe程序(本文复制IPMSG.exe)用于实验,用010打开,找到节表信息,发现有4个节,且发现节表后面的空白区足够放下代码。为了使得添加完代码后的程序具有可执行的特征,选择复制第一个节点的所有信息(40个字节),复制到最后一个节点后面:
假设在新的节中添加4096个字节。
修改节的数量:
修改SizeOfImage(原始值为0022B000)为0022C000
插入4096个字节的内容,在文件末尾:
修改添加节点的成员信息:
Name:改为tttt
VirtualSize:直接改成在文件中对齐后的长度1000
VirtualAddress:等于SizeOfImage修改前的大小
SizeOfRawData:1000
PointerToRawData:用上一个节点的PointerToRawData+SizeOfRawData = 22 2200
Characteristics:无需修改
保持后打开文件,能够正常打开,说明添加节点成功。
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#include <memory.h>
int GetFilesize(FILE* fptr);
char* ReadFilea(const char* Filepath);
void addSection(char* Filepath) {
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
char* pFileBuffer = ReadFilea(Filepath);
if(!pFileBuffer) {
printf("读取文件失败");
return;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)(pFileBuffer + (pDosHeader->e_lfanew));
pPEHeader = (PIMAGE_FILE_HEADER)(pFileBuffer + (pDosHeader->e_lfanew) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)(pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
DWORD restSpace = pOptionHeader->SizeOfHeaders - ((uintptr_t)pSectionHeader + pPEHeader->NumberOfSections - (uintptr_t)pFileBuffer);
if(restSpace < 80) {
printf("剩余空间不够");
return;
}
PIMAGE_SECTION_HEADER new_pSectionHeader = pSectionHeader + pPEHeader->NumberOfSections;
//修改添加节点的成员信息:
//Name:改为tttt
strcpy((char*)new_pSectionHeader->Name,".tttt");
//VirtualSize:直接改成在文件中对齐后的长度1000
new_pSectionHeader->Misc.VirtualSize = 0x1000;
//VirtualAddress:等于SizeOfImage修改前的大小
new_pSectionHeader->VirtualAddress = pOptionHeader->SizeOfImage;
//SizeOfRawData:1000
new_pSectionHeader->SizeOfRawData = 0x1000;
//PointerToRawData:用上一个节点的PointerToRawData+SizeOfRawData = 22 2200
new_pSectionHeader->PointerToRawData = (new_pSectionHeader-1)->PointerToRawData + (new_pSectionHeader-1)->SizeOfRawData;
//Characteristics:无需修改
new_pSectionHeader->Characteristics = pSectionHeader->Characteristics;
//插入全0的节表
LPVOID new_sectionBegin = LPVOID(new_pSectionHeader + 1);
memset(new_sectionBegin,0,40);
//修改节的数量
pPEHeader->NumberOfSections += 1;
//修改SizeOfImage(插入4096个字节)
pOptionHeader->SizeOfImage += 0x1000;
//写回文件
FILE* nFp1;
nFp1 = fopen("D:\\ipmsg\\IPMsg_2_3.exe", "rb");
int size_file = GetFileszie(nFp1);
fclose(nFp1);
nFp1 = fopen("D:\\ipmsg\\IPMsgnew_2_3.exe", "wb");
if(!nFp1) {
printf("打开写出文件失败\n");
free(pFileBuffer);
return ;
}
//把修改完的写回去
fwrite(pFileBuffer, size_file, 1, nFp1);
//新节表填充
LPVOID new_Buffer = malloc(0x1000);
if(!new_Buffer) {
printf("给新结点申请空间失败");
free(pFileBuffer);
return;
}
memset(new_Buffer,0,0x1000);
fwrite(new_Buffer,0x1000,1,nFp1);
fclose(nFp1);
free(new_Buffer); free(pFileBuffer);
new_Buffer = NULL; pFileBuffer = NULL;
}
char* ReadFilea(const char *Filepath) {
FILE* fptr = NULL;
fptr = fopen(Filepath,"rb");
if(!fptr) {
printf("打开失败");
return NULL;
}
int filesize = 0;
filesize = GetFilesize(fptr);
if (filesize == 0) {
printf("获取文件大小失败");
return NULL;
}
char* FileBuffer = (char*)malloc(filesize);
if(!FileBuffer) {
printf("开辟空间失败");
return NULL;
}
size_t n=fread(FileBuffer, 1, filesize, fptr);//将文件内容读到内存中
if(!n) {
printf("读取数据失败");
free(FileBuffer);
FileBuffer = NULL;
fclose(fptr);
return NULL;
}
fclose(fptr);
return FileBuffer;
}
int GetFilesize(FILE* fptr) {
int num = 0;
fseek(fptr, 0, SEEK_END);
num = ftell(fptr);
fseek(fptr, 0, SEEK_SET);
return num;
}
int main() {
char* path = (char*)"D:\\ipmsg\\IPMsg_2_3.exe";
addSection(path);
return 0;
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com