首页
社区
课程
招聘
[原创]一段仿真PE加载器行为的程序
发表于: 2006-6-10 00:50 39422

[原创]一段仿真PE加载器行为的程序

2006-6-10 00:50
39422

【  标题  】 一段仿真PE加载器行为的程序
【  声明  】 水平有限,不对之处敬请各位大侠赐教!

以下程序假定PE文件是合法的,所以很多地方都没有提供容错处理

bool PELoader(char *lpStaticPEBuff, long lStaticPELen)
{
        long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c);
        IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset);

        //取加载到内存中大小
        long lImageSize = pINH->OptionalHeader.SizeOfImage;
        char *lpDynPEBuff = new char[lImageSize];
        if(lpDynPEBuff == NULL)
        {
                return false;
        }
        memset(lpDynPEBuff, 0, lImageSize);

        //取PE文件的节数量
        long lSectionNum = pINH->FileHeader.NumberOfSections;

        //计算PE头信息及节表信息占用内存大小
        long lPEHeadSize = lPESignOffset + sizeof(IMAGE_NT_HEADERS) + lSectionNum * sizeof(IMAGE_SECTION_HEADER);
       
        //加载PE头部信息及其各个节表
        memcpy(lpDynPEBuff, lpStaticPEBuff, lPEHeadSize);

        //加载各个节
        long lFileAlignMask = pINH->OptionalHeader.FileAlignment - 1;        //各节在磁盘中的对齐掩码
        long lSectionAlignMask = pINH->OptionalHeader.SectionAlignment - 1;  //各节在load后内存中的对齐掩码
        IMAGE_SECTION_HEADER *pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS));
        for(int nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++)
        {
                //判定各节的对齐属性,合法不
                if((pISH->VirtualAddress & lSectionAlignMask) || (pISH->SizeOfRawData & lFileAlignMask))
                {
                        //出现非法节
                        delete lpDynPEBuff;
                        return false;
                }

                //加载改节
                memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData);
        }

        //修改导入表,导入程序执行过程中要用到的API函数地址
        if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) //大于0说明有导入表
        {
                IMAGE_IMPORT_DESCRIPTOR *pIID = (IMAGE_IMPORT_DESCRIPTOR *)(lpDynPEBuff + \
                        pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

                //循环扫描每个将有函数导入的dll
                for(; pIID->Name != NULL; pIID++)
                {
                        /*曾看过OllyDump源代码,那里在重建导入表的时候,并没有初始化OriginalFirstThunk这个字段,
                        所以这里也不对OriginalFirstThunk这个字段进行处理了*/
                        IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)(lpDynPEBuff + pIID->FirstThunk);

                        HINSTANCE hInstance = LoadLibrary(lpDynPEBuff + pIID->Name);
                        if(hInstance == NULL)
                        {
                                //导入这个dll失败
                                delete lpDynPEBuff;
                                return false;
                        }

                        //循环扫描dll内每个被导入函数
                        for(; pITD->u1.Ordinal != 0; pITD++)
                        {
                                FARPROC fpFun;
                                if(pITD->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
                                {
                                        //函数是以序号的方式导入的
                                        fpFun = GetProcAddress(hInstance, (LPCSTR)(pITD->u1.Ordinal & 0x0000ffff));
                                }
                                else
                                {
                                        //函数是以名称方式导入的
                                        IMAGE_IMPORT_BY_NAME * pIIBN = (IMAGE_IMPORT_BY_NAME *)(lpDynPEBuff + pITD->u1.Ordinal);
                                        fpFun = GetProcAddress(hInstance, (LPCSTR)pIIBN->Name);
                                }

                                if(fpFun == NULL)
                                {
                                        //导出这个函数失败
                                        delete lpDynPEBuff;
                                        return false;
                                }

                                pITD->u1.Ordinal = (long)fpFun;
                        }

                        FreeLibrary(hInstance);
                }
        }

        //重定位处理
        if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
        {
                //取第一个重定位块
                IMAGE_BASE_RELOCATION *pIBR = (IMAGE_BASE_RELOCATION *)(lpDynPEBuff + \
                        pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

                long lDifference = (long)lpDynPEBuff - pINH->OptionalHeader.ImageBase;

                //循环每个重定位块
                for(; pIBR->VirtualAddress != 0; )
                {
                        char *lpMemPage = lpDynPEBuff + pIBR->VirtualAddress;
                        long lCount = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1;

                        //对这个页面中的每个需重定位的项进行处理
                        short int *pRelocationItem = (short int *)((char *)pIBR + sizeof(IMAGE_BASE_RELOCATION));
                        for(int nIndex = 0; nIndex < lCount; nIndex++)
                        {
                                int nOffset = pRelocationItem[nIndex] &0x0fff;
                                int nType = pRelocationItem[nIndex] >> 12;

                                //虽然windows定义了很多重定位类型,但是在PE文件中只能见到0和3两种
                                if(nType == 3)
                                {
                                        *(long *)(lpDynPEBuff + nOffset) += lDifference;
                                }
                                else if(nType == 0)
                                {
                                        //什么也不做
                                }
                        }

                        //pIBR指向下一个重定位块
                        pIBR = (IMAGE_BASE_RELOCATION *)(pRelocationItem + lCount);
                }

        }

        delete lpDynPEBuff;

        return true;
}


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

收藏
免费 7
支持
分享
最新回复 (49)
雪    币: 331
活跃值: (56)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
2
good~~!!!
thx
2006-6-10 09:45
0
雪    币: 208
活跃值: (376)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
3
收藏一下!
2006-6-10 10:39
0
雪    币: 313
活跃值: (250)
能力值: ( LV9,RANK:650 )
在线值:
发帖
回帖
粉丝
4
先收藏,再研究一下。
2006-6-10 11:15
0
雪    币: 235
活跃值: (41)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
学习啊...
2006-6-10 11:31
0
雪    币: 211
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
虚拟机收藏
2006-6-10 17:17
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
7
支持!
2006-6-10 18:04
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
NIU
8
好代码,非常有用
2006-6-10 19:15
0
雪    币: 149
活跃值: (344)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
9
不错呀...

不过还是应该少了点东西的,比如说tls
总是觉得m$的loader资料不是太多...
2006-6-11 22:10
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
10
支持先~
2006-6-12 09:38
0
雪    币: 50161
活跃值: (20675)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
11
不错
2006-6-12 09:43
0
雪    币: 184
活跃值: (108)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
12
收藏先,thx
2006-6-12 10:42
0
雪    币: 50161
活跃值: (20675)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
13
最初由 linxer 发布
*(long *)(lpDynPEBuff + nOffset) += lDifference;


在重定位处理这块,linxer好像有一句笔误,上面这句应是:

*(long *)(lpMemPage + nOffset) += lDifference;
2006-7-7 12:24
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
14
最初由 kanxue 发布
在重定位处理这块,linxer好像有一句笔误,上面这句应是:

*(long *)(lpMemPage + nOffset) += lDifference;


老大的猛壳要出世了!
2006-7-7 12:31
0
雪    币: 50161
活跃值: (20675)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
15
最初由 prince 发布
老大的猛壳要出世了!


不是,在处理DLL文件时参考了一下这块,呵~
2006-7-7 13:05
0
雪    币: 440
活跃值: (832)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
16
非常好。
期待老大的猛壳横空出世。
2006-7-7 14:04
0
雪    币: 1746
活跃值: (287)
能力值: (RANK:450 )
在线值:
发帖
回帖
粉丝
17
首先谢谢看雪老大对程序bug的更正

近期在对FSG1.33加壳后程序load时发现 程序还有两处不妥之处

现连同看雪老大指出的bug一同更正,再次发布这段程序,希望各位大侠指点

bool PELoader(char *lpStaticPEBuff, long lStaticPELen)
{
        long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c);
        IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset);

        //取加载到内存中大小
        long lImageSize = pINH->OptionalHeader.SizeOfImage;
        char *lpDynPEBuff = new char[lImageSize];
        if(lpDynPEBuff == NULL)
        {
                return false;
        }
        memset(lpDynPEBuff, 0, lImageSize);

        //取PE文件的节数量
        long lSectionNum = pINH->FileHeader.NumberOfSections;

        IMAGE_SECTION_HEADER *pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS));
       
        //加载PE文件第一个节前的信息
        memcpy(lpDynPEBuff, lpStaticPEBuff, pISH->VirtualAddress);

        //加载各个节
        long lFileAlignMask = pINH->OptionalHeader.FileAlignment - 1;        //各节在磁盘中的对齐掩码
        long lSectionAlignMask = pINH->OptionalHeader.SectionAlignment - 1;  //各节在load后内存中的对齐掩码
       
        for(int nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++)
        {
                /***************************************************
                在对FSG1.33加壳程序进行loader的时候,其节对齐属性
                比较怪异,对PE文件接触时间不长,不过地方不知道为什么,
                请各位大虾指点迷津,故注掉节属性验证代码
                ***************************************************/
                //判定各节的对齐属性,合法不
                /*if((pISH->VirtualAddress & lSectionAlignMask) || (pISH->SizeOfRawData & lFileAlignMask))
                {
                        //出现非法节
                        delete lpDynPEBuff;
                        return false;
                }*/

                //加载改节
                memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData);
        }

        //修改导入表,导入程序执行过程中要用到的API函数地址
        if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) //大于0说明有导入表
        {
                IMAGE_IMPORT_DESCRIPTOR *pIID = (IMAGE_IMPORT_DESCRIPTOR *)(lpDynPEBuff + \
                        pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

                //循环扫描每个将有函数导入的dll
                for(; pIID->Name != NULL; pIID++)
                {
                        /*曾看过OllyDump源代码,那里在重建导入表的时候,并没有初始化OriginalFirstThunk这个字段,
                        所以这里也不对OriginalFirstThunk这个字段进行处理了*/
                        IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)(lpDynPEBuff + pIID->FirstThunk);

                        HINSTANCE hInstance = LoadLibrary(lpDynPEBuff + pIID->Name);
                        if(hInstance == NULL)
                        {
                                //导入这个dll失败
                                delete lpDynPEBuff;
                                return false;
                        }

                        //循环扫描dll内每个被导入函数
                        for(; pITD->u1.Ordinal != 0; pITD++)
                        {
                                FARPROC fpFun;
                                if(pITD->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
                                {
                                        //函数是以序号的方式导入的
                                        fpFun = GetProcAddress(hInstance, (LPCSTR)(pITD->u1.Ordinal & 0x0000ffff));
                                }
                                else
                                {
                                        //函数是以名称方式导入的
                                        IMAGE_IMPORT_BY_NAME * pIIBN = (IMAGE_IMPORT_BY_NAME *)(lpDynPEBuff + pITD->u1.Ordinal);
                                        fpFun = GetProcAddress(hInstance, (LPCSTR)pIIBN->Name);
                                }

                                if(fpFun == NULL)
                                {
                                        //导出这个函数失败
                                        delete lpDynPEBuff;
                                        return false;
                                }

                                pITD->u1.Ordinal = (long)fpFun;
                        }

                        FreeLibrary(hInstance);
                }
        }

        //重定位处理
        if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
        {
                //取第一个重定位块
                IMAGE_BASE_RELOCATION *pIBR = (IMAGE_BASE_RELOCATION *)(lpDynPEBuff + \
                        pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

                long lDifference = (long)lpDynPEBuff - pINH->OptionalHeader.ImageBase;

                //循环每个重定位块
                for(; pIBR->VirtualAddress != 0; )
                {
                        char *lpMemPage = lpDynPEBuff + pIBR->VirtualAddress;
                        long lCount = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1;

                        //对这个页面中的每个需重定位的项进行处理
                        short int *pRelocationItem = (short int *)((char *)pIBR + sizeof(IMAGE_BASE_RELOCATION));
                        for(int nIndex = 0; nIndex < lCount; nIndex++)
                        {
                                int nOffset = pRelocationItem[nIndex] & 0x0fff;
                                int nType = pRelocationItem[nIndex] >> 12;

                                //虽然windows定义了很多重定位类型,但是在PE文件中只能见到0和3两种
                                if(nType == 3)
                                {
                                        *(long *)(lpMemPage + nOffset) += lDifference;
                                }
                                else if(nType == 0)
                                {
                                        //什么也不做
                                }
                        }

                        //pIBR指向下一个重定位块
                        pIBR = (IMAGE_BASE_RELOCATION *)(pRelocationItem + lCount);
                }

        }

        delete lpDynPEBuff;

        return true;
}
2006-7-7 14:11
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
18
顶楼上的~
2006-7-7 14:25
0
雪    币: 255
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
我正在学习这块,赶上了哈
2006-7-17 09:52
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
收藏,收藏收藏
2006-7-20 20:17
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
for(int nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++)
        {
                /***************************************************
                在对FSG1.33加壳程序进行loader的时候,其节对齐属性
                比较怪异,对PE文件接触时间不长,不过地方不知道为什么,
                请各位大虾指点迷津,故注掉节属性验证代码
                ***************************************************/
                /* 判定各节的对齐属性,是否合法 */
                if((pISH->VirtualAddress & lSectionAlignMask) || (pISH->SizeOfRawData & lFileAlignMask))
                {
                        delete lpDynPEBuff;
                        return false;
                }

                /* 加载改节 */
                memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData);
        }

这段我看不明白,在for语句里面lSectionNum是节表数,而一个节表的大小是028H,那么后面的nIndex++, pISH++是什么意思啊?
请教
2006-7-26 09:29
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
是不是应该pISH = pISH + 28H
2006-7-26 09:54
0
雪    币: 221
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
如果我没有猜错的话:

    因为pISH是一个IMAGE_SECTION_HEADER结构指针,pISH的自增就是相当于pISH += sizeof(IMAGE_SECTION_HEADER).其实和你说的一样.

我有个问题没明白,就是入口的传入参数char *lpStaticPEBuff, long lStaticPELen分别代表什么含义?
2006-7-26 17:41
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
研究一下,向各位学习了,不知道楼上的兄弟,强!
2006-7-27 21:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
还有个问题,我不明白就是楼主修正后的程序

......
//取PE文件的节数量
  long lSectionNum = pINH->FileHeader.NumberOfSections;

  IMAGE_SECTION_HEADER *pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS));
  
  //加载PE文件第一个节前的信息
  memcpy(lpDynPEBuff, lpStaticPEBuff, pISH->VirtualAddress);
......

最后一句
memcpy(lpDynPEBuff, lpStaticPEBuff, pISH->VirtualAddress);
好象有点问题
是不是应该这样
memcpy(lpDynPEBuff, lpStaticPEBuff, pINH->OptionalHeader.SizeOfHeaders);
2006-7-31 14:48
0
游客
登录 | 注册 方可回帖
返回
//