首页
社区
课程
招聘
[求助]PE程序怎样合并节
发表于: 2016-11-8 10:37 6019

[求助]PE程序怎样合并节

2016-11-8 10:37
6019
最近在学习PE结构,自己试着写了一个合并节的函数,但是生成的文件总是有问题。

在不模仿操作系统装载PE的情况下,在文件中怎么做到合并节。大家看看我写的这个函数有什么问题?或者能贴一份思路或代码,那就感激不尽了~
因为我把这个函数写进了一个类里面,所以可能有些成员的声明看不到,但从变量的字面意思应该可以看得懂。
(附加:自从学了PE之后,感觉对指针的理解又深了一层,现在有一种强迫症,定义空指针然后来回强转,放到以前根本不敢这么用

PVOID PE_Headers::CompressSection(IN PVOID File_Buffer)
{
        PVOID newbuff = NULL;
        PBYTE read = NULL, write = NULL;
        DWORD filesize = 0;
        DWORD i;
       
        if (File_Buffer == NULL)
        {
                Error_Flag |= EMPTY_IMAGEBUFFER;
                return FALSE;
        }

        filesize = pSection_Header[pPE_Header->NumberOfSections - 1].VirtualAddress
                + pSection_Header[pPE_Header->NumberOfSections - 1].SizeOfRawData;
        newbuff = malloc(filesize);
        memset(newbuff, 0, filesize);
       
        memcpy (newbuff, pDos_Header, pOptional_Header->SizeOfHeaders);
        for (i = 0; i < pPE_Header->NumberOfSections; i++)
        {
                read = (PBYTE) pDos_Header + pSection_Header[i].PointerToRawData;
                write = (PBYTE) newbuff + pSection_Header[i].VirtualAddress;

                if (i == 0)
                {
                        write = (PBYTE) newbuff + pSection_Header[i].PointerToRawData;
                }
                memcpy(write, read, pSection_Header[i].SizeOfRawData);
        }
       
       
        GetPEHeaders(newbuff);
       
        //合并后,virtualsize = ImageSize - 第一个节的偏移量(头的内存大小)
        pSection_Header->Misc.VirtualSize = pOptional_Header->SizeOfImage
                - pSection_Header->VirtualAddress;
       
        //合并后,sizeofrawdata = 最后节的内存偏移 + 最后节的文件大小 - 第一节的文件偏移量(头的大小)
        pSection_Header->SizeOfRawData = filesize - pSection_Header->PointerToRawData;

        for (i = 1; i < pPE_Header->NumberOfSections; i++)
        {
                pSection_Header->Characteristics |= pSection_Header[i].Characteristics;
                memset(&pSection_Header[i], 0, sizeof(IMAGE_SECTION_HEADER));
        }

        pPE_Header->NumberOfSections = 1;

        return newbuff;

}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 21
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好吧,我大致说明下类内的成员:
pSection_Header,一个指向节表的指针,(PIMAGE_SECTION_HEADER)类型
pOptional_Header, 指向optional header的结构体指针
pPE_Header, 一个指向IMAGE_FILE_HEADER的指针
pDos_Header, 指向DOS头指针

GetPEHeaders(newbuff)函数:把以上的指针赋值,
2016-11-8 11:22
0
雪    币: 64
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
用LordPE之类的看看新的EXE都有没有问题呗
2016-11-8 12:25
0
雪    币: 267
活跃值: (438)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
4
关健要使原始节rva=新pe文件的节文件偏移量!
2016-11-8 12:36
0
雪    币: 21
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
手头只有一个PE tool,分析了一下,发现并没有看出什么问题。但是改完的程序就是不能正常运行了。
2016-11-8 12:53
0
雪    币: 21
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
首先:对windows的peloader来说,最重要的是介个data_directory,section几乎没什么作用。。。只是为了内存映射方便而已,所以你合并节之后,最重要的是处理表。。比如导入导出,比如重定向表 还有tls表。。。
2016-11-8 13:21
0
雪    币: 21
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
刚才仔细想了下,这么做要处理的地方有点多。如果你的第一个节是代码段还好,如果不是 那就头疼了。像导入表和重定向。。会烦死
2016-11-8 13:27
0
雪    币: 21
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢大家的指导,问题已经解决了。

其实我这个合并节并不需要移动各种表,因为我是作为整体移动的,而且当节合并之后,加载到内存中的时候,节的RVA并不会有任何变化。之前我是用模拟加载PE的过程,把每个节经过拉伸,填补内存对齐。然后再合并节,这样并不会影响data_directory所记录的RVA。   

但是当我程序不模拟加载PE过程的时候,就出现了错误。因内存对齐和文件对齐参数的不同,没有把每个节的所应该的偏移量找准。

至于你们说的代码段和数据段的问题,  只要改动节表属性就行了。这个程序并不影响data_directory记录的RVA。   研究这个的主要原因还是当空闲空间不够添加一个节时,可以合并节之后再添加节。但势必会造成文件尺寸加大。比如我测试时用的windows 32位的笔记本程序,由原来的65k,变成了73k。因为内存对齐比文件对齐大的因素。合并节之后统一按照每个节的内存对齐(RVA)来直接存储到文件中。下面附上经修改后的代码

PVOID PE_Headers::CompressSection(IN PVOID File_Buffer)
{
        PVOID newbuff = NULL;
        PBYTE read = NULL, write = NULL;
        DWORD i;
       
        if (File_Buffer == NULL)
        {
                Error_Flag |= EMPTY_IMAGEBUFFER;
                return NULL;
        }
       
        //新生成的文件大小 = 最后节的RVA + 最后节的FOA - 头的RVA + 头的FOA
        File_Size = pSection_Header[pPE_Header->NumberOfSections - 1].VirtualAddress
                + pSection_Header[pPE_Header->NumberOfSections - 1].SizeOfRawData
                - pSection_Header->VirtualAddress + pSection_Header->PointerToRawData;               

        newbuff = malloc(File_Size);
        memset(newbuff, 0, File_Size);
       
        memcpy (newbuff, pDos_Header, pOptional_Header->SizeOfHeaders);                        //拷贝头部
        for (i = 0; i < pPE_Header->NumberOfSections; i++)
        {
                read = (PBYTE) pDos_Header + pSection_Header[i].PointerToRawData;
                write = (PBYTE) newbuff + pSection_Header[i].VirtualAddress
                        - pSection_Header->VirtualAddress + pSection_Header->PointerToRawData;        //因头部的RVA和FOA的不同产生的偏移量
                memcpy(write, read, pSection_Header[i].SizeOfRawData);                       
        }
       
        Release(File_Buffer);
        GetPEHeaders(newbuff);
       
        //合并后,virtualsize = 文件大小 - 头的文件大小
        pSection_Header->Misc.VirtualSize = File_Size - pSection_Header->PointerToRawData;
        pSection_Header->SizeOfRawData = File_Size - pSection_Header->PointerToRawData;

        for (i = 1; i < pPE_Header->NumberOfSections; i++)
        {
                pSection_Header->Characteristics |= pSection_Header[i].Characteristics;                //把每个节的节属性合并到第一个节里
                memset(&pSection_Header[i], 0, sizeof(IMAGE_SECTION_HEADER));                        //把原来节的数据置0,以便新增一个节
        }

        pPE_Header->NumberOfSections = 1;

        return newbuff;

}
2016-11-8 14:10
0
雪    币: 21
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
额,刚才没看清楚,你是直接将数据拷贝到RVA的文件偏移处(去除内存对齐的差值),但是这样文件大小会更大吧。。刚用pe工具随便看了一个文件最后一个节的RVA 是0x21900 而FOA为0x17a400。。。
2016-11-8 16:20
0
雪    币: 21
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
确实会使文件变大,但会把节表压缩,空出一堆零
2016-11-8 16:49
0
雪    币: 1214
活跃值: (53)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
我和你一样这样做,但是不知道为什么导入表这些都错了,你的实验成功了吗?
2019-2-16 17:50
0
游客
登录 | 注册 方可回帖
返回
//