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

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

2012-2-24 01:30
14563

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

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


加载待压缩PE文件

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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++;
    }
1
2
3
4
5
6
7
8
9
10
//保存重定位表的原始数据
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;
1
2
3
4
5
6
7
8
//保存原始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到压缩数据节之后。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//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
支持
分享
赞赏记录
参与人
雪币
留言
时间
伟叔叔
为你点赞~
2024-5-31 03:56
心游尘世外
为你点赞~
2024-3-30 01:50
飘零丶
为你点赞~
2024-3-21 03:19
QinBeast
为你点赞~
2024-3-5 01:46
shinratensei
为你点赞~
2024-1-27 04:24
PLEBFE
为你点赞~
2023-3-7 00:46
最新回复 (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
雪    币: 2562
活跃值: (4293)
能力值: ( LV13,RANK:540 )
在线值:
发帖
回帖
粉丝
5
拔云见日~~~
2012-2-24 10:01
0
雪    币: 77
活跃值: (53)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
拔云见日~~~
2012-2-24 11:44
0
雪    币: 1149
活跃值: (1008)
能力值: ( 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
雪    币: 559
活跃值: (334)
能力值: ( 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
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册