扩大节、合并节
如果pe头部没有足够的空间插入一个新的节表,可以考虑扩大最后一个节;
注意是最后一个节,如果扩大中间的节,很可能造成后面的节整体偏移而找不到;
1.扩大节的大概步骤
1】读取文件到缓冲区;
2】拉伸文件镜像;
3】分配一个新的空间:SizeOfImage + Ex;
4】修改最后一个节表的数据:
SizeOfRawData = Misc.VirtualSize = N; ->因为无法确定这两个数哪个大
N = (SizeOfRawData或VirtualSize内存对齐后的值) + Ex;
5】修改SizeOfImage的大小;
7】压缩、存盘
2.用代码实现扩大节
#include "stdafx.h"
#include "petool.h"
#include "string.h"
#define SRC "C:\\Users\\Administrator\\Desktop\\TraceMe.exe"
#define DEST "C:\\Users\\Administrator\\Desktop\\copy1.exe"
//扩大最后一个节
void lastSecInc(){
//定义头结构指针
PIMAGE_DOS_HEADER dosHeader = NULL; //dos头指针
PIMAGE_FILE_HEADER peHeader = NULL; //pe头指针
PIMAGE_OPTIONAL_HEADER32 opHeader = NULL; //可选pe头指针
PIMAGE_SECTION_HEADER seHeader = NULL; //节表指针
PIMAGE_SECTION_HEADER lastSeHeader = NULL; //最后一个节表指针
LPVOID pFileBuffer = NULL;
//1.加载文件到内存
DWORD size = ReadPEFile(SRC, &pFileBuffer);
if(!pFileBuffer){
printf("读取文件失败\n");
return;
}
//2.拉伸文件镜像
LPVOID pImageBuffer = NULL;
DWORD imageSize = CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
if(!imageSize){
printf("拉伸文件失败\n");
free(pFileBuffer);
return;
}
//4.扩大内存镜像
LPVOID newImageBuffer = NULL;
DWORD newImageSize = imageSize + 0x1000; //目标文件的内存对齐是1000文件对齐是200,就扩大1000正好为两个数的整数倍
newImageBuffer = malloc(newImageSize);
if(! newImageBuffer){
printf("给扩大后的内存镜像申请内存失败\n");
free(pFileBuffer);
free(pImageBuffer);
return;
}
//初始化内存空间
memset(newImageBuffer, 0, newImageSize);
//复制内存镜像到新的空间
memcpy(newImageBuffer, pImageBuffer, imageSize);
//4.初始化头指针
dosHeader = (PIMAGE_DOS_HEADER) newImageBuffer;
peHeader = (PIMAGE_FILE_HEADER)((DWORD)newImageBuffer + dosHeader->e_lfanew + 4);
opHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
seHeader = (PIMAGE_SECTION_HEADER)((DWORD)opHeader + peHeader->SizeOfOptionalHeader);
//5.修改头部信息
//修改节表信息
lastSeHeader = seHeader + (peHeader->NumberOfSections - 1);
lastSeHeader->Misc.VirtualSize = lastSeHeader->Misc.VirtualSize + 0x1000;
lastSeHeader->SizeOfRawData = lastSeHeader->SizeOfRawData + 0x1000;
//修改SizeOfImage
opHeader->SizeOfImage = opHeader->SizeOfImage+0x1000;
//6.压缩新内存镜像
LPVOID newBuffer = NULL;
DWORD newBufferSize = CopyImageBufferToNewBuffer(newImageBuffer, &newBuffer);
if(!newBufferSize){
printf("压缩新内存镜像失败\n");
free(pFileBuffer);
free(pImageBuffer);
free(newImageBuffer);
return;
}
//7.写出文件
BOOL isOk = MemeryTOFile(newBuffer, newBufferSize, DEST);
if(!isOk){
printf("存盘失败\n");
}else{
printf("存盘成功\n");
}
//8.释放内存
free(pFileBuffer);
free(pImageBuffer);
free(newImageBuffer);
free(newBuffer);
return;
}
int main(int argc, char* argv[])
{
lastSecInc();
getchar();
return 0;
}
3.合并节
合并节是将多个节合并;
例如所有节合并为一个节:
1】只保留一个节表;
2】所有的节当作一个节,将描述信息写在第一个节表中;
意义:
合并节后,原来节表的地方空出来了,可以方便插入新节;
有多个节时,拉伸时需要循环遍历各个节表做对齐之类的操作;合并节表后减少了这些操作;
影响:文件可能变大;
步骤:
1)拉伸到内存
2)将第一个节的内存大小、文件大小改成一样
Max = SizeOfRawData>VirtualSize?SizeOfRawData:VirtualSize
SizeOfRawData = VirtualSize = 最后一个节的VirtualAddress + Max - SizeOfHeaders内存对齐后的大小
3)将第一个节的属性改为包含所有节的属性
4)修改节的数量为1
4.程序实现合并节
内存对齐的工具方法:
//对齐
DWORD align(int size, int fileSize){
//如果尺寸小于对齐尺寸则按对齐尺寸算
if(size <= fileSize){
return fileSize;
}
//向上取整*对齐尺寸的倍数
int n = size%fileSize;
if(n == 0){
n = size/fileSize;
}else{
n = seze/fileSize + 1;
}
return n*fileSize;
}
合并节:
//失败了,先放着