本次实验内容是要在原来exe文件中新增一个节和一个节表,新增的节可以追加到文件末尾,新增的节表可以放到原有节表的后面,包括节表本身的40字节和40字节的0共80字节,为了防止原有节表后面空间不足,我们选择占用dos stub空间
步骤如下
1.先将原文件读取到内存buff1中
2.为新文件申请一个空间buff2 大小为原文件大小+新节的大小
3.将buff1中的内容全部复制到buff2,buff2后面就是新节的内容,默认给0 ,到此新增新节就完成了
4.将buff2中的PE、标准PE头、可选PE头、所有节表整体上移80字节,为了给新节表腾出空间
5.将buff1中第1个节表复制到buff2 腾出的空间中
6.修改buff2中新增节表的属性
6.1修改总节表数
6.2修改新增节的名称
6.3修改新增节在内存中大小【默认0x1000字节】
6.4修改新增节在内存中的偏移【根据上一节的偏移和大小计算(文件大小或者内存大小取较大的),结果要保持内存对齐】
6.5修改新增节在文件中的大小【默认0x1000字节】
6.6修改新增节在文件中的偏移【根据上一节的偏移和大小计算】
6.7修改sizeofimage大小
7.将buff2写入到新文件 生成新exe
代码如下
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "mycode.h"
// 文件 -> FileBuffer -> NewFileBuffer -> 文件
int main()
{
char* sourcefile="D:\\CODE\\t\\Debug\\t.exe";
char* targetfile="D:\\CODE\\t\\Debug\\t3.exe";
int newsecsize=0x1000; //新增节的大小
char* ptr=read_file_to_file_buffer(sourcefile);
PE filePE;
set_pe(ptr,&filePE);
//判断 节表空闲空间是否够40(节表数据)+40(0)=80个字节
//不够80字节 需要节表上移 占用dos stub 的空间
//我们这里按不够来处理 将新增的节表放到dos stub中
if( *filePE.p_e_lfanew >= 80 )
{
printf("dos stub 可以存放80字节 \n");
}
else
{
printf("dos stub 不可以存放80字节 \n");
return 0;
}
//要复制节表的开始、结束 地址 从PE开始
int source_sec_no=1; //节表编号
char* sec_table_begin = (char*)filePE.image_section_header_base + (source_sec_no-1)*40 ;
char* sec_table_end = (char*)filePE.image_section_header_base + (source_sec_no-1)*40 + 40 ;
char* pe_sig= filePE.p_signature;
printf("当前复制的节表为第%d节 节表的起始地址:%x 节表的结束地址:%x \n",source_sec_no,sec_table_begin - ptr,sec_table_end - ptr);
//为新文件申请空间 新文件大小为原文件大小+新增的节的大小
int sizeofp_newfilebuffer=get_file_size(sourcefile) + newsecsize ;
char* p_newfilebuffer = (char*) malloc(sizeofp_newfilebuffer);
if( p_newfilebuffer == NULL)
{
printf("空间不足\n");
return 0;
}
else
{
printf("Newfilebuffer地址:%x \n",p_newfilebuffer);
}
memset(p_newfilebuffer,0,sizeofp_newfilebuffer);
//将原文件先全部复制到新节
memcpy(p_newfilebuffer
,ptr
,get_file_size(sourcefile) );
PE newfilePE;
set_pe(p_newfilebuffer,&newfilePE);
//新增的节默认给0
memset( p_newfilebuffer + get_file_size(sourcefile) //目标位置为 文件的结束位置
,0
,newsecsize); //节大小
//复制节表
//修改e_lfanew 节表上移
*newfilePE.p_e_lfanew = *newfilePE.p_e_lfanew - 80;
//节表上移
memcpy( p_newfilebuffer + *newfilePE.p_e_lfanew
,ptr + *filePE.p_e_lfanew
,4+20 + *(filePE.p_sizeofoptionalheader) + *filePE.p_numberofsections*40 //PE、标准PE头、可选PE头、所有节表
);
//新增的节 复制到节表后面 包括节表本身40字节 和 40个0 的空字节 共80字节
memcpy(
// 文件开始位置 PE位置 PE大小 标准PE头大小 可选PE头大小 所有节大小
p_newfilebuffer + *newfilePE.p_e_lfanew + 4 + 20 + *(filePE.p_sizeofoptionalheader) + *filePE.p_numberofsections*40
,sec_table_begin
,40
);
memset(p_newfilebuffer + *newfilePE.p_e_lfanew + 4 + 20 + *(filePE.p_sizeofoptionalheader) + *filePE.p_numberofsections*40 + 40
,0
,40);
//刷新PE结构
set_pe(p_newfilebuffer,&newfilePE);
//节的数量加一
*newfilePE.p_numberofsections = *newfilePE.p_numberofsections+1;
//修改节属性
//修改节名
char newname[]="newsec";
memcpy(newfilePE.image_section_header_base + *filePE.p_numberofsections*40,newname,8);
//修改在内存中的大小
*(int*)((char*)newfilePE.pmisc + *filePE.p_numberofsections*40)= newsecsize;
//修改新增节的内存偏移 根据上一个节的偏移和大小计算
int finalsecmemsize= *(int*)((char*)newfilePE.pmisc + (*newfilePE.p_numberofsections-2)*40 ) > *(int*)((char*)newfilePE.psizeofrawdata+(*newfilePE.p_numberofsections-2)*40)
?
*(int*)((char*)newfilePE.pmisc + (*newfilePE.p_numberofsections-2)*40 ) : *(int*)((char*)newfilePE.psizeofrawdata+(*newfilePE.p_numberofsections-2)*40); //取内存大小和文件大小 较大的一个
int zhengshu =finalsecmemsize/(*newfilePE.p_sectionalignment) ;
int yushu = finalsecmemsize - zhengshu*(*newfilePE.p_sectionalignment);
int addsize = (*newfilePE.p_sectionalignment) - yushu; //根据内存对齐需要增加的大小 上一节内存偏移 上一节大小(内存大小或者文件大小) 补齐内存对齐
*(int*)((char*)newfilePE.pvirtualaddress + (*newfilePE.p_numberofsections-1)*40 ) = *(int*)((char*)newfilePE.pvirtualaddress + (*newfilePE.p_numberofsections-2)*40) + finalsecmemsize + addsize ; //上一个节的偏移+大小(这里的大小 要判断文件大小和内存大小哪个大 取较大的那个然后根据内存对齐)
//修改在文件中的大小
*(int*)((char*)newfilePE.psizeofrawdata + *filePE.p_numberofsections*40)= newsecsize;
//修改新增节的文件偏移 根据上一个节的偏移和大小计算 上一个节的偏移 上一个节的大小
*(int*)((char*)newfilePE.ppointertorawdata + (*newfilePE.p_numberofsections-1)*40 ) = *(int*)((char*)newfilePE.ppointertorawdata + (*newfilePE.p_numberofsections-2)*40 ) + *(int*)((char*)newfilePE.psizeofrawdata + (*newfilePE.p_numberofsections-2)*40 ) ;
//修改sizeofimage大小 增加一个节内存对齐后的大小
zhengshu = *(filePE.pmisc + (source_sec_no-1)*40)/(*newfilePE.p_sectionalignment);
yushu = *(filePE.pmisc + (source_sec_no-1)*40) - zhengshu * (*newfilePE.p_sectionalignment);
int finalimgmemsize = (*newfilePE.p_sectionalignment) - yushu;
*newfilePE.p_sizeofimage = *newfilePE.p_sizeofimage + *(filePE.pmisc + (source_sec_no-1)*40) + finalimgmemsize; //这里应该算内存对齐后的字节 所以要加finalimgmemsize
//将NewFileBuffer 中的内容写入到一个新的exe文件
trans_file_buffer_to_file(p_newfilebuffer,targetfile,sizeofp_newfilebuffer);
//释放内存
free(p_newfilebuffer);
p_newfilebuffer=NULL;
read_file_to_file_buffer_free(ptr);
return 0;
}
运行结果
原来exe的PE结构
.