手工解析PE(新增节)

手工解析PE(新增节),第1张

本次实验内容是要在原来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 
#include 
#include 
#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结构

.

 

 新增节之后exe的PE结构

新增节后,程序仍可以正常运行

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1498202.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-25
下一篇 2022-06-25

发表评论

登录后才能评论

评论列表(0条)

保存