扩大节、合并节

如果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;
}
合并节:
//失败了,先放着
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/ShiningArmor/p/11742162.html