首页
社区
课程
招聘
[原创]我写的一个压缩壳
发表于: 2013-1-17 23:55 32478

[原创]我写的一个压缩壳

2013-1-17 23:55
32478

VC6写的一个简单的压缩壳,我把我的心得体会分享给大家.
因为本人的水平有限,很多东西都是靠自己的理解来实现的,其中错误难免,拍砖、喷我,我都能Hold住,
但是一定要指出来,我会及时修正,因为我不想让文中的错误传遍互联网,祸害大家.

大致思路:
把被加壳程序的所有区段,放到压缩后放到第一个区段,资源和TLS段我选择不压缩,就直接拷贝到后面的
段中,添加一个shell段来做引导,解压压缩过的所有区段

结构为:
.oldDat
.shell
.rsrc(如果有的话)
.tls(如果有的话)
.info(一些shell用到的必要信息)

实现起来有几点要注意的地方:
1.为什么那么多壳都是选择把被加壳程序的区段放到第一个区段?,因为不放入第一个区段,变相的相当
于更改了ImageBase,导入被加壳程序用到的全局数据偏移都要修正,并且EXE基本上没有重定位表,这时
解决方法,需要特征码扫描被加壳程序需要重定位的数据偏移,在shell引导程序中修正偏移,
首先构造重定位表已经很累很难了,再者就是增加shell代码, 不过写loader应该是必须要做的(当然不
排除你能申请到你想要的ImageBase),第二种解决方法是修正EXE的ImageBase, 我就直接放到第一区段
了,何必麻烦呢

2.资源段的处理:资源段我选择全部不压缩,当然也可以压缩运行后才需要到的资源数据,但是感觉太麻
烦了(自己太菜-_-), 把资源段放到后面需要注意,要修正数据目录的RVA,并且资源的结构是三层目录结
构,要修正最后一层数据RVA

3.TLS的处理:TLS需要拷贝到后面区段,同时修正数据目录的RVA, 当TLS有回调函数时, 则shell解压数
据后,首先调用TLS回调函数,然后再跳到OEP,TLS还有个要处理的是.TLS区段有可能包含全局数据,所以
shell需要把TLS区段再拷贝到原始地方,以便被加壳程序能正确引用

4.被加壳程序的导入表处理:我的做法把他的导入表清空,区段也清除,当运行加壳后的程序使用shell
来填写原始IAT即可, 而应用程序加载后,即使没有导入表也是默认加载ntdll和kernel32(有了这两个,
飞机都能造了),当然最后一个面临问题就是shell用的Api的怎么填写, 就是我们写的程序,事先把
dll的IAT写入shell要用的api即可,这样就事先了,加壳后的程序没有导入表也可正常运行

5.shell用什么来写:可以考虑用exe,但是首选是dll,因为dll默认会有重定位表,上面说到生成后的程序
的基址与被加壳程序的基址一致是最方便的做法, 而dll又有重定位表, 只需要修正dll的重定位地址即


具体实现:
注:
文中的m_TargetPeTag,m_ShellPeTag,m_PressPeTag
分别是被加壳程序,dll写的shell,要生成的加壳程序
我用结构体成员管理了内存映射文件的句柄和地址,方便最后释放资源

首先用个数组保存被加壳程序区段信息,以及区段内容.以便后面查找和压缩用
判断被加壳程序是否有资源段和tls段,有的话,把区段信息设置为不压缩

	//保存被压缩PE的区段信息
	StorePressSecInfo();

	//被压缩程序的TLS和资源区段要保持不变 首先判断是否有TLS表和资源表
	DWORD dwResRVA = m_TargetPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
	DWORD dwTLSRVA = m_TargetPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress;
	MySecInfo* lpResSecInfo = NULL;
	if (dwResRVA != 0)
	{
		lpResSecInfo = GetSecInfoByRVA(dwResRVA, m_TargetPeTag.m_lpNtHeader-

>OptionalHeader.SectionAlignment);
		//资源段不压缩
		lpResSecInfo->m_isNeedPress = false;
	}

	MySecInfo* lpTLSSecInfo = NULL;
	if (dwTLSRVA != 0)
	{
		lpTLSSecInfo = GetSecInfoByRVA(dwTLSRVA, m_TargetPeTag.m_lpNtHeader-

>OptionalHeader.SectionAlignment);
		//TLS段不压缩
		lpTLSSecInfo->m_isNeedPress = false;
	}
	//获得被压缩PE的所有区段文件大小和(去除不能压缩的资源,TLS)
	DWORD dwPressSize = GetPressSize();

	//申请要压缩数据的空间
	char* lpSrcData = new char[dwPressSize];
	if (lpSrcData == NULL)
	{
		AfxMessageBox("new Error");
		return false;
	}
	RtlZeroMemory(lpSrcData, dwPressSize);

	//拷贝要压缩的数据
	CopyPressData(lpSrcData);

        //aplib压缩数据
        DWORD dwAfterPressSize = MyCompress(lpSrcData, &m_lpPressData, dwPressSize);

        if (dwAfterPressSize == APLIB_ERROR)
	{
		if (lpSrcData != NULL)
		{
			delete[] lpSrcData;
		}	
		return false;
	}

        
	DWORD dwFileAlign = m_TargetPeTag.m_lpNtHeader->OptionalHeader.FileAlignment;
	DWORD dwResFileSize = 0;
	if (lpResSecInfo != NULL)
	{
		dwResFileSize = Align(dwFileAlign, lpResSecInfo-

>m_SecHeader.SizeOfRawData);
	}
	DWORD dwTlsFileSize = 0;
	if (lpTLSSecInfo != NULL)
	{
		dwTlsFileSize = Align(dwFileAlign, lpTLSSecInfo-

>m_SecHeader.SizeOfRawData);
	}

	DWORD dwFileSize = m_TargetPeTag.m_lpNtHeader->OptionalHeader.SizeOfHeaders +
						Align(dwFileAlign, dwAfterPressSize) + 

Align(dwFileAlign, m_ShellPeTag.m_lpNtHeader->OptionalHeader.SizeOfCode) +
						dwResFileSize + dwTlsFileSize + 

dwFileAlign;
	//拷贝PE头
	memcpy(m_PressPeTag.m_FileMapTag.m_lpFileData,
		m_TargetPeTag.m_FileMapTag.m_lpFileData, 
		m_TargetPeTag.m_lpNtHeader->OptionalHeader.SizeOfHeaders);
	
	m_PressPeTag.m_lpDosHeader =(IMAGE_DOS_HEADER*)

m_PressPeTag.m_FileMapTag.m_lpFileData;
	m_PressPeTag.m_lpNtHeader = (IMAGE_NT_HEADERS*)

(m_PressPeTag.m_FileMapTag.m_lpFileData + m_PressPeTag.m_lpDosHeader->e_lfanew);
	
	//生成程序的映像大小 = pe头 + 被压缩PE镜像大小 + .shell + rsrc + tls + info
	DWORD dwSecAlign = m_PressPeTag.m_lpNtHeader->OptionalHeader.SectionAlignment;
	DWORD dwResSize = 0;
	if (lpResSecInfo != NULL)
	{
		dwResSize = Align(dwSecAlign, lpResSecInfo->m_SecHeader.SizeOfRawData);
	}
	DWORD dwTlsSize = 0;
	if (lpTLSSecInfo != NULL)
	{
		dwTlsSize = Align(dwSecAlign, lpTLSSecInfo->m_SecHeader.SizeOfRawData);
	}
	
	DWORD dwImageSize = Align(dwSecAlign, m_PressPeTag.m_lpNtHeader-

>OptionalHeader.SizeOfHeaders) +
		dwTargetImageSize + Align(dwSecAlign, m_ShellPeTag.m_lpNtHeader-

>OptionalHeader.SizeOfCode) +
		dwResSize + dwTlsSize + Align(dwSecAlign, dwFileAlign);
	
	m_PressPeTag.m_lpNtHeader->OptionalHeader.SizeOfImage = dwImageSize;
	//添加区段表

	m_PressPeTag.m_lpNtHeader->FileHeader.NumberOfSections = 0;
	AddSec(".OldDat", dwAfterPressSize, m_PressPeTag.m_FileMapTag.m_lpFileData);
	AddSec(".Shell", m_ShellPeTag.m_lpNtHeader->OptionalHeader.SizeOfCode, 

m_PressPeTag.m_FileMapTag.m_lpFileData);
	if (lpResSecInfo != NULL)
	{
		AddSec(".rsrc", lpResSecInfo->m_SecHeader.SizeOfRawData, 

m_PressPeTag.m_FileMapTag.m_lpFileData);
	}
	if (lpTLSSecInfo != NULL)
	{
		AddSec(".Tls", lpTLSSecInfo->m_SecHeader.SizeOfRawData, 

m_PressPeTag.m_FileMapTag.m_lpFileData);
	}
	AddSec(".Info", dwFileAlign, m_PressPeTag.m_FileMapTag.m_lpFileData);

//拷贝.OldDat区段
	DWORD dwCurPos = m_PressPeTag.m_lpNtHeader->OptionalHeader.SizeOfHeaders;
	memcpy((m_PressPeTag.m_FileMapTag.m_lpFileData + dwCurPos), 
			m_lpPressData, 
			dwAfterPressSize);



	//拷贝.Shell区段
	dwCurPos += Align(dwFileAlign, dwAfterPressSize);
	memcpy((m_PressPeTag.m_FileMapTag.m_lpFileData + dwCurPos), 
			(LPVOID)((DWORD)hRes + RVA2FA((char*)hRes, 

m_ShellPeTag.m_lpNtHeader->OptionalHeader.BaseOfCode)),
			m_ShellPeTag.m_lpNtHeader->OptionalHeader.SizeOfCode);
	dwCurPos += Align(dwFileAlign, m_ShellPeTag.m_lpNtHeader-

>OptionalHeader.SizeOfCode);
	//拷贝.rsrc区段
	if (lpResSecInfo != NULL)
	{
		memcpy((m_PressPeTag.m_FileMapTag.m_lpFileData + dwCurPos), 
			(m_TargetPeTag.m_FileMapTag.m_lpFileData + lpResSecInfo-

>m_SecHeader.PointerToRawData),
			lpResSecInfo->m_SecHeader.SizeOfRawData);
		dwCurPos += Align(dwFileAlign, lpResSecInfo->m_SecHeader.SizeOfRawData);
	}
	
	//拷贝.tls区段
	if (lpTLSSecInfo != NULL)
	{
		memcpy((m_PressPeTag.m_FileMapTag.m_lpFileData + dwCurPos), 
			(m_TargetPeTag.m_FileMapTag.m_lpFileData + lpTLSSecInfo-

>m_SecHeader.PointerToRawData), 
			lpTLSSecInfo->m_SecHeader.SizeOfRawData);
	}
//设置数据目录
	//记录被压缩程序的导入表RVA
	DWORD dwOldImpAddr = m_PressPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
	//把所有数据目录项都清空
	ClearDataDir(m_PressPeTag.m_FileMapTag.m_lpFileData);

//资源表
	DWORD dwRVA = 0;
	DWORD dwSize = 0;
	GetResRVA(m_PressPeTag.m_FileMapTag.m_lpFileData, dwRVA, dwSize);
	m_PressPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = dwRVA;
	m_PressPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = dwSize;
	//TLS
	//某些时候 TLS和别的区段连在一起 则要加上一个相差偏移
	DWORD dwPressTLSRVA = 0;
	if (lpTLSSecInfo != NULL)
	{
	
		DWORD dwTLSSize = 0;
		GetTLSRVA(m_PressPeTag.m_FileMapTag.m_lpFileData, dwPressTLSRVA, 

dwTLSSize);
		dwPressTLSRVA += dwTLSRVA - lpTLSSecInfo->m_SecHeader.VirtualAddress;
		m_PressPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = dwPressTLSRVA;
		m_PressPeTag.m_lpNtHeader->OptionalHeader.DataDirectory

[IMAGE_DIRECTORY_ENTRY_TLS].Size = dwTLSSize;
	}

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

上传的附件:
收藏
免费 6
支持
分享
最新回复 (54)
雪    币: 292
活跃值: (153)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
That's   my  boy ~  
2013-1-17 23:59
0
雪    币: 210
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
呵呵 学习了
2013-1-18 00:27
0
雪    币: 615
活跃值: (187)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
4
收下了,过后看看
2013-1-18 01:16
0
雪    币: 190
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
我会说,这是我留下的脚印么,留个记号,不错不错
2013-1-18 04:03
0
雪    币: 3386
活跃值: (1418)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
6
好东西,得踩个脚印。
2013-1-18 07:07
0
雪    币: 2155
活跃值: (29)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
学习一下啊,下载留名。。。
2013-1-18 08:50
0
雪    币: 1021
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zig
8
好东西,收藏了,(*^__^*) 嘻嘻……
ths for sharing。。。。。。。。。
2013-1-18 09:11
0
雪    币: 98803
活跃值: (201054)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
9
Thanks for share.
2013-1-18 09:36
0
雪    币: 27
活跃值: (354)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢楼主分享,下载收藏。希望后续版本继续更新。
2013-1-18 12:48
0
雪    币: 2203
活跃值: (1021)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
暂无指出错误的能力
2013-1-18 13:36
0
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
好学习了,哈哈
2013-1-18 15:09
0
雪    币: 206
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
对我而言很有参考价值,谢谢
2013-1-18 15:24
0
雪    币: 58
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
看看看看,呵呵呵。不错
2013-1-18 17:17
0
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
15
谢谢楼主的分享啊!
2013-1-18 17:18
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
学PE,很有必要学这个!!
2013-1-18 17:35
0
雪    币: 97
活跃值: (60)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
17
非常感谢,自己也在写简单的壳,拿来学习下!
2013-1-18 17:53
0
雪    币: 773
活跃值: (442)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
18
谢谢分享,楼主牛逼
2013-1-18 19:56
0
雪    币: 246
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
顶一下,呵呵。
2013-1-19 21:46
0
雪    币: 6706
活跃值: (4687)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
20
感谢开源,值得学习
2013-1-19 22:22
0
雪    币: 220
活跃值: (786)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
对2K-WIN7X64 各种系统的支持性怎么样呢?
2013-1-20 21:22
0
雪    币: 37
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
此等好贴,必须得顶
2013-1-21 10:23
0
雪    币: 45
活跃值: (51)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
23
mark  不错..
2013-1-21 18:35
0
雪    币: 1737
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
多谢分享东东
2013-1-22 13:52
0
雪    币: 230
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
简单测了一下。。。。。压缩过的程序在win7下错误!!!不能运行!
2013-1-22 16:54
0
游客
登录 | 注册 方可回帖
返回
//