首页
社区
课程
招聘
[原创]使用C++写壳
发表于: 2020-12-6 15:35 41758

[原创]使用C++写壳

2020-12-6 15:35
41758

第一次写壳,如有错误,感谢指点~

编写一个加壳器项目、一个动态链接库项目,将动态链接库的.text.data.rdata区段合并为一个区段

1.1为了方便调试,进行如下设置

设置 .exe(加壳器) 和 .dll(stub) 文件的输出路径为同一路径

项目属性 -> 常规 -> 输出目录

设置工作目录为刚才的输出路径

项目属性 -> 调试 -> 工作目录

1.2STUB 区域代码的重定位问题

起初代码是放在了 dll 中,需要重定位的内容,是以 dll 实际加载基址设置的,现在我们将dll中的三个区段合并之后放到原程序后面了,那么涉及到重定位的问题:首先了解一下一个虚拟地址的组成:

VA = ImageBase + 区段首地址 + 区段偏移

在加壳器中,首先打开需要被加壳的程序,读取需要加壳的程序的PE文件到内存中

新建一个动态链接库项目,作为壳代码使用

在加壳器中,打开动态链接库生成的dll文件,以便后面获取合并区段中的壳代码

打开完dll和需要加壳的exe后,对exe的PE结构操作:新增一个区段,将dll中合并后的.text区段拷贝到新区段中

AlignmentToSize函数:根据大小以及对齐粒度,获取对齐后的大小

拷贝完成之后,将程序的OEP设置为壳代码的OEP(也就是刚刚拷贝过来的区段),并且备份原程序的OEP

设置完OEP,开始对区段加密,加密的实现很简单,就是获取需要加密的区段首地址和大小,循环加密。加密算法这里就使用简单的异或。

加密完之后,对原程序的.text区段压缩,压缩的原理如下图,此处仅压缩了.text区段

压缩实现之后的大小变化:因为只是压缩了一个.text区段所以压缩率并不高,只是少了600KB左右

我们先看一下程序从编译到运行之间的流程

编译:将单个的 .c.cpp编译成中间文件 (.obj),在VS 下,这个过程由 cl.exe程序完成。

链接:将编译出的.obj 中间文件、系统的启动文件和用到的库文件链接成一个可执行文件 (.exe)。VS下由 link.exe程序完成

装载:将一个可执行文件映射到虚拟地址空间并执行,由操作系统完成。在装载的过程中,完了让程序正常被执行,会有下列几个步骤:

判断是否开启重定位,如果开启了,将 PE 文件加载到指定位置,并且修复目标PE 文件的重定位。

遍历导入表,加载使用到的所有模块到内存,修复模块相关的信息,并根据导入表中的函数名称,填充所有的IAT地址项。

查看当前是否存在TLS回调函数,如果存在,则传入进程创建事件,依次调用 所有的TLS回调函数。

PE文件中的AddressOfEntryPoint为起始位置,创建线程并运行。

我们的IAT加密是在壳代码中完成的,但是为了能让壳代码顺利接管到IAT表,需要在令程序在装载的时候不填充IAT

一个程序如果有TLS会在程序运行之前就调用TLS里面的回调函数,由于我们运行的是加壳后的程序,原程序的代码段已经被加密,直接运行TLS肯定不行,我们需要手动处理TLS,在原程序中备份TLS以及TLS的回调函数数组,然后在壳代码中,程序解密后运行前,自己手动遍历TLS回调函数,手动循环调用一次,然后在恢复TLS

重定位是一个比较麻烦的问题,还需要考虑到随机基址的问题。

首先,dll合并后的.text区段由于ImageBase区段RVA改变了,需要先修复dll.text区段的重定位项

随机基址的问题:由于有了随机基址,即使我们上面修复了重定位项,程序也不能正常运行,我们可以替换原程序的重定位表,让原程序帮我们修复壳代码的重定位项,当程序装载之后,壳代码的重定位项已经修复为随机基址之后的地址了,我们就可以在壳代码中修复原程序的重定位表,壳代码修复原程序的重定位项需要使用到原程序的重定位表,因此,还需要备份一下原程序的重定位表地址。

那如何替换原程序的重定位表呢?新建一个区段,这个区段用于存放DLL的重定位表,然后备份原程序的重定位表后,将原程序的重定位表指向新建的区段。完成重定位表的替换。

添加区段的函数:

拷贝dll.text区段到被加壳程序的.pack区段

壳代码其实就是动态链接库中合并后的.text区段,在2.1中有提到过

其实也是和加壳器是一一对应的,理解了加壳器的代码,壳代码也就好理解了

由于壳代码在运行的时候,原程序还没有运行起来,并且我们对IAT进行了加密,因此,在壳代码中不能直接调用函数,需要手动获取函数地址。

一旦有了GetProcAddress这个函数和Kerler32基址,我们就可以调用所有函数了,获取到LoadLibraryExA之后,就可以加载其他模块,获取其他模块的函数了。(因为不管是Kernel32还是KernelBase都存在这个导出函数,所以不使用LoadLibraryA)

此处为壳子添加了一个密码弹框,需要输入正确的密码后才能运行壳代码,其实也并没什么作用,就是手动获取API调用了SDK的函数,创建窗口以及消息处理的函数。

运行加壳后的程序会弹出对话框:

在加壳器中我们对原程序进行了压缩,那么在壳代码中就要对原程序解压,解压很简单,就是将压缩后的数据解压后放回该数据的原来的位置(参考2.6的图)

与加壳器中的加密同理

在加壳器中,我们对导出表进行了清零操作,目的就是为了不让系统去修复导入表,而令我们的壳代码来修复导入表并加密IAT。而加密IAT的原理如下:

就是为每一个IAT都申请一个堆空间,然后在堆空间中填入解密IAT的代码以及加密后的IAT地址,将原来的IAT替换为堆空间的地址,这样,只要程序使用到IAT,就会执行堆空间的代码,动态解密IAT。下面的图片是为了便于理解画的简化版,并没有加密IAT

由于加壳器中的设置,程序装载的时候,系统帮我们修复了壳代码的重定位,但是原程序的重定位并没有修复,需要我们自己手动修复

这里处理的TLS并不是完美处理的。但是也能实现TLS的处理,就是循环调用TLS的回调函数,将数据目录表的TLS恢复。

反调试有很多很多种方法,这里就是简单的意思一下。遍历所有线程的TEB+0xF24的反调试方法目前还有BUG,暂时没有完成实现。若有大佬能指点一二,感激不尽~

原程序的解压、解密、IAT加密都已经操作完成了,跳回原程序执行。

关于混淆和花指令在这里并没有做太深入的探究。
最后,非常感谢15PB万老师的课上讲解、以及顿老师的课后辅导~

 
//1.  将 DLL 设置为 Release 版本进行编译、小、内联了一些函数
//2.  C\C++ -> 代码生成 -> GS安全检查 -> 禁用 (取消一些库函数的调用)
//3.  C\C++ -> 所有选项 -> 运行库 -> MT (取消一些库函数的调用)
//4.  合并区段,并设置属性为可读可写可执行(0xE00000E0)
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/section:.text,RWE")
//1.  将 DLL 设置为 Release 版本进行编译、小、内联了一些函数
//2.  C\C++ -> 代码生成 -> GS安全检查 -> 禁用 (取消一些库函数的调用)
//3.  C\C++ -> 所有选项 -> 运行库 -> MT (取消一些库函数的调用)
//4.  合并区段,并设置属性为可读可写可执行(0xE00000E0)
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/section:.text,RWE")
 
 
 
//打开、读取、判断文件
VOID Pack::OpenPeFile(LPCSTR Path) {
    HANDLE hFile = CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        print("打开文件失败");//自己封装的判断函数
    PeSize = GetFileSize(hFile, NULL);
    PeBase = (DWORD)malloc(PeSize);
    DWORD ReadSize = 0;
    ReadFile(hFile, (LPVOID)PeBase, PeSize, &ReadSize, NULL);
    if (pDosHead(PeBase)->e_magic!=0x5A4D)
        print("不是有效的PE文件");   
    else if (pNtHead(PeBase)->Signature != 0x4550)
        print("不是有效的PE文件");
    CloseHandle(hFile);
}
//打开、读取、判断文件
VOID Pack::OpenPeFile(LPCSTR Path) {
    HANDLE hFile = CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        print("打开文件失败");//自己封装的判断函数
    PeSize = GetFileSize(hFile, NULL);
    PeBase = (DWORD)malloc(PeSize);
    DWORD ReadSize = 0;
    ReadFile(hFile, (LPVOID)PeBase, PeSize, &ReadSize, NULL);
    if (pDosHead(PeBase)->e_magic!=0x5A4D)
        print("不是有效的PE文件");   
    else if (pNtHead(PeBase)->Signature != 0x4550)
        print("不是有效的PE文件");
    CloseHandle(hFile);
}
#include "../pack/Share.h"                  // 壳代码与加壳器之间共用的结构体类型头文件
#include"../aplib/aplib.h"                  // 压缩库头文件
#include <Windows.h>
#pragma comment(lib, "../aplib/aplib.lib")    // 压缩库
// 对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/section:.text,RWE")
// 去除所有导出函数和导出变量的名称粉碎
extern "C"{
    __declspec(dllexport) SHARE ShareData;                    //导出变量,用于壳代码与加壳器之间的通讯
    __declspec(dllexport) __declspec(naked) void start()     //导出函数地址,将会作为新的OEP
    {       
        _asm{
            mov eax, fs:[0x30]
            mov eax, [eax + 0x8]        //获取当前进程gImageBase
            mov gImageBase, eax
        }
        GetFunAdd();                    //获取GetProcAddress
        GetApi();                        //获取API
        CallShllFun();                    //密码弹窗
        UnCompression(ShareData);         //解压
        DecSection();                    //解密代码段
        DecIat(ShareData);                //加密IAT
        FixReloca(ShareData);            //修复重定位
        CallTls(ShareData);                //处理TLS       
        Debugging();                    //反调试
        __asm
        {
            mov eax, gImageBase                //获取当前进程gImageBase
            mov ebx, ShareData.DestOEP         //获取原程序的OEP
            add eax,ebx
            jmp eax
        }
    }
}
#include "../pack/Share.h"                  // 壳代码与加壳器之间共用的结构体类型头文件
#include"../aplib/aplib.h"                  // 压缩库头文件
#include <Windows.h>
#pragma comment(lib, "../aplib/aplib.lib")    // 压缩库
// 对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/section:.text,RWE")
// 去除所有导出函数和导出变量的名称粉碎
extern "C"{
    __declspec(dllexport) SHARE ShareData;                    //导出变量,用于壳代码与加壳器之间的通讯
    __declspec(dllexport) __declspec(naked) void start()     //导出函数地址,将会作为新的OEP
    {       
        _asm{
            mov eax, fs:[0x30]
            mov eax, [eax + 0x8]        //获取当前进程gImageBase
            mov gImageBase, eax
        }
        GetFunAdd();                    //获取GetProcAddress
        GetApi();                        //获取API
        CallShllFun();                    //密码弹窗
        UnCompression(ShareData);         //解压
        DecSection();                    //解密代码段
        DecIat(ShareData);                //加密IAT
        FixReloca(ShareData);            //修复重定位
        CallTls(ShareData);                //处理TLS       
        Debugging();                    //反调试
        __asm
        {
            mov eax, gImageBase                //获取当前进程gImageBase
            mov ebx, ShareData.DestOEP         //获取原程序的OEP
            add eax,ebx
            jmp eax
        }
    }
}
//打开 壳代码的DLL 文件,获取基址
VOID  Pack::OpenDllFile(LPCSTR Path) {
    //加载模块到内存中,并且不调用DllMain
    DllBase = (DWORD)LoadLibraryEx(Path, NULL, DONT_RESOLVE_DLL_REFERENCES);
    //获取导出函数StartOfsset地址
    StartOfsset = (DWORD)GetProcAddress((HMODULE)DllBase, "start");
    if (!StartOfsset)
        print("获取DLLMain的导出函数失败");
    StartOfsset = StartOfsset - DllBase - (DWORD)GetSecHeadAddr(DllBase, DllSecName)->VirtualAddress;
    //获取导出变量通讯结构体,加壳器需要使用到
    pShareData = (SHARE*)GetProcAddress((HMODULE)DllBase, "ShareData");
}
//打开 壳代码的DLL 文件,获取基址
VOID  Pack::OpenDllFile(LPCSTR Path) {
    //加载模块到内存中,并且不调用DllMain
    DllBase = (DWORD)LoadLibraryEx(Path, NULL, DONT_RESOLVE_DLL_REFERENCES);
    //获取导出函数StartOfsset地址
    StartOfsset = (DWORD)GetProcAddress((HMODULE)DllBase, "start");
    if (!StartOfsset)
        print("获取DLLMain的导出函数失败");
    StartOfsset = StartOfsset - DllBase - (DWORD)GetSecHeadAddr(DllBase, DllSecName)->VirtualAddress;
    //获取导出变量通讯结构体,加壳器需要使用到
    pShareData = (SHARE*)GetProcAddress((HMODULE)DllBase, "ShareData");
}
//添加并拷贝一个新区段
VOID Pack::CopySection(LPCSTR DestName) {
    if (strlen(DestName) > 7)
        print("新区段名称太长");
    //获取需要添加的区段
    auto pLastSection = IMAGE_FIRST_SECTION(pNtHead(PeBase)) + (pFileHead(PeBase)->NumberOfSections - 1);
    auto pNewSection = pLastSection + 1;
    //获取区段头的首地址
    auto SrcAddr = GetSecHeadAddr(DllBase, DllSecName);
    //拷贝区段头
    memcpy(pNewSection, SrcAddr, sizeof(IMAGE_SECTION_HEADER));
    //修改属性
    pNewSection->VirtualAddress = pLastSection->VirtualAddress +
        AlignmentToSize(pLastSection->Misc.VirtualSize, pOptionHead(PeBase)->SectionAlignment);
    pNewSection->PointerToRawData = pLastSection->PointerToRawData +
        AlignmentToSize(pLastSection->SizeOfRawData, pOptionHead(PeBase)->FileAlignment);
    // Name
    memcpy(pNewSection->Name, DestName, strlen(DestName));
    // NumberOfSections
    pFileHead(PeBase)->NumberOfSections += 1;
    // SizeOfImage大小
    pOptionHead(PeBase)->SizeOfImage +=
        AlignmentToSize(pNewSection->Misc.VirtualSize, pOptionHead(PeBase)->SectionAlignment);
    // 从新分配空间,将新区段添加到堆空间中
    PeSize = pNewSection->SizeOfRawData + pNewSection->PointerToRawData;
    PeBase = (DWORD)realloc((VOID*)PeBase, PeSize);   
    return;
}
//添加并拷贝一个新区段
VOID Pack::CopySection(LPCSTR DestName) {
    if (strlen(DestName) > 7)
        print("新区段名称太长");
    //获取需要添加的区段
    auto pLastSection = IMAGE_FIRST_SECTION(pNtHead(PeBase)) + (pFileHead(PeBase)->NumberOfSections - 1);
    auto pNewSection = pLastSection + 1;
    //获取区段头的首地址
    auto SrcAddr = GetSecHeadAddr(DllBase, DllSecName);
    //拷贝区段头
    memcpy(pNewSection, SrcAddr, sizeof(IMAGE_SECTION_HEADER));
    //修改属性
    pNewSection->VirtualAddress = pLastSection->VirtualAddress +
        AlignmentToSize(pLastSection->Misc.VirtualSize, pOptionHead(PeBase)->SectionAlignment);
    pNewSection->PointerToRawData = pLastSection->PointerToRawData +
        AlignmentToSize(pLastSection->SizeOfRawData, pOptionHead(PeBase)->FileAlignment);
    // Name
    memcpy(pNewSection->Name, DestName, strlen(DestName));
    // NumberOfSections
    pFileHead(PeBase)->NumberOfSections += 1;
    // SizeOfImage大小
    pOptionHead(PeBase)->SizeOfImage +=
        AlignmentToSize(pNewSection->Misc.VirtualSize, pOptionHead(PeBase)->SectionAlignment);
    // 从新分配空间,将新区段添加到堆空间中
    PeSize = pNewSection->SizeOfRawData + pNewSection->PointerToRawData;
    PeBase = (DWORD)realloc((VOID*)PeBase, PeSize);   
    return;
}
//根据大小以及对齐粒度获取对齐大小
DWORD Pack::AlignmentToSize(DWORD Size, DWORD Algmt) {
    return (Size / Algmt)?(((Size / Algmt) + 1)*Algmt):Algmt;
}
//根据大小以及对齐粒度获取对齐大小
DWORD Pack::AlignmentToSize(DWORD Size, DWORD Algmt) {
    return (Size / Algmt)?(((Size / Algmt) + 1)*Algmt):Algmt;
}
//设置OEP
VOID Pack::SetOep() {   
    //在重定位之前,保存原程序OEP
    pShareData->DestOEP = pOptionHead(PeBase)->AddressOfEntryPoint;
    //设置OEP为壳代码OEP
    pOptionHead(PeBase)->AddressOfEntryPoint = StartOfsset + GetSecHeadAddr(PeBase,".pack")->VirtualAddress;   
}
//设置OEP
VOID Pack::SetOep() {   
    //在重定位之前,保存原程序OEP
    pShareData->DestOEP = pOptionHead(PeBase)->AddressOfEntryPoint;
    //设置OEP为壳代码OEP
    pOptionHead(PeBase)->AddressOfEntryPoint = StartOfsset + GetSecHeadAddr(PeBase,".pack")->VirtualAddress;   
}
//加密区段
VOID Pack::Encryption(CHAR* SectionName) {
    //找到需要加密的区段
    auto SectionHead = GetSecHeadAddr(PeBase, SectionName);
    //加密的大小和加密起始地址
    DWORD Size = SectionHead->Misc.VirtualSize;
    CHAR* Address =(CHAR*)(SectionHead->PointerToRawData + PeBase);
    for (size_t i = 0; i < Size; i++){
        *Address ^= 0x15;
        Address++;
    }
}
//加密区段
VOID Pack::Encryption(CHAR* SectionName) {
    //找到需要加密的区段
    auto SectionHead = GetSecHeadAddr(PeBase, SectionName);
    //加密的大小和加密起始地址
    DWORD Size = SectionHead->Misc.VirtualSize;
    CHAR* Address =(CHAR*)(SectionHead->PointerToRawData + PeBase);
    for (size_t i = 0; i < Size; i++){
        *Address ^= 0x15;
        Address++;
    }
}
 
//压缩
VOID Pack::Compression()
{   
    int SecTextSize = GetSecHeadAddr(PeBase, ".text")->SizeOfRawData;
    pShareData->SizeOfRawData = SecTextSize;
    char* TextSecData = (char*)(GetSecHeadAddr(PeBase, ".text")->PointerToRawData + PeBase);
    //被压缩的数据,Packed保存压缩数据的空间,WorkMem为完成压缩需要使用的空间
    char* Packed = (char*)malloc(aP_max_packed_size(SecTextSize));
    char* WorkMem = (char*)malloc(aP_workmem_size(SecTextSize));
    //压缩后的大小
    int OutSize = aPsafe_pack(TextSecData, Packed, SecTextSize, WorkMem, NULL, NULL);
    //对齐后的大小
    int AlignSize = OutSize % 0x200 == 0 ? OutSize : (OutSize / 0x200 + 1) * 0x200;
    //新空间大小
    DWORD NewFileSize = PeSize - GetSecHeadAddr(PeBase, ".text")->SizeOfRawData + AlignSize;
    //申请新的空间大小 文件大小 - 区段在文件中的大小 + 压缩后的大小(不对齐)
    DWORD NewFileBase = (DWORD)malloc(NewFileSize);
    //TextSecData之前的数据
    DWORD PreText = GetSecHeadAddr(PeBase, ".text")->PointerToRawData - 1;
    //拷贝TextSecData段之前的数据
    memcpy((LPVOID)NewFileBase, (LPVOID)PeBase, PreText);
    //拷贝压缩部分的数据
    memcpy((LPVOID)(NewFileBase + PreText + 1), Packed, OutSize);
    //拷贝TextSecData段后面的数据
    LPVOID DestAddr = (LPVOID)(NewFileBase + PreText + AlignSize + 1);
    DWORD TextSecSize = GetSecHeadAddr(PeBase, ".text")->SizeOfRawData;
    DWORD TextSecPointRaw = GetSecHeadAddr(PeBase, ".text")->PointerToRawData;
    LPVOID SrcAddr = (LPVOID)(PeBase + TextSecSize + TextSecPointRaw);
    DWORD LastSize = NewFileSize - PreText - AlignSize;
    memcpy(DestAddr, SrcAddr, LastSize);
    //free(&FileBase);
    PeBase = NewFileBase;
    //free((void*)NewFileBase);
    NewFileBase = NULL;
    // 1. 获取到目标模块的区段表   
    auto Sections = IMAGE_FIRST_SECTION(pNtHead(PeBase));
    // 2. 使用文件头中的区段数量遍历区段表   
    WORD Count = pFileHead(PeBase)->NumberOfSections;
    BOOL bChangeFoa = FALSE;
    for (WORD i = 0; i < Count; ++i)
    {
        if (bChangeFoa) {
            Sections[i].PointerToRawData = Sections[i].PointerToRawData - GetSecHeadAddr(PeBase, ".text")->SizeOfRawData + AlignSize;
        }
        // 3. .text区段之前的区段不改变,操作.text区段之后的区段
        if (!memcmp(Sections[i].Name, ".text", 7)) {
            bChangeFoa = TRUE;
        }
    }   
    pShareData->TextCompressSize = OutSize;
    GetSecHeadAddr(PeBase, ".text")->SizeOfRawData = AlignSize;
    pShareData->TextRVA = GetSecHeadAddr(PeBase, ".text")->VirtualAddress;
    PeSize = NewFileSize;
}
//压缩
VOID Pack::Compression()
{   
    int SecTextSize = GetSecHeadAddr(PeBase, ".text")->SizeOfRawData;
    pShareData->SizeOfRawData = SecTextSize;
    char* TextSecData = (char*)(GetSecHeadAddr(PeBase, ".text")->PointerToRawData + PeBase);
    //被压缩的数据,Packed保存压缩数据的空间,WorkMem为完成压缩需要使用的空间
    char* Packed = (char*)malloc(aP_max_packed_size(SecTextSize));
    char* WorkMem = (char*)malloc(aP_workmem_size(SecTextSize));
    //压缩后的大小
    int OutSize = aPsafe_pack(TextSecData, Packed, SecTextSize, WorkMem, NULL, NULL);
    //对齐后的大小
    int AlignSize = OutSize % 0x200 == 0 ? OutSize : (OutSize / 0x200 + 1) * 0x200;
    //新空间大小
    DWORD NewFileSize = PeSize - GetSecHeadAddr(PeBase, ".text")->SizeOfRawData + AlignSize;
    //申请新的空间大小 文件大小 - 区段在文件中的大小 + 压缩后的大小(不对齐)
    DWORD NewFileBase = (DWORD)malloc(NewFileSize);
    //TextSecData之前的数据
    DWORD PreText = GetSecHeadAddr(PeBase, ".text")->PointerToRawData - 1;
    //拷贝TextSecData段之前的数据
    memcpy((LPVOID)NewFileBase, (LPVOID)PeBase, PreText);
    //拷贝压缩部分的数据
    memcpy((LPVOID)(NewFileBase + PreText + 1), Packed, OutSize);
    //拷贝TextSecData段后面的数据
    LPVOID DestAddr = (LPVOID)(NewFileBase + PreText + AlignSize + 1);
    DWORD TextSecSize = GetSecHeadAddr(PeBase, ".text")->SizeOfRawData;
    DWORD TextSecPointRaw = GetSecHeadAddr(PeBase, ".text")->PointerToRawData;
    LPVOID SrcAddr = (LPVOID)(PeBase + TextSecSize + TextSecPointRaw);
    DWORD LastSize = NewFileSize - PreText - AlignSize;
    memcpy(DestAddr, SrcAddr, LastSize);
    //free(&FileBase);
    PeBase = NewFileBase;
    //free((void*)NewFileBase);
    NewFileBase = NULL;
    // 1. 获取到目标模块的区段表   
    auto Sections = IMAGE_FIRST_SECTION(pNtHead(PeBase));
    // 2. 使用文件头中的区段数量遍历区段表   
    WORD Count = pFileHead(PeBase)->NumberOfSections;
    BOOL bChangeFoa = FALSE;
    for (WORD i = 0; i < Count; ++i)
    {
        if (bChangeFoa) {
            Sections[i].PointerToRawData = Sections[i].PointerToRawData - GetSecHeadAddr(PeBase, ".text")->SizeOfRawData + AlignSize;
        }
        // 3. .text区段之前的区段不改变,操作.text区段之后的区段
        if (!memcmp(Sections[i].Name, ".text", 7)) {
            bChangeFoa = TRUE;
        }
    }   
    pShareData->TextCompressSize = OutSize;
    GetSecHeadAddr(PeBase, ".text")->SizeOfRawData = AlignSize;
    pShareData->TextRVA = GetSecHeadAddr(PeBase, ".text")->VirtualAddress;
    PeSize = NewFileSize;
}
 
 
 
 
//令壳代码接管IAT表
VOID Pack::SetIatTo0() {
    // 在重定位之前设置
    pShareData->ImpTableVA = pOptionHead(PeBase)->DataDirectory[1].VirtualAddress;//备份原导入表RVA
    pOptionHead(PeBase)->DataDirectory[1].VirtualAddress = 0;    //清零
    pOptionHead(PeBase)->DataDirectory[12].VirtualAddress = 0;    //第[12]项也是导入表,也需要清零
}
//令壳代码接管IAT表
VOID Pack::SetIatTo0() {
    // 在重定位之前设置
    pShareData->ImpTableVA = pOptionHead(PeBase)->DataDirectory[1].VirtualAddress;//备份原导入表RVA
    pOptionHead(PeBase)->DataDirectory[1].VirtualAddress = 0;    //清零
    pOptionHead(PeBase)->DataDirectory[12].VirtualAddress = 0;    //第[12]项也是导入表,也需要清零
}
//备份TLS后清空TLS
VOID Pack::SetTls() {
    pShareData->TlsVirtualAddress = pOptionHead(PeBase)->DataDirectory[9].VirtualAddress;
    //如果存在TLS表
    if (pShareData->TlsVirtualAddress) {
        pOptionHead(PeBase)->DataDirectory[9].VirtualAddress = 0;
        DWORD TlsFoa = RvaToOffset(PeBase, pShareData->TlsVirtualAddress);
        auto TlsTable = (PIMAGE_TLS_DIRECTORY)(TlsFoa + PeBase);
        //备份TLS的回调函数
        pShareData->TlsCallBackTableVa = TlsTable->AddressOfCallBacks;
    }
}
//备份TLS后清空TLS
VOID Pack::SetTls() {
    pShareData->TlsVirtualAddress = pOptionHead(PeBase)->DataDirectory[9].VirtualAddress;
    //如果存在TLS表
    if (pShareData->TlsVirtualAddress) {
        pOptionHead(PeBase)->DataDirectory[9].VirtualAddress = 0;
        DWORD TlsFoa = RvaToOffset(PeBase, pShareData->TlsVirtualAddress);
        auto TlsTable = (PIMAGE_TLS_DIRECTORY)(TlsFoa + PeBase);
        //备份TLS的回调函数
        pShareData->TlsCallBackTableVa = TlsTable->AddressOfCallBacks;
    }
}
 
// 对壳代码进行重定位
VOID Pack::FixReloc(){
    DWORD OldImageBase = pOptionHead(DllBase)->ImageBase;
    DWORD NewImageBase = pOptionHead(PeBase)->ImageBase;
    DWORD OldSectionBase = GetSecHeadAddr(DllBase, ".text")->VirtualAddress;
    DWORD NewSectionBase = GetSecHeadAddr(PeBase, ".pack")->VirtualAddress;
    auto Relocs = (PIMAGE_BASE_RELOCATION)(DllBase + pOptionHead(DllBase)->DataDirectory[5].VirtualAddress);
    // 遍历重定位表
    while (Relocs->SizeOfBlock)    {
        DWORD OldProtect = 0;
        VirtualProtect((LPVOID)(DllBase + Relocs->VirtualAddress), 0x1000, PAGE_READWRITE, &OldProtect);
        TypeOffset* items = (TypeOffset*)(Relocs + 1);
        //重定位项数量
        int count = (Relocs->SizeOfBlock - 8) / 2;
        //遍历并修复重定位项
        for (int i = 0; i < count; ++i)    {           
            if (items[i].Type == 3)    {
                DWORD* item = (DWORD*)(pOptionHead(DllBase)->ImageBase + Relocs->VirtualAddress + items[i].Offset);
                *item = *item - OldImageBase - OldSectionBase + NewImageBase + NewSectionBase;
            }
        }
        VirtualProtect((LPVOID)(DllBase + Relocs->VirtualAddress), 0x1000, OldProtect, &OldProtect);
        Relocs = (PIMAGE_BASE_RELOCATION)(Relocs->SizeOfBlock + (DWORD)Relocs);
    }
    // 关闭源程序的随机基址
    //pOptionHead(PeBase)->DllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
}
// 对壳代码进行重定位
VOID Pack::FixReloc(){
    DWORD OldImageBase = pOptionHead(DllBase)->ImageBase;
    DWORD NewImageBase = pOptionHead(PeBase)->ImageBase;
    DWORD OldSectionBase = GetSecHeadAddr(DllBase, ".text")->VirtualAddress;
    DWORD NewSectionBase = GetSecHeadAddr(PeBase, ".pack")->VirtualAddress;
    auto Relocs = (PIMAGE_BASE_RELOCATION)(DllBase + pOptionHead(DllBase)->DataDirectory[5].VirtualAddress);
    // 遍历重定位表
    while (Relocs->SizeOfBlock)    {
        DWORD OldProtect = 0;
        VirtualProtect((LPVOID)(DllBase + Relocs->VirtualAddress), 0x1000, PAGE_READWRITE, &OldProtect);
        TypeOffset* items = (TypeOffset*)(Relocs + 1);
        //重定位项数量
        int count = (Relocs->SizeOfBlock - 8) / 2;
        //遍历并修复重定位项
        for (int i = 0; i < count; ++i)    {           
            if (items[i].Type == 3)    {
                DWORD* item = (DWORD*)(pOptionHead(DllBase)->ImageBase + Relocs->VirtualAddress + items[i].Offset);
                *item = *item - OldImageBase - OldSectionBase + NewImageBase + NewSectionBase;
            }
        }
        VirtualProtect((LPVOID)(DllBase + Relocs->VirtualAddress), 0x1000, OldProtect, &OldProtect);
        Relocs = (PIMAGE_BASE_RELOCATION)(Relocs->SizeOfBlock + (DWORD)Relocs);
    }
    // 关闭源程序的随机基址
    //pOptionHead(PeBase)->DllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
}
 
 
//备份并替换重定位表
VOID Pack::SetReloc() {
    //1.备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,将dll的重定位表替换到原程序的重定位表
    //2.在壳代码中,系统会帮我们修复壳代码的重定位,待原程序解密之后,在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位
    DWORD DllImageBase = pOptionHead(DllBase)->ImageBase;
    //备份原重定位表
    pShareData->dwRelocRva = pOptionHead(PeBase)->DataDirectory[5].VirtualAddress;
    pShareData->dwRelocSize = pOptionHead(PeBase)->DataDirectory[5].Size;
    pShareData->OldImageBase = pOptionHead(PeBase)->ImageBase;
    //Dll重定位表
    auto DllBaseReloc = (PIMAGE_BASE_RELOCATION)(pOptionHead(DllBase)->DataDirectory[5].VirtualAddress + DllImageBase);
    DWORD DllRelocaSize = pOptionHead(DllBase)->DataDirectory[5].Size;   
    //新增区段
    AddSection(".mysec", DllRelocaSize);
    auto NewSecHed = GetSecHeadAddr(PeBase, ".mysec");
    auto OldSecHed = GetSecHeadAddr(DllBase, ".text");
    auto PackSecHed = GetSecHeadAddr(PeBase, ".pack");
    auto NewRelocaSection = (PIMAGE_BASE_RELOCATION)(NewSecHed->PointerToRawData + PeBase);
    DWORD OldSectionAddr = (DWORD)(OldSecHed->VirtualAddress + DllBase);
 
    memcpy((DWORD*)NewRelocaSection, (DWORD*)(DllBaseReloc), DllRelocaSize);
    while (NewRelocaSection->VirtualAddress){
        //新的内存页起始RVA = 原RVA - 原段基址 +.pack段基址
        NewRelocaSection->VirtualAddress = NewRelocaSection->VirtualAddress - (OldSectionAddr -DllBase) + PackSecHed->VirtualAddress;
        NewRelocaSection = (PIMAGE_BASE_RELOCATION)(NewRelocaSection->SizeOfBlock + (DWORD)NewRelocaSection);
    }   
    //替换原程序重定位表
    pOptionHead(PeBase)->DataDirectory[5].VirtualAddress = NewSecHed->VirtualAddress;
    pOptionHead(PeBase)->DataDirectory[5].Size = DllRelocaSize;   
}
//备份并替换重定位表
VOID Pack::SetReloc() {
    //1.备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,将dll的重定位表替换到原程序的重定位表
    //2.在壳代码中,系统会帮我们修复壳代码的重定位,待原程序解密之后,在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位
    DWORD DllImageBase = pOptionHead(DllBase)->ImageBase;
    //备份原重定位表
    pShareData->dwRelocRva = pOptionHead(PeBase)->DataDirectory[5].VirtualAddress;
    pShareData->dwRelocSize = pOptionHead(PeBase)->DataDirectory[5].Size;
    pShareData->OldImageBase = pOptionHead(PeBase)->ImageBase;
    //Dll重定位表
    auto DllBaseReloc = (PIMAGE_BASE_RELOCATION)(pOptionHead(DllBase)->DataDirectory[5].VirtualAddress + DllImageBase);
    DWORD DllRelocaSize = pOptionHead(DllBase)->DataDirectory[5].Size;   
    //新增区段
    AddSection(".mysec", DllRelocaSize);
    auto NewSecHed = GetSecHeadAddr(PeBase, ".mysec");
    auto OldSecHed = GetSecHeadAddr(DllBase, ".text");
    auto PackSecHed = GetSecHeadAddr(PeBase, ".pack");
    auto NewRelocaSection = (PIMAGE_BASE_RELOCATION)(NewSecHed->PointerToRawData + PeBase);
    DWORD OldSectionAddr = (DWORD)(OldSecHed->VirtualAddress + DllBase);
 
    memcpy((DWORD*)NewRelocaSection, (DWORD*)(DllBaseReloc), DllRelocaSize);
    while (NewRelocaSection->VirtualAddress){
        //新的内存页起始RVA = 原RVA - 原段基址 +.pack段基址
        NewRelocaSection->VirtualAddress = NewRelocaSection->VirtualAddress - (OldSectionAddr -DllBase) + PackSecHed->VirtualAddress;
        NewRelocaSection = (PIMAGE_BASE_RELOCATION)(NewRelocaSection->SizeOfBlock + (DWORD)NewRelocaSection);
    }   
    //替换原程序重定位表
    pOptionHead(PeBase)->DataDirectory[5].VirtualAddress = NewSecHed->VirtualAddress;
    pOptionHead(PeBase)->DataDirectory[5].Size = DllRelocaSize;   
}
//添加一个新区段
VOID Pack::AddSection(LPCSTR Name, DWORD Size) {
    PIMAGE_DOS_HEADER pDos = pDosHead(PeBase);
    PIMAGE_NT_HEADERS pNt = pNtHead(PeBase);
    //获取需要添加的区段
    PIMAGE_SECTION_HEADER pLastSection = (IMAGE_FIRST_SECTION(pNt)) + (pNt->FileHeader.NumberOfSections - 1);
    PIMAGE_SECTION_HEADER pNewSection = pLastSection + 1;
    //Name
    memcpy(pNewSection->Name, Name, 7);
    //VirtualSize
    pNewSection->Misc.VirtualSize = AlignmentToSize(Size, pNt->OptionalHeader.SectionAlignment);
    //VirtualAddress = 最后一个区段的 VirtualAddress +最后一个区段内存大小
    pNewSection->VirtualAddress = pLastSection->VirtualAddress +
        AlignmentToSize(pLastSection->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
    //SizeOfRawData
    pNewSection->SizeOfRawData = AlignmentToSize(Size, pNt->OptionalHeader.FileAlignment);
    //PointerToRawData = 最后一个区段的 PointerToRawData + 最后一个区段文件大小
    pNewSection->PointerToRawData = pLastSection->PointerToRawData +
        AlignmentToSize(pLastSection->SizeOfRawData, pNt->OptionalHeader.FileAlignment);
    //Characteristics
    pNewSection->Characteristics = 0xE00000E0;
    //NumberOfSections
    pNt->FileHeader.NumberOfSections += 1;
    //SizeOfImage大小
    pNt->OptionalHeader.SizeOfImage += AlignmentToSize(pNewSection->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
    //从新分配空间,将新区段添加到堆空间中
    PeSize = pNewSection->SizeOfRawData + pNewSection->PointerToRawData;
    PeBase = (DWORD)realloc((VOID*)PeBase, PeSize);
    pNewSection = GetSecHeadAddr(PeBase, Name);
    memset((DWORD*)(pNewSection->PointerToRawData + PeBase), 0, pNewSection->SizeOfRawData);
    return;
}
//添加一个新区段
VOID Pack::AddSection(LPCSTR Name, DWORD Size) {
    PIMAGE_DOS_HEADER pDos = pDosHead(PeBase);
    PIMAGE_NT_HEADERS pNt = pNtHead(PeBase);
    //获取需要添加的区段
    PIMAGE_SECTION_HEADER pLastSection = (IMAGE_FIRST_SECTION(pNt)) + (pNt->FileHeader.NumberOfSections - 1);
    PIMAGE_SECTION_HEADER pNewSection = pLastSection + 1;
    //Name
    memcpy(pNewSection->Name, Name, 7);
    //VirtualSize
    pNewSection->Misc.VirtualSize = AlignmentToSize(Size, pNt->OptionalHeader.SectionAlignment);
    //VirtualAddress = 最后一个区段的 VirtualAddress +最后一个区段内存大小
    pNewSection->VirtualAddress = pLastSection->VirtualAddress +
        AlignmentToSize(pLastSection->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
    //SizeOfRawData
    pNewSection->SizeOfRawData = AlignmentToSize(Size, pNt->OptionalHeader.FileAlignment);
    //PointerToRawData = 最后一个区段的 PointerToRawData + 最后一个区段文件大小
    pNewSection->PointerToRawData = pLastSection->PointerToRawData +
        AlignmentToSize(pLastSection->SizeOfRawData, pNt->OptionalHeader.FileAlignment);
    //Characteristics
    pNewSection->Characteristics = 0xE00000E0;
    //NumberOfSections
    pNt->FileHeader.NumberOfSections += 1;
    //SizeOfImage大小
    pNt->OptionalHeader.SizeOfImage += AlignmentToSize(pNewSection->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
    //从新分配空间,将新区段添加到堆空间中
    PeSize = pNewSection->SizeOfRawData + pNewSection->PointerToRawData;
    PeBase = (DWORD)realloc((VOID*)PeBase, PeSize);
    pNewSection = GetSecHeadAddr(PeBase, Name);
    memset((DWORD*)(pNewSection->PointerToRawData + PeBase), 0, pNewSection->SizeOfRawData);
    return;
}
//拷贝区段数据
VOID Pack::CopySecData(CHAR* DestName) {   
    //.text的地址
    CHAR* Src = (CHAR*)(GetSecHeadAddr(DllBase, ".text")->VirtualAddress+DllBase);
    //.pack的地址
    CHAR* Dest = (CHAR*)(GetSecHeadAddr(PeBase, DestName)->PointerToRawData+PeBase);
    memcpy(Dest, Src, GetSecHeadAddr(DllBase,  ".text")->Misc.VirtualSize);
    return;
}
//拷贝区段数据
VOID Pack::CopySecData(CHAR* DestName) {   
    //.text的地址
    CHAR* Src = (CHAR*)(GetSecHeadAddr(DllBase, ".text")->VirtualAddress+DllBase);
    //.pack的地址
    CHAR* Dest = (CHAR*)(GetSecHeadAddr(PeBase, DestName)->PointerToRawData+PeBase);
    memcpy(Dest, Src, GetSecHeadAddr(DllBase,  ".text")->Misc.VirtualSize);
    return;
}
//将新文件写入磁盘
VOID Pack::WriteToFile(LPCSTR Path) {
    HANDLE hFile = CreateFile(Path, GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD WriteSize = 0;
    DWORD Ret = WriteFile(hFile, (LPVOID)PeBase, PeSize, &WriteSize, NULL);
    if (!Ret)
        print("写入文件失败");
    CloseHandle(hFile);
    return;
}
//将新文件写入磁盘
VOID Pack::WriteToFile(LPCSTR Path) {
    HANDLE hFile = CreateFile(Path, GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD WriteSize = 0;
    DWORD Ret = WriteFile(hFile, (LPVOID)PeBase, PeSize, &WriteSize, NULL);
    if (!Ret)
        print("写入文件失败");
    CloseHandle(hFile);
    return;
}
#include "../pack/Share.h"                  // 壳代码与加壳器之间共用的结构体类型头文件
#include"../aplib/aplib.h"                  // 压缩库头文件
#include <Windows.h>
#pragma comment(lib, "../aplib/aplib.lib")    // 压缩库
// 对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/section:.text,RWE")
// 去除所有导出函数和导出变量的名称粉碎
extern "C"{
    __declspec(dllexport) SHARE ShareData;                    //导出变量,用于壳代码与加壳器之间的通讯
    __declspec(dllexport) __declspec(naked) void start()     //导出函数地址,将会作为新的OEP
    {       
        _asm{
            mov eax, fs:[0x30]
            mov eax, [eax + 0x8]        //获取当前进程gImageBase
            mov gImageBase, eax
        }
        GetFunAdd();                    //获取GetProcAddress
        GetApi();                        //获取API
        CallShllFun();                    //密码弹窗
        UnCompression(ShareData);         //解压
        DecSection();                    //解密代码段
        DecIat(ShareData);                //加密IAT
        FixReloca(ShareData);            //修复重定位
        CallTls(ShareData);                //处理TLS       
        Debugging();                    //反调试
        __asm
        {
            mov eax, gImageBase                //获取当前进程gImageBase
            mov ebx, ShareData.DestOEP         //获取原程序的OEP
            add eax,ebx
            jmp eax
        }
    }
}
#include "../pack/Share.h"                  // 壳代码与加壳器之间共用的结构体类型头文件
#include"../aplib/aplib.h"                  // 压缩库头文件
#include <Windows.h>
#pragma comment(lib, "../aplib/aplib.lib")    // 压缩库
// 对 dll 的区段合并为.text区段,并设置区段属性为[读写执行]
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
#pragma comment(linker, "/section:.text,RWE")
// 去除所有导出函数和导出变量的名称粉碎
extern "C"{
    __declspec(dllexport) SHARE ShareData;                    //导出变量,用于壳代码与加壳器之间的通讯
    __declspec(dllexport) __declspec(naked) void start()     //导出函数地址,将会作为新的OEP
    {       
        _asm{
            mov eax, fs:[0x30]
            mov eax, [eax + 0x8]        //获取当前进程gImageBase
            mov gImageBase, eax
        }
        GetFunAdd();                    //获取GetProcAddress
        GetApi();                        //获取API
        CallShllFun();                    //密码弹窗
        UnCompression(ShareData);         //解压
        DecSection();                    //解密代码段
        DecIat(ShareData);                //加密IAT
        FixReloca(ShareData);            //修复重定位
        CallTls(ShareData);                //处理TLS       
        Debugging();                    //反调试
        __asm
        {
            mov eax, gImageBase                //获取当前进程gImageBase
            mov ebx, ShareData.DestOEP         //获取原程序的OEP
            add eax,ebx
            jmp eax
        }
    }
}
//定义GetProcAddress函数指针
typedef FARPROC(WINAPI* MYGetProcAddress)(HMODULE hModule, LPCSTR  lpProcName);
MYGetProcAddress MyGetProcAddress =0;
void GetFunAdd() {
    DWORD Ent;
    DWORD Eot;
    DWORD Eat;
    CHAR Buff[] = { 'G','e','t','P','r','o','c','A','d','d','r' ,'e','s','s','\0' };
    __asm
    {
        pushad
        mov eax,fs:[0x30]
        mov eax,[eax+0xc]
        mov eax,[eax+0x1c]        //第一个模块
        mov eax,[eax]            //kernel模块
        mov eax,[eax+0x8]        //kernel基址
        mov gKernelBase,eax       
        mov edx,[eax+0x3c]
        add edx,eax
        mov edx,[edx+0x78]
        add edx,eax                //导出表
        mov ebx,[edx+0x1c]
        add ebx,eax
        mov Eat,ebx                //地址表
        mov ebx,[edx+0x20]
        add ebx,eax
        mov Ent,ebx                //名称表
        mov ebx,[edx+0x24]
        add ebx,eax
        mov Eot,ebx                //序号表
 
        xor ebx, ebx
        jmp tag_FristCmp
    tag_CmpFunNameLoop:
        inc ebx
    tag_FristCmp:
        mov esi, Ent
        mov esi, [ebx * 0x4 + esi]                    //遍历名称表           
        lea esi, [esi + eax]                        //函数名称VA
        lea edi, dword ptr Buff                        //GetProAddress字符串地址
        mov ecx, 0xE                               //GetProAddress长度
        cld                                          //清除方向位
        repe cmpsb                                   //循环比较字符
        jne tag_cmpFunNameLoop
 
        mov esi,Eot                                   
        xor edi, edi
        mov di, [ebx * 2 + esi]                        //序号
        //使用序号在地址表中找到函数地址
        mov edx, Eat
        mov esi, [edx + edi * 4]                    //得到函数地址RVA
        lea eax, [esi + eax]                        //函数地址
        mov MyGetProcAddress,eax                    //保存函数地址到函数指针
        popad
    }
}
//定义GetProcAddress函数指针
typedef FARPROC(WINAPI* MYGetProcAddress)(HMODULE hModule, LPCSTR  lpProcName);
MYGetProcAddress MyGetProcAddress =0;
void GetFunAdd() {
    DWORD Ent;
    DWORD Eot;
    DWORD Eat;
    CHAR Buff[] = { 'G','e','t','P','r','o','c','A','d','d','r' ,'e','s','s','\0' };
    __asm
    {
        pushad
        mov eax,fs:[0x30]
        mov eax,[eax+0xc]
        mov eax,[eax+0x1c]        //第一个模块
        mov eax,[eax]            //kernel模块
        mov eax,[eax+0x8]        //kernel基址
        mov gKernelBase,eax       
        mov edx,[eax+0x3c]
        add edx,eax
        mov edx,[edx+0x78]
        add edx,eax                //导出表
        mov ebx,[edx+0x1c]
        add ebx,eax
        mov Eat,ebx                //地址表
        mov ebx,[edx+0x20]
        add ebx,eax
        mov Ent,ebx                //名称表
        mov ebx,[edx+0x24]
        add ebx,eax
        mov Eot,ebx                //序号表
 
        xor ebx, ebx
        jmp tag_FristCmp
    tag_CmpFunNameLoop:
        inc ebx
    tag_FristCmp:
        mov esi, Ent
        mov esi, [ebx * 0x4 + esi]                    //遍历名称表           
        lea esi, [esi + eax]                        //函数名称VA
        lea edi, dword ptr Buff                        //GetProAddress字符串地址
        mov ecx, 0xE                               //GetProAddress长度
        cld                                          //清除方向位
        repe cmpsb                                   //循环比较字符

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-1-4 15:59 被三一米田编辑 ,原因:
上传的附件:
收藏
免费 18
支持
分享
最新回复 (26)
雪    币: 3998
活跃值: (5131)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
感谢,拜读
2020-12-6 17:48
0
雪    币: 1246
活跃值: (4322)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
3
666,还在研究壳?
2020-12-7 22:23
0
雪    币: 2216
活跃值: (3276)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
4
是啊,现在研究壳的人不多了
2020-12-8 10:48
0
雪    币: 1140
活跃值: (266)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
楼主,链接失效了,请补发下,谢谢!
2020-12-8 11:34
0
雪    币: 803
活跃值: (4969)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
6
wx_Chao 楼主,链接失效了,请补发下,谢谢!
什么连接?我没贴链接上去啊
2020-12-8 18:14
0
雪    币: 34
活跃值: (76)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不错,学习了
2020-12-8 20:38
0
雪    币: 4886
活跃值: (4863)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
学习啦!
2020-12-8 23:16
0
雪    币: 1140
活跃值: (266)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
可以下载了,昨天附件不能下载,我还以为失效了。多谢~
2020-12-9 08:55
0
雪    币: 300
活跃值: (2532)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark
2020-12-9 10:44
0
雪    币: 1390
活跃值: (131)
能力值: ( LV5,RANK:62 )
在线值:
发帖
回帖
粉丝
11
熟悉的15格式
2020-12-17 19:29
0
雪    币: 1859
活跃值: (2245)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
12
怎么运行不了呢?
2021-3-3 16:47
0
雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
你好,我想问一下,3.1 手动获取函数地址那一部分,
void GetFunAdd() {
    DWORD Ent;
    DWORD Eot;
    DWORD Eat;
    CHAR Buff[] = { 'G','e','t','P','r','o','c','A','d','d','r' ,'e','s','s','\0' };
    __asm
    {
        pushad
        mov eax,fs:[0x30]
        mov eax,[eax+0xc]
        mov eax,[eax+0x1c]        //第一个模块
        mov eax,[eax]            //kernel模块
        mov eax,[eax+0x8]        //kernel基址
        mov gKernelBase,eax       
        mov edx,[eax+0x3c]
        add edx,eax
        mov edx,[edx+0x78]
        add edx,eax                //导出表
        mov ebx,[edx+0x1c]
        add ebx,eax
        mov Eat,ebx                //地址表
        mov ebx,[edx+0x20]
        add ebx,eax
        mov Ent,ebx                //名称表
        mov ebx,[edx+0x24]
        add ebx,eax
        mov Eot,ebx                //序号表
 
        xor ebx, ebx
        jmp tag_FristCmp
    tag_CmpFunNameLoop:
        inc ebx
    tag_FristCmp:
        mov esi, Ent
        mov esi, [ebx * 0x4 + esi]                    //遍历名称表           
        lea esi, [esi + eax]                        //函数名称VA
        lea edi, dword ptr Buff                        //GetProAddress字符串地址
        mov ecx, 0xE                               //GetProAddress长度
        cld                                          //清除方向位
        repe cmpsb                                   //循环比较字符
        jne tag_cmpFunNameLoop
 
        mov esi,Eot                                   
        xor edi, edi
        mov di, [ebx * 2 + esi]                        //序号
        //使用序号在地址表中找到函数地址
        mov edx, Eat
        mov esi, [edx + edi * 4]                    //得到函数地址RVA
        lea eax, [esi + eax]                        //函数地址
        mov MyGetProcAddress,eax                    //保存函数地址到函数指针
        popad
    }
}
这里fs:[30h],获取PEB结构地址,如果是x64和x86一样么?
我查了查资料,如果是x64平台的话,会有两个PEB什么的.....
2021-3-14 20:54
0
雪    币: 9626
活跃值: (1838)
能力值: ( LV5,RANK:73 )
在线值:
发帖
回帖
粉丝
14
wx_风凪 你好,我想问一下,3.1 手动获取函数地址那一部分, void GetFunAdd() { DWORD Ent; DWORD Eot; DWORD Eat; ...
在 x64 系统中,32 位程序会有两个 TEB 和 PEB:
TEB32:fs:[18h]
TEB64:TEB32 - 0x2000
两个 PEB 分别在这俩 TEB 中,名为 PEB32 和 PEB64
2021-3-15 00:29
0
雪    币: 5275
活跃值: (4021)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15

真是太详细 了。。

最后于 2021-3-15 01:03 被yoobaby编辑 ,原因:
2021-3-15 01:02
0
雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
Sprite雪碧 在 x64 系统中,32 位程序会有两个 TEB 和 PEB: TEB32:fs:[18h] TEB64:TEB32 - 0x2000 两个 PEB 分别在这俩 TEB 中,名为 PEB32 和 ...
谢谢指点。
2021-3-15 20:22
0
雪    币: 25
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
Sprite雪碧 在 x64 系统中,32 位程序会有两个 TEB 和 PEB: TEB32:fs:[18h] TEB64:TEB32 - 0x2000 两个 PEB 分别在这俩 TEB 中,名为 PEB32 和 ...

大佬,你好,我还想问一下,备份原程序的重定位表这里,如果原程序的重定位表的VirtualAdress是0的话(我试验了一个.exe文件,他的重定位表的VirtualAddress是0),在加壳后的程序执行.pack的壳代码时,手动修复原来exe的重定位表的那个函数,是不是就出问题了呢?因为ShareData.dwRelocRva是0,ShareData.dwRelocRva + gImageBase的地址就是0x00400000了,这样的话后面的程序员是不是就执行崩了? 

/////////////////////////////

不会标红,下边这个函数 “//备份重定位表“的下一行

VOID Pack::SetReloc() {
//1.备份原程序的重定位表地址,将原程序的重定位写入到通讯结构体中,将dll的重定位表替换到原程序的重定位表
//2.在壳代码中,系统会帮我们修复壳代码的重定位,待原程序解密之后,在壳代码中获取通讯结构体,获取原程序重定位表,修复原程序重定位

DWORD DllImageBase = pOptionHead(DllBase)->ImageBase;

//备份原重定位表
pShareData->dwRelocRva = pOptionHead(PeBase)->DataDirectory[5].VirtualAddress;
pShareData->dwRelocSize = pOptionHead(PeBase)->DataDirectory[5].Size;
pShareData->OldImageBase = pOptionHead(PeBase)->ImageBase;
//Dll重定位表
auto DllBaseReloc = (PIMAGE_BASE_RELOCATION)(pOptionHead(DllBase)->DataDirectory[5].VirtualAddress + DllImageBase);
DWORD DllRelocaSize = pOptionHead(DllBase)->DataDirectory[5].Size;

//新增区段
AddSection(".mysec", DllRelocaSize);
auto NewSecHed = GetSecHeadAddr(PeBase, ".mysec");
auto OldSecHed = GetSecHeadAddr(DllBase, ".text");
auto PackSecHed = GetSecHeadAddr(PeBase, ".pack");
auto NewRelocaSection = (PIMAGE_BASE_RELOCATION)(NewSecHed->PointerToRawData + PeBase);
DWORD OldSectionAddr = (DWORD)(OldSecHed->VirtualAddress + DllBase);

memcpy((DWORD*)NewRelocaSection, (DWORD*)(DllBaseReloc), DllRelocaSize);
while (NewRelocaSection->VirtualAddress)
{
//新的内存页起始RVA = 原RVA - 原段基址 +.pack段基址
NewRelocaSection->VirtualAddress = NewRelocaSection->VirtualAddress - (OldSectionAddr -DllBase) + PackSecHed->VirtualAddress;
NewRelocaSection = (PIMAGE_BASE_RELOCATION)(NewRelocaSection->SizeOfBlock + (DWORD)NewRelocaSection);
}
//替换原程序重定位表
pOptionHead(PeBase)->DataDirectory[5].VirtualAddress = NewSecHed->VirtualAddress;
pOptionHead(PeBase)->DataDirectory[5].Size = DllRelocaSize;
}

///////////////////////////////////

这个函数第一行

void FixReloca(SHARE ShareData) {

auto Relocs = (PIMAGE_BASE_RELOCATION)(ShareData.dwRelocRva + gImageBase);

DWORD OldProtect = 0;

while (Relocs->VirtualAddress)

{

DWORD OldProtect = 0;

MyVirtualProtect((LPVOID)(gImageBase + Relocs->VirtualAddress), 0x1000, PAGE_READWRITE, &OldProtect);


TypeOffset* items = (TypeOffset*)(Relocs + 1);

//遍历重定位项

int count = (Relocs->SizeOfBlock - 8) / 2;

for (int i = 0; i < count; ++i)

{

if (items[i].Type == 3)

{

DWORD Temp = 0;

// 计算出每一个需要重定位的数据所在的地址

DWORD* item = (DWORD*)(gImageBase + Relocs->VirtualAddress + items[i].Offset);

// 这里操作的是需要重定位的数据,通常是代码段(不可写)

*item = *item + gImageBase - ShareData.OldImageBase;

}

}

MyVirtualProtect((LPVOID)(gImageBase + Relocs->VirtualAddress), 0x1000, OldProtect, &OldProtect);

// 下一个重定位块

Relocs = (PIMAGE_BASE_RELOCATION)(Relocs->SizeOfBlock + (DWORD)Relocs);

}

}


2021-3-15 20:38
0
雪    币: 5609
活跃值: (5038)
能力值: ( LV9,RANK:143 )
在线值:
发帖
回帖
粉丝
18
加密iat的部分有个问题,如果被加载的dll导出的是个变量而不是函数,当成函数来加密会使得程序在使用该变量时出错直接崩溃。
2021-8-4 16:00
0
雪    币: 803
活跃值: (4969)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
19
wx_风凪 你好,我想问一下,3.1 手动获取函数地址那一部分, void GetFunAdd() { DWORD Ent; DWORD Eot; DWORD Eat; ...
https://www.vergiliusproject.com/这个网址可以在线查看windows内核结构体,x86和x64就可以看出端倪,但是好像需要梯子
2021-8-6 09:42
0
雪    币: 299
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
不错不错,支持
2022-5-26 21:41
0
雪    币: 1935
活跃值: (4180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
非常好,感谢分享
2022-5-27 09:48
0
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
mark,感谢分享
2022-5-27 10:33
0
雪    币: 631
活跃值: (3026)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
23
mark
2022-6-2 08:32
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
大牛就是牛
2023-7-27 16:54
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
你好,请问一下使用OllyDBG检查IAT加密,出现内存地址无法找到怎么办
2024-3-31 18:39
0
游客
登录 | 注册 方可回帖
返回
//