admin管理员组

文章数量:1547074

加壳的实现

我是个初学者,所知有限,难免会有错误,如果有人发现了错误,还请指正。
先大致说一下加壳的原理,即在原PE文件(后面称之为宿主文件)上加一个新的区段(也就是壳),然后从这个新的区段上开始运行;也就算是成功的加上了壳;下面我们就说一下具体的实现。
这个工程有两个项目,一个用来生成壳的Win32项目(dll类型),另一个是实现加壳的MFC项目;
加壳的项目界面是用MFC实现的,除了原有的类外,添加了两个新类,一个用于PE操作,
一个用于加壳。

下面说下加壳过程的实现:
先将原PE文件读取到内存;获取头文件信息,获得.text区段信息,然后对代码段进行加密(简单的异或加密);随后再用LoadLibrary将生成的壳(是一个dll)加载到内存;我们需要在壳的程序里对宿主PE进行解密,并且还要修复重定位,所以要把一些必要的数据存储到加载的壳里面;
申请空间将dll(壳)拷贝一份(此处大家可能会疑惑为什么要拷贝一份,因为我在以LoadLibrary加载进来的壳里直接修改需要重定位的地址信息时,程序运行会出错);
然后申请内存,大小是原宿主PE文件和壳的大小的和;先将宿主程序拷贝进去;
然后修复重定位信息,这个地方应该重点说明一下,我是直接把展开的整个dll拷贝到新PE文件里,并且打算壳的部分利用系统的重定位(每次加载PE文件的时候,如果重定位没有关掉,系统会进行一次重定位),所以在拷贝之前,要把需要重定位的地址修改成在新PE中的虚拟地址,并且我们的壳是通过LoadLibrary的方式加载的,已经被重定位过,我又是直接拷贝过来的,所以修改地址的时候要注意,后面会说到如何修改。
然后,合并PE文件和壳;设置新的OEP,既然加壳,当然要从壳的我们规定的开始位置开始执行,需要将其改成相对新PE开始位置的偏移,原理和修复重定位差不多,不过一个是相对虚拟地址,一个是虚拟地址。
如图:

相对虚拟地址=1+2;
如果修复重定位的话就某一地址的相对虚拟地址再加个默认基址;
下面是代码实现部分:

bool CPack::Pack(WCHAR * szPath)
{
    CPe objPe;

    //读取要被加壳的PE文件
    DWORD dwReadFilSize = 0;
    HANDLE hFile = CreateFile(szPath,GENERIC_READ | GENERIC_WRITE, 0, NULL,
                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    DWORD dwFileSize = GetFileSize(hFile, NULL);
    char * pFileBuf = new char[dwFileSize];
    memset(pFileBuf, 0, dwFileSize);
    ReadFile(hFile, pFileBuf, dwFileSize, &dwReadFilSize, NULL);

    //获取PE头文件信息
    PEHEADERINFO pPeHead = { 0 };
    objPe.GetPeHeaderinfo(pFileBuf, &pPeHead);

    //加密
    IMAGE_SECTION_HEADER pTxtSection;
    objPe.GetSectionInfo(pFileBuf, &pTxtSection, ".text");
    objPe.XorCode((LPBYTE)(pTxtSection.PointerToRawData + pFileBuf), pTxtSection.SizeOfRawData);

    //用loadLibrary加载壳文件
    HMODULE pLoadStubBuf = LoadLibrary(L"..\\Release\\Stub.dll");

    //存储必要的信息
    PPACKINFO PackInfoAdd = (PPACKINFO)GetProcAddress((HMODULE)pLoadStubBuf, "g_PackInfo");

    PackInfoAdd->dwOriStartPoint = pPeHead.pOptionHeader->AddressOfEntryPoint;                                          //需要跳转的OEP
    PackInfoAdd->dwImageBase = pPeHead.pOptionHeader->ImageBase;                                                        //默认加载基址
    PackInfoAdd->dwXorCode = pTxtSection.VirtualAddress;                                                                //加密代码段地址
    PackInfoAdd->dwXorKey = 0xE;                                                                                        //加密密钥
    PackInfoAdd->dwXorSize = pTxtSection.SizeOfRawData;                                                                 //加密大小
    PackInfoAdd->stcPeRelocDir = pPeHead.pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];                 //重定位表信息
    PackInfoAdd->dwSizeOfImage = pPeHead.pOptionHeader->SizeOfImage;                                                    //原PE的大小

    //拷贝一份
    MODULEINFO stcModInfo = { 0 };
    GetModuleInformation(GetCurrentProcess(), pLoadStubBuf, &stcModInfo, sizeof(MODULEINFO));
    

本文标签: 原理加壳软件