首页
社区
课程
招聘
[原创]学写压缩壳心得系列之四 实践流程,云开见日
发表于: 2012-2-24 01:30 14472

[原创]学写压缩壳心得系列之四 实践流程,云开见日

2012-2-24 01:30
14472

1.数据与指令,以及加载前期相关概念(已完成)
2.pe文件的结构解析(已完成)
3.pe文件load的过程(已完成)
4.壳的处理(已完成)

我们要了解压缩壳处理PE的方式,即是要按照正常的方式载入PE,然后在内存中进行各个操作,完成后写回磁盘中,下图简单的表述了这个过程:


加载待压缩PE文件

壳在模拟系统修改pe文件的时候,有两种方式:

1.直接读取文件,按照各个结构进行拷贝。这里存在一个问题,也是第一篇中介绍过的,磁盘文件的对齐粒度和内存文件对齐粒度不一样。而在PE文件中,各个数据结构依赖于偏移的定位,而相对偏移恰恰是内存中相对基址的偏移,存在一个对齐粒度的转换。第一篇中也提供了文件偏移转内存偏移的函数,在定位各个结构之前,需要调用此函数来转换指定偏移。

2.直接模拟系统loader装载的方法。类似于第三篇中前面部分介绍过系统装载的方法。在一段内存空间内,依此读取pe各个部分的结构,按照各个结构所给定要加载到内存中的偏移,填充的偏移指定的内存处。这样直接的填充方法就避免了文件偏移转换内存偏移,清晰直观。在模拟系统装载的时候,也需要用到一个对其粒度函数的转换。与方式1中的不同,这个转换仅仅是为了填充因为对其粒度与实际大小之间的空隙,满足实际pe装进内存大小的填充。

AlignmentNum(DWORD address, DWORD Alignment)
{
	int align = address % Alignment;
        return address + Alignment - align;
}

获取目标文件hFile和NT头NtHeader后,要模拟装载PE,首先要知道目标PE头中的下列参数:

DWORD MemAlignment = NtHeader.OptionalHeader.SectionAlignment;//内存对其粒度
DWORD FileAlignment = NtHeader.OptionalHeader.FileAlignment;//磁盘内存对其粒度
DWORD PeSize = AlignmentNum(NtHeader.OptionalHeader.ImageBase, MemAlignment);//载入总大小

根据之前获得经过内存对其的总大小,可以开辟空间
char *pMemPointer = (char *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, PeSize);
DWORD SecNum = NtHeader.FileHeader.NumberOfSections;//读取节数目

DWORD SizeOfHeader = NtHeader.OptionalHeader.SizeOfHeader;//读取PE头大小
ReadFile(hFile, pMemPointer, SizeOfHeader, NULL, NULL);//从文件读取PE头

获取的了节表头pSectionHeader后,就可以进行装载了。

for (i = 0; i < SecNum; i++)
	{
		//定位文件第一个节磁盘偏移处
		SetFilePointer(hFile, pSectionHeader.PointerToRawData , NULL, FILE_BEGIN);
		//读取整个节内存,并转换到内存对其粒度
		ReadFile(hFile, (char *)pMemPointer + AlignmentNum(pSectionHeader.VirtualAddress, MemAlignment), pSectionHeader.SizeOfRawData, NULL, NULL);
                //读取完之后转到下一个节表
		pSectionHeader++;
	}
//保存重定位表的原始数据
if(NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > 0 )
{
    IsRESOURCE == TURE;
    DWORD BASERELOC_VA = Headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
    DWORD BASERELOC_SIZE = Headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
}
//清空重定位表目录
NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
//保存原始PE资源目录表的信息
if(NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > 0 )
{
    IsRESOURCE == TURE;
    DWORD RESOURCE_VA = NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
    DWORD RESOURCE_SIZE = NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
}
//这里保存要原始资源目录的VA和SIZE,载入内存之后,不进行处理,直接copy到压缩数据节之后。
//pSource压缩源,lInLength数据的大小,lOutLenght判断宏
Compress(PVOID pSource, long lInLength, OUT long &lOutLenght)
{
        //packed保存压缩数据的空间,workmem为完成压缩需要使用的空间
	BYTE *packed, *workmem;
	if ((packed  = (BYTE *) malloc(aP_max_packed_size(lInLength))) == NULL ||
		(workmem = (BYTE *) malloc(aP_workmem_size(lInLength)))    == NULL)
	{
		return NULL;
	}
        //调用aP_pack压缩函数
	lOutLenght = aP_pack(pSource, packed, lInLength, workmem, NULL, NULL);
	if (lOutLenght == APLIB_ERROR)
	{
		return NULL;
	}
	if (NULL != workmem)
	{
		free(workmem);
		workmem = NULL;
	}
	return packed;//返回保存地址
}
[B]区段的处理[/B]
为了保存各个压缩区段的信息,可以定义一个结构体,保存压缩区段信息
typedef struct _CompessSection
{
	DWORD VA;
	DWORD CompessVA;
	DWORD CompessSize;//
	LPVOID lpCompessData;//
}CompessSection, *PCompessSection;

首先,要提取出不能压缩的区段,然后根据之前压缩壳的构建,确定要压缩区段写入的地址,应该是紧接在占位区间之后。这里全局变量pMemPointer为之前获得的载入内存基址。
//PeSectionHeader此时指向占位区段最后一个节首地址
DWORD LastSecRva = PeSectionHeader.VirtualAddress;
//最后一个节经过内存对齐后的大小
DWORD LastSecSize = AlignmentNum(pPeSectionHeader[m_iSecNum-1].Misc.VirtualSize, 
		MemAlignment);
//获得区段压缩后保存的地址
DWORD CompressRva = LastSecRva + LastSecSize;
//获取要压缩区段数
DWORD CompressSecNum = SecNum;
//如果存在资源区段,则不压缩这个区段,被压缩区段数减1
if (IsRESOURCE == TURE)  
	{
		CompressSecNum --;
	}

	//配置压缩信息
	m_pComSec = new CompessSection[CompressSecNum];
	int iPos = 0;
	int j = 0;
	for (unsigned int i = 0; i < SecNum; i++)
	{
		//跳过资源目录和重定位目录
		if (i == 2 )
		{
			iPos++;
			continue;
		}
		else  
		{
			if (mPeSectionHeader[iPos].SizeOfRawData == 0)
			{   //空节不压缩
				iPos++;
				continue;
			}
			long lCompressSize = 0;
			PVOID pCompressData;
			PVOID pInData = (BYTE *)pMemPointer + PeSectionHeader[iPos].VirtualAddress;
                        //调用Compress函数
			pCompressData = Compress(pInData, 
				PeSectionHeader[iPos].Misc.VirtualSize,
				lCompressSize);
			//压缩数据指针
			m_pComSec[j].lpCompessData = pCompressData;
			//解压后内存地址
			m_pComSec[j].VA = PeSectionHeader[iPos].VirtualAddress;
			//压缩数据加载后的内存地址
			m_pComSec[j].CompessVA = CompressRva;
			//压缩数据大小
			m_pComSec[j].CompessSize = CompressSize;
			//下一个节压缩数据加载的地址
			iCompressRva += AlignmentNum(CompressSize, MemAlignment);
			iPos++;
			j++;
		}
	}
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 6
支持
分享
最新回复 (17)
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
我来顶一下,睡觉去。。呵呵
2012-2-24 01:37
0
雪    币: 408
活跃值: (156)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
3
呵呵,嗯,时间不早了,注意身体呀:)
2012-2-24 01:51
0
雪    币: 602
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
这个要顶 备用 压缩壳
2012-2-24 05:51
0
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
5
拔云见日~~~
2012-2-24 10:01
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
拔云见日~~~
2012-2-24 11:44
0
雪    币: 1149
活跃值: (888)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
7
能动手 写出来 和 讲出来 我就觉得 挺不错的....
2012-2-24 13:35
0
雪    币: 22
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
顶,忙完了手上的活在来看。
2012-2-24 13:44
0
雪    币: 2362
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
顶一个
2012-2-24 13:47
0
雪    币: 91
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
值得好好学习学习,顶
2012-2-24 16:10
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
拔云见日~~~
2012-2-24 17:28
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
12
来顶下
2012-2-25 09:54
0
雪    币: 563
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
收下慢慢看
2012-2-25 20:06
0
雪    币: 129
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
2012-2-26 20:17
0
雪    币: 1737
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
真不赖啊,我什么时候能到这个地步呢~
2012-3-3 09:37
0
雪    币: 237
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
markkkkkkkkk
2012-3-6 08:35
0
雪    币: 124
活跃值: (43)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
17
mark 真心不错
2012-3-7 17:50
0
雪    币: 870
活跃值: (2264)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
学习一下~
2018-9-25 19:23
0
游客
登录 | 注册 方可回帖
返回
//