欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]通过c++代码给PE文件添加一个区段

[原创]通过c++代码给PE文件添加一个区段

为什么要添加区段就不说了, 如果连理由都没有的话吧应该是不需要添加区段的. 怎么添加区段那是必须说的,这也是这个文章出现的原因.
添加区段:                               
首先得了解区段在PE文件中哪一个位置(从哪里来).
其次,要把区段添加到什么位置(到哪里去),
最后还需要清楚要添加的区段的区段名,大小,文件偏移,内存偏移(你是谁).
                                       
第一步 从哪里来                                
1. 区段一般都是有多个.
2. 区段内容的位置一般是在PE文件头部(对齐后)的末尾,
3. 每个区段描述表索引一个区段的内容,所以区段描述表是多个的,
   PE文件的区段描述表之于区段内容就像字典里的拼音之于字(请脑补使用拼音查找字的技术).
                                       
区段描述表(索引):
                                 
区段内容(索引到的内容):
                               
                                       
区段内容是通过区段描述表的DWORD PointerToRawDatz 字段索引到的.
IMAGE_SECTION_HEADER 结构
       

	BYTE	Name[IMAGE_SIZEOF_SHORT_NAME]	//区段名,长度8字节的ASCII字符串
	union 	Misc : 	;//区段大小,实际被使用的区段大小,即未被对齐之前的大小
	                DWORD??  PhysicalAddress
	                DWORD??  VirtualSize
	DWORD?? 	VirtualAddress	//此区段加载到内存后的RVA,按照内存页对齐
	DWORD	SizeOfRawData?	 //此区段在磁盘中的体积,按照文件页对齐
	DWORD?	PointerToRawData	//此区段在文件中的偏移
	DWORD?	PointerToRelocations	;//此区段重定位表的偏移(用于OBJ文件)
	DWORD?	PointerToLinenumbers	//行号表在文件中的偏移(用于调试)
	WORD??? 	NumberOfRelocations	//重定位表项数量(用于OBJ文件)
	WORD???	NumberOfLinenumbers	;//行号表项数量
	DWORD?	Characteristics	//区段属性值,具体的值和前面那张文件属性表相同
	

                                       
第二步 到哪里去                                
等待解决要到哪里去这个深奥的问题的有两个:
一. 区段描述表                               
二. 区段内容                                
                                               
1. 先说区段描述表, 区段描述表只能在PE扩展头末尾,PE头部的底部之前(文件对齐后的底部).                                
                               
区段描述表就像上图所示,是一个IMAGE_SECTION_HEADER结构的数组,数组的个数在PE文件头:IMAGE_FILE_HEADER NumberOfSections 有给出.数组以全零的结构结尾.
所以区段描述表要到哪里去呢,一般都是在最后一个区段表描述表后,就是那个以全零填充的结构那里.
2. 再说区段内容                                
PE文件是一个组织好的文件,就像一篇优美的小说,就像正常的作家,继续写作时一般都是在文件的末尾接着写,因为如果在中间插上一段,就意味着要把后续的内容改变.
PE文件是一个组织好的文件 , 如果在中间插上一个区段,想要不覆盖原先的内容,就要把原先的内容后移,那么后移的内容中涉及到地址操作的代码就不能用了,
因为代码操作的地址没有改变,比如 jmp 0x00400000,原先在地址0x00400000处的代码是mov eax,0 ,但是mov eax,0 已经被后移到0x004000001.
所以添加的区段要到哪里去呢,插入区段一般都是插入到文件末尾.
               
第三步 你是谁                                
先作一个小小的总结, 经过前两步,我们可以有了几个已知条件                                
1. 区段描述表和区段内容的关联                                
2. 添加一个区段描述表必须要在PE扩展头底部的区段描述表数组末尾
3. 区段的内容要添加到文件的末尾.
                                       
第三步主要是完善的一步 , 要完善的地方就是区段描述表.
                                       
1. 增加了几个区段,需要如实在IMAGE_FILE_HEADER NumberOfSection字段中记录.
2. 增加了多大的区段内容,需要如实在IMAGE_OPTION_HEADER SizeofImage 中如实记录.
|---1. SizeOfImage是经过内存粒度对齐的值, 所以如果你的区段的实际大小是200字节.那么你就需要先计算200的内存对齐粒度的值.
3. 区段描述表必须介绍区段内容在文件中的哪个位置,有多大,是什么属性,在内存中的RVA是 多少.
|---1. 在文件中的位置可以从最后一个区段描述表中获取. 新区段的文件偏移就是最后一个区段的文件偏移+区段大小 .
|---2. 新区段的RVA就是最后一个区段的RVA+按照内存粒度对齐后的区段大小
4. 将原来PE文件扩充,长度是原PE文件的字节数 + 新区段文件对齐后的字节数
|---1. 将原来的PE文件数据拷贝到新的内存中,
|---2. 将新内存写会文件.
5. 修改Misc.VirtualSize的大小为新区段实际大小按内存对齐后的值(这个我不是很清楚是否要修改成这样的值, 修改为实际大小时会形成不是有效的PE文件)
值得注意的地方是
1. 要记得改区段计数 IMAGE_FILE_HEADER.NumberOfSection
2. 要记得修改镜像大小,并且记得镜像大小是按内存粒度对齐的,修改前要注意 IMAGE_OPTION_HEADER.SizeofImage
3. 要记得添加区段描述表 IMAGE_SECTION_HEADER
4. 要记得修改区段描述表字段的值
   修改区段内容文件偏移PointerToRawData
   修改区段内存相对偏移VirtualAddress
   修改区段大小        SizeOfRawData
   修改Misc                           Misc.VirtualAddress
下面是代码 , 有一些函数宏和函数是自己封装的,另外删除区段的函数也有写,但是一个帖子放太多的内容不对排版不好,不过我提供了附件,附件中有全部的源码.       
代码 PEInfo.7z                          
PIMAGE_SECTION_HEADER	AddSection(_Inout_ LPBYTE& lpFile, // 通过ReadFile()获得的文件在内存指针
								   _Inout_ DWORD& dwSize, // 通过GetFileSize()获得的文件大小
								   const  TCHAR* pszName, // 新增区段名
								   DWORD	dwNameLen, // 新增区段名长度
								   DWORD	dwSecSize // 新增区段字节数
								   )
{
	//////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////
	// 获取nt头
	// 获取扩展nt头
	PIMAGE_FILE_HEADER		pFileNt = &(NTHEADER(lpFile))->FileHeader;
	PIMAGE_OPTIONAL_HEADER	pOptNt = NTOPTIONALHEADER(lpFile);
	// 获取对齐后的区段描述表对齐后的总大小
	DWORD	dwAligentSectionSize = pOptNt->SizeOfHeaders;
	// 得到所有区段描述表的实际占用字节数
	DWORD	dwLengthOfAllSection = pFileNt->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
	// 判断是否有空间容纳新的区段描述表
	if((dwLengthOfAllSection + sizeof(IMAGE_SECTION_HEADER) <= dwAligentSectionSize))
	{
		// 1. 修改PE标准文件头的Numberofsection +1 
		// 2. 修改PE扩展头的SizeofImage 增加一个内存对齐粒度
		// 3. 找打最后一个区段描述表
		//		3.1 修改Misc.Virtualaddress 为一个内存对齐粒度
		//		3.2	修改SizeOfRawData 0x200(实际大小文件对齐后的大小)
		//		3.3	修改PointerToRawData 为上一个PointerToRawData+Pointer +SizeOfRawData的位置
		//		3.3	修改VirtualAddress 为上一个VirtualAddress+SizeOfRawData 内存对齐后的位置
		// 有空间
		//在最后一个全段描述表末尾添加一个新的区段描述表
		PIMAGE_SECTION_HEADER	pNewSection = &(IMAGE_FIRST_SECTION(NTHEADER(lpFile))[pFileNt->NumberOfSections]);
		/// 修改新的区段的读数
		// 修改区段名
		WideCharToMultiByte(CP_ACP,0,
							pszName,dwNameLen,
							(char*)pNewSection->Name,dwNameLen,
							NULL,NULL);
		pNewSection->Name[dwNameLen] = 0;
		// 修改大小
		pNewSection->Misc.VirtualSize = size2AligentSize(dwSecSize,pOptNt->SectionAlignment);
		// 修改区段文件对齐后文件大小
		pNewSection->SizeOfRawData = size2AligentSize(dwSecSize,pOptNt->FileAlignment);
		// 修改区段的位置
		PIMAGE_SECTION_HEADER pOldSec = &(IMAGE_FIRST_SECTION(NTHEADER(lpFile))[pFileNt->NumberOfSections - 1]);
		pNewSection->PointerToRawData = pOldSec->PointerToRawData + pOldSec->SizeOfRawData;
		// 修改区段的RVA
		pNewSection->VirtualAddress = size2AligentSize(pOldSec->VirtualAddress + pOldSec->SizeOfRawData,pOptNt->SectionAlignment);
		// 增加一个区段描述表计数
		++pFileNt->NumberOfSections;
		// 增加映像大小为新增区段大小内存对齐后的大小
		pOptNt->SizeOfImage += size2AligentSize(dwSecSize,pOptNt->SectionAlignment);
		/// 申请空间追加新增的区段
		DWORD	dwSecAligSize = size2AligentSize(dwSecSize,pOptNt->FileAlignment);
		LPBYTE lpNewFile = new BYTE[dwSize + dwSecAligSize];
		//memset(lpNewFile,0,dwSize + dwSecAligSize);
		// 将原有内容拷贝回去
		memcpy_s(lpNewFile,dwSize + dwSecAligSize,lpFile,dwSize);
		memset(lpNewFile + dwSize,0,dwSecAligSize); // 以0填充
		delete[]	lpFile;
		lpFile = lpNewFile;
		dwSize += dwSecSize;
		return pNewSection;
	}
	return	NULL;
}

上传的附件 PE头.png
PEInfo.7z
区段描述表位置.png
区段内容.png

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功