首页
社区
课程
招聘
[原创]实现一个压缩壳,并给它加点“料”
发表于: 2022-8-12 21:20 126826

[原创]实现一个压缩壳,并给它加点“料”

2022-8-12 21:20
126826

学完科锐第三阶段壳的课程内容之后,我发现,实现压缩壳,必须对PE格式十分熟悉,其次,解压缩代码需要编写shellcode,也是十分麻烦的环节。有了两者的结合,我们才能写好一个真正的压缩壳。

首先上一张图,让大家直观地感受到一个壳程序是如何运行起来的。
左边是壳PE,壳程序有一个PE头,节表1是空节,用来存放解压缩后的原程序PE,节表2此时存储的是压缩后的原PE。节表3则是壳代码节,壳PE运行起来后,首先就是进入入口点,运行节表3的代码,解压缩节表2,然后将结果覆盖PE头+节表1的位置,修复完导入表、重定位表,jmp到原程序的入口点处即可。
图片描述
原理不变,我这里加了点“料”,新增了节4和节5,存储了相关的信息,让压缩壳的脱壳过程变难,往后看就知道了。

1.为了生成一个新的壳PE,我们一步步来,首先是PE头,俗话说靠山吃山,靠水吃水,这个PE头我就直接拿原程序的PE头来代替了,只不过需要改一些数据:

2.新PE头里一些需要修改的数据,比如SizeOfImage,我们目前还没有,需要等我们构造出节表1、2、3、4、5之后,才知道。接下来,先构造节表1的表头,节表1是个空节,它的大小只要够存放原程序的节表即可,多给一点也没关系,我这里直接给了SizeOfImage。(由于是空节,所以这里并不需要考虑节表1的数据内容)

3.接着是节表2,这个节要存放原PE的压缩数据,先设计表头(使用了PointerToRelocations和PointerToLinenumbers这两个没啥用的字段,存放压缩大小信息,留着给后面shellcode用)

然后将PE压缩,压缩前我把节表、导入表、重定位表保存并清空,到时候由shellcode进行还原。

4.接着是节表3,该节表存放的是解压缩PE、还原导入表、重定位表,运行原程序的至关重要的shellcode,先设计表头

至于节表3的数据内容,也就是shellcode,等我把节表、PE设计完,我再说
5.接着是节表4,节表4是我额外增加的一个,用来存储步骤3中保存的原节表表头、原导入表、原重定位表,首先设计节表4表头

然后把刚才保存的原节表表头、原导入表、原重定位表信息,按顺序写入到缓冲区里。

6.还剩最后一个节表5,是一个空节,壳代码还原原PE时,要还原导入表,于是这个节的作用就体现出来了,shellcode在这里玩了一波偷梁换柱,直接毙掉了x64dbg的脱壳后导入表自动修复功能,等会介绍shellcode的时候你们就知道了。设计节表5的表头

至此,新的壳PE结构我们就设计好了,然后将新PE头、节表234写入到新文件(节表1、5是空节,不用写入),就大功告成,加壳完毕!

由于壳PE可能是随机基址,所以执行shellcode时,一定要确保它的代码跟地址无关。我的shellcode是在VS上编译的,为了保证VS不会生成多余的代码,要修改以下几个设置:

然后就是最麻烦的shellcode代码编写了。首先要清楚shellcode代码的功能:

1.要解压缩,那么必定要调用库的API,如果直接调用的话,call的就是死地址,违背了地址无关原则。那么使用LoadLibrary然后GetProcAddress?显然也不行,LoadLibrary和GetProcAddress也是死地址,所以我们要自己实现LoadLibrary和GetProcAddress的功能。
首先通过_PEB来拿到kernel32的模块基址

然后通过kernel32的导出函数表,拿到GetProcAddress函数地址,代码如下:

有了GetProcAddress函数地址和kernel32的基址,同理就能拿到LoadLibrary函数地址了(注意定义字符串变量时,用单个字符一个一个排列,在汇编里面看就是db出来的,否则字符串会有一个常量区地址,影响shellcode的通用性)

2.有了LoadLibrary和GetProcAddress,就可以使用任何库函数了,解压缩便是小菜一碟。

3.解压缩完毕,得到了原PE,接下来就是将原PE覆盖到现在的PE头+节表1的地方,同时还原节表头、导入表和重定位表,相当于LoadPE的功能了

这里重点要介绍的,就是还原导入表的过程,也是整篇文章的核心主题,加点“料”。我在遍历还原导入表时,并没有直接将API的地址填入到IAT里,而是将节表5的地址,从起始位置开始,每隔16个字节,将地址填入到IAT里,然后在对应的节表5地址上填入push 真实函数地址 + retn的汇编指令。这样一来,原PE程序运行调用API时,就会跳到节表5里面,再从节表5里面跳到真实API地址,直接干掉了x64dbg的脱壳导入表自动修复功能。嘿嘿~~

最后来看看效果,对扫雷进行加壳,加壳后的程序可以正常运行

先用x64找到真实入口点,进行一波dump操作
图片描述
dump后无法直接运行
图片描述
然后去x64里使用自动搜索修复导入表的功能,可以看到,IAT这里存放的压根就不是真实API的地址,所以x64也无法识别出来。
图片描述
搞定,收工!

NumberOfSections --节表数量,要改为5
AddressOfEntryPoint --入口点,要改为节表3里的代码入口
SizeOfImage --PE在内存中的大小,要改为新的PE的内存大小
pSecHdr --节表头,要拓展为5个节表
 
void CPacker::GetNewPeHdr()
{
    //拷贝原PE的PE头
    m_dwNewPeHdrSize = m_pNtHdr->OptionalHeader.SizeOfHeaders;
    m_pNewPeHdr = new BYTE[m_dwNewPeHdrSize];
    CopyMemory(m_pNewPeHdr, m_pDosHdr, m_dwNewPeHdrSize);
 
    //修改
    auto pDosHdr = (PIMAGE_DOS_HEADER)m_pNewPeHdr;
    auto pNtHdr = (PIMAGE_NT_HEADERS)(m_pNewPeHdr + pDosHdr->e_lfanew);
    auto pSecHdr = (PIMAGE_SECTION_HEADER)
        ((LPBYTE)&pNtHdr->OptionalHeader + pNtHdr->FileHeader.SizeOfOptionalHeader);
 
    pNtHdr->FileHeader.NumberOfSections = 5;
    pNtHdr->OptionalHeader.AddressOfEntryPoint = m_newSecHdr[2].VirtualAddress;
    pNtHdr->OptionalHeader.SizeOfImage = m_newSecHdr[4].VirtualAddress + m_newSecHdr[4].Misc.VirtualSize;
    //清空DataDirectory目录
    ZeroMemory(pNtHdr->OptionalHeader.DataDirectory, sizeof(pNtHdr->OptionalHeader.DataDirectory));
 
    //修改新的节表头
    CopyMemory(pSecHdr, m_newSecHdr, sizeof(m_newSecHdr));
 
}
NumberOfSections --节表数量,要改为5
AddressOfEntryPoint --入口点,要改为节表3里的代码入口
SizeOfImage --PE在内存中的大小,要改为新的PE的内存大小
pSecHdr --节表头,要拓展为5个节表
 
void CPacker::GetNewPeHdr()
{
    //拷贝原PE的PE头
    m_dwNewPeHdrSize = m_pNtHdr->OptionalHeader.SizeOfHeaders;
    m_pNewPeHdr = new BYTE[m_dwNewPeHdrSize];
    CopyMemory(m_pNewPeHdr, m_pDosHdr, m_dwNewPeHdrSize);
 
    //修改
    auto pDosHdr = (PIMAGE_DOS_HEADER)m_pNewPeHdr;
    auto pNtHdr = (PIMAGE_NT_HEADERS)(m_pNewPeHdr + pDosHdr->e_lfanew);
    auto pSecHdr = (PIMAGE_SECTION_HEADER)
        ((LPBYTE)&pNtHdr->OptionalHeader + pNtHdr->FileHeader.SizeOfOptionalHeader);
 
    pNtHdr->FileHeader.NumberOfSections = 5;
    pNtHdr->OptionalHeader.AddressOfEntryPoint = m_newSecHdr[2].VirtualAddress;
    pNtHdr->OptionalHeader.SizeOfImage = m_newSecHdr[4].VirtualAddress + m_newSecHdr[4].Misc.VirtualSize;
    //清空DataDirectory目录
    ZeroMemory(pNtHdr->OptionalHeader.DataDirectory, sizeof(pNtHdr->OptionalHeader.DataDirectory));
 
    //修改新的节表头
    CopyMemory(pSecHdr, m_newSecHdr, sizeof(m_newSecHdr));
 
}
//空节
    strcpy((char*)m_newSecHdr[0].Name, ".cr42");
    m_newSecHdr[0].Misc.VirtualSize = m_pNtHdr->OptionalHeader.SizeOfImage;
    m_newSecHdr[0].VirtualAddress = m_pSecHdr[0].VirtualAddress;
    m_newSecHdr[0].SizeOfRawData = 0;
    m_newSecHdr[0].PointerToRawData = 0;
    m_newSecHdr[0].Characteristics =
        IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
//空节
    strcpy((char*)m_newSecHdr[0].Name, ".cr42");
    m_newSecHdr[0].Misc.VirtualSize = m_pNtHdr->OptionalHeader.SizeOfImage;
    m_newSecHdr[0].VirtualAddress = m_pSecHdr[0].VirtualAddress;
    m_newSecHdr[0].SizeOfRawData = 0;
    m_newSecHdr[0].PointerToRawData = 0;
    m_newSecHdr[0].Characteristics =
        IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
//压缩数据节
    strcpy((char*)m_newSecHdr[1].Name, ".data");
    m_newSecHdr[1].Misc.VirtualSize = GetAlign(m_dwComSecSize, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[1].VirtualAddress = m_newSecHdr[0].VirtualAddress + m_newSecHdr[0].Misc.VirtualSize;
    m_newSecHdr[1].SizeOfRawData = m_dwComSecSize;
    m_newSecHdr[1].PointerToRawData = m_pNtHdr->OptionalHeader.SizeOfHeaders;
    m_newSecHdr[1].Characteristics = IMAGE_SCN_MEM_READ;
 
    m_newSecHdr[1].PointerToRelocations = m_dwComSize; //压缩后大小
    m_newSecHdr[1].PointerToLinenumbers = m_dwSrcPeSize;//压缩前大小
//压缩数据节
    strcpy((char*)m_newSecHdr[1].Name, ".data");
    m_newSecHdr[1].Misc.VirtualSize = GetAlign(m_dwComSecSize, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[1].VirtualAddress = m_newSecHdr[0].VirtualAddress + m_newSecHdr[0].Misc.VirtualSize;
    m_newSecHdr[1].SizeOfRawData = m_dwComSecSize;
    m_newSecHdr[1].PointerToRawData = m_pNtHdr->OptionalHeader.SizeOfHeaders;
    m_newSecHdr[1].Characteristics = IMAGE_SCN_MEM_READ;
 
    m_newSecHdr[1].PointerToRelocations = m_dwComSize; //压缩后大小
    m_newSecHdr[1].PointerToLinenumbers = m_dwSrcPeSize;//压缩前大小
bool CPacker::GetCompressData()
{
    COMPRESSOR_HANDLE hCompressor = NULL;
    BOOL Success = CreateCompressor(
        COMPRESS_ALGORITHM_XPRESS_HUFF,
        NULL,
        &hCompressor
    );
 
    m_pComData = new BYTE[m_dwSrcPeSize + 0x28];
    LPBYTE m_pSrcPeTmp = new BYTE[m_dwSrcPeSize];
    CopyMemory(m_pSrcPeTmp, m_pSrcPe, m_dwSrcPeSize);
 
    PIMAGE_DOS_HEADER m_pDosHdrTmp = (PIMAGE_DOS_HEADER)m_pSrcPeTmp;
    PIMAGE_NT_HEADERS m_pNtHdrTmp = (PIMAGE_NT_HEADERS)(m_pSrcPeTmp + m_pDosHdrTmp->e_lfanew);
    PIMAGE_SECTION_HEADER m_pSecHdrTmp = (PIMAGE_SECTION_HEADER)
        ((LPBYTE)&m_pNtHdrTmp->OptionalHeader + m_pNtHdrTmp->FileHeader.SizeOfOptionalHeader);
 
    //1.在压缩前,把节表保存并清空
    nSecNum = m_pNtHdrTmp->FileHeader.NumberOfSections;
    CopyMemory(m_pSaveSecHdr, m_pSecHdrTmp, nSecNum * 40);
    ZeroMemory(m_pSecHdrTmp, nSecNum * 40);
 
    //2.把导入表保存并清空
    m_pImportAddr = m_pNtHdrTmp->OptionalHeader.DataDirectory[1].VirtualAddress;
    nImpSize = m_pNtHdrTmp->OptionalHeader.DataDirectory[1].Size;
    ZeroMemory(&(m_pNtHdrTmp->OptionalHeader.DataDirectory[1]), 8);
 
    //3.把重定位表保存并清空
    m_pRelocAddr = m_pNtHdrTmp->OptionalHeader.DataDirectory[5].VirtualAddress;
    nRelocSize = m_pNtHdrTmp->OptionalHeader.DataDirectory[5].Size;
    ZeroMemory(&(m_pNtHdrTmp->OptionalHeader.DataDirectory[5]), 8);
 
 
 
    Success = Compress(
        hCompressor,
        m_pSrcPeTmp,
        m_dwSrcPeSize,
        m_pComData,
        m_dwSrcPeSize + 0x28,
        &m_dwComSize
    );
 
 
    return true;
}
bool CPacker::GetCompressData()
{
    COMPRESSOR_HANDLE hCompressor = NULL;
    BOOL Success = CreateCompressor(
        COMPRESS_ALGORITHM_XPRESS_HUFF,
        NULL,
        &hCompressor
    );
 
    m_pComData = new BYTE[m_dwSrcPeSize + 0x28];
    LPBYTE m_pSrcPeTmp = new BYTE[m_dwSrcPeSize];
    CopyMemory(m_pSrcPeTmp, m_pSrcPe, m_dwSrcPeSize);
 
    PIMAGE_DOS_HEADER m_pDosHdrTmp = (PIMAGE_DOS_HEADER)m_pSrcPeTmp;
    PIMAGE_NT_HEADERS m_pNtHdrTmp = (PIMAGE_NT_HEADERS)(m_pSrcPeTmp + m_pDosHdrTmp->e_lfanew);
    PIMAGE_SECTION_HEADER m_pSecHdrTmp = (PIMAGE_SECTION_HEADER)
        ((LPBYTE)&m_pNtHdrTmp->OptionalHeader + m_pNtHdrTmp->FileHeader.SizeOfOptionalHeader);
 
    //1.在压缩前,把节表保存并清空
    nSecNum = m_pNtHdrTmp->FileHeader.NumberOfSections;
    CopyMemory(m_pSaveSecHdr, m_pSecHdrTmp, nSecNum * 40);
    ZeroMemory(m_pSecHdrTmp, nSecNum * 40);
 
    //2.把导入表保存并清空
    m_pImportAddr = m_pNtHdrTmp->OptionalHeader.DataDirectory[1].VirtualAddress;
    nImpSize = m_pNtHdrTmp->OptionalHeader.DataDirectory[1].Size;
    ZeroMemory(&(m_pNtHdrTmp->OptionalHeader.DataDirectory[1]), 8);
 
    //3.把重定位表保存并清空
    m_pRelocAddr = m_pNtHdrTmp->OptionalHeader.DataDirectory[5].VirtualAddress;
    nRelocSize = m_pNtHdrTmp->OptionalHeader.DataDirectory[5].Size;
    ZeroMemory(&(m_pNtHdrTmp->OptionalHeader.DataDirectory[5]), 8);
 
 
 
    Success = Compress(
        hCompressor,
        m_pSrcPeTmp,
        m_dwSrcPeSize,
        m_pComData,
        m_dwSrcPeSize + 0x28,
        &m_dwComSize
    );
 
 
    return true;
}
//代码节
    strcpy((char*)m_newSecHdr[2].Name, ".text");
    m_newSecHdr[2].Misc.VirtualSize = GetAlign(m_dwCodeSecSize, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[2].VirtualAddress = m_newSecHdr[1].VirtualAddress + m_newSecHdr[1].Misc.VirtualSize;
    m_newSecHdr[2].SizeOfRawData = m_dwCodeSecSize;
    m_newSecHdr[2].PointerToRawData = m_newSecHdr[1].PointerToRawData + m_newSecHdr[1].SizeOfRawData;
    m_newSecHdr[2].Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
//代码节
    strcpy((char*)m_newSecHdr[2].Name, ".text");
    m_newSecHdr[2].Misc.VirtualSize = GetAlign(m_dwCodeSecSize, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[2].VirtualAddress = m_newSecHdr[1].VirtualAddress + m_newSecHdr[1].Misc.VirtualSize;
    m_newSecHdr[2].SizeOfRawData = m_dwCodeSecSize;
    m_newSecHdr[2].PointerToRawData = m_newSecHdr[1].PointerToRawData + m_newSecHdr[1].SizeOfRawData;
    m_newSecHdr[2].Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
//存放原节表、导入表、重定位表的节
    strcpy((char*)m_newSecHdr[3].Name, ".info");
    m_newSecHdr[3].Misc.VirtualSize = GetAlign(m_dwTableSecSize, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[3].VirtualAddress = m_newSecHdr[2].VirtualAddress + m_newSecHdr[2].Misc.VirtualSize;
    m_newSecHdr[3].SizeOfRawData = m_dwTableSecSize;
    m_newSecHdr[3].PointerToRawData = m_newSecHdr[2].PointerToRawData + m_newSecHdr[2].SizeOfRawData;
    m_newSecHdr[3].Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
//存放原节表、导入表、重定位表的节
    strcpy((char*)m_newSecHdr[3].Name, ".info");
    m_newSecHdr[3].Misc.VirtualSize = GetAlign(m_dwTableSecSize, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[3].VirtualAddress = m_newSecHdr[2].VirtualAddress + m_newSecHdr[2].Misc.VirtualSize;
    m_newSecHdr[3].SizeOfRawData = m_dwTableSecSize;
    m_newSecHdr[3].PointerToRawData = m_newSecHdr[2].PointerToRawData + m_newSecHdr[2].SizeOfRawData;
    m_newSecHdr[3].Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
bool CPacker::GetTable()
{
    m_dwTableSize = nSecNum * 40 + 4 + 8 + 8;
    m_pTable = new BYTE[m_dwTableSize];
    RtlCopyMemory(m_pTable, &nSecNum, 4);
    RtlCopyMemory(m_pTable + 4, m_pSaveSecHdr, nSecNum * 40);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40, &m_pImportAddr, 4);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40 + 4, &nImpSize, 4);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40 + 4 + 4, &m_pRelocAddr, 4);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40 + 4 + 4 + 4, &nRelocSize, 4);
 
    return true;
}
bool CPacker::GetTable()
{
    m_dwTableSize = nSecNum * 40 + 4 + 8 + 8;
    m_pTable = new BYTE[m_dwTableSize];
    RtlCopyMemory(m_pTable, &nSecNum, 4);
    RtlCopyMemory(m_pTable + 4, m_pSaveSecHdr, nSecNum * 40);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40, &m_pImportAddr, 4);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40 + 4, &nImpSize, 4);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40 + 4 + 4, &m_pRelocAddr, 4);
    RtlCopyMemory(m_pTable + 4 + nSecNum * 40 + 4 + 4 + 4, &nRelocSize, 4);
 
    return true;
}
//绕过x64搜索导入表的节(空节)
    strcpy((char*)m_newSecHdr[4].Name, ".imp");
    m_newSecHdr[4].Misc.VirtualSize = GetAlign(0x10000, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[4].VirtualAddress = m_newSecHdr[3].VirtualAddress + m_newSecHdr[3].Misc.VirtualSize;
    m_newSecHdr[4].SizeOfRawData = 0;
    m_newSecHdr[4].PointerToRawData = m_newSecHdr[3].PointerToRawData + m_newSecHdr[2].SizeOfRawData;
    m_newSecHdr[4].Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
//绕过x64搜索导入表的节(空节)
    strcpy((char*)m_newSecHdr[4].Name, ".imp");
    m_newSecHdr[4].Misc.VirtualSize = GetAlign(0x10000, m_pNtHdr->OptionalHeader.SectionAlignment);
    m_newSecHdr[4].VirtualAddress = m_newSecHdr[3].VirtualAddress + m_newSecHdr[3].Misc.VirtualSize;
    m_newSecHdr[4].SizeOfRawData = 0;
    m_newSecHdr[4].PointerToRawData = m_newSecHdr[3].PointerToRawData + m_newSecHdr[2].SizeOfRawData;
    m_newSecHdr[4].Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
bool CPacker::WriteNewPe(CString strNewPe)
{
    //创建文件
    HANDLE hFile = CreateFile(strNewPe,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
 
    //写入PE头
    DWORD dwBytesWrited = 0;
    WriteFile(hFile, m_pNewPeHdr, m_dwNewPeHdrSize, &dwBytesWrited, NULL);
 
    //写入数据节
    WriteFile(hFile, m_pComSec, m_dwComSecSize, &dwBytesWrited, NULL);
 
    //写入代码节
    WriteFile(hFile, m_pCodeSec, m_dwCodeSecSize, &dwBytesWrited, NULL);
 
    //写入存放表数据节
    WriteFile(hFile, m_pTableSec, m_dwTableSecSize, &dwBytesWrited, NULL);
 
    CloseHandle(hFile);
 
    return true;
}
bool CPacker::WriteNewPe(CString strNewPe)
{
    //创建文件
    HANDLE hFile = CreateFile(strNewPe,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
 
    //写入PE头
    DWORD dwBytesWrited = 0;
    WriteFile(hFile, m_pNewPeHdr, m_dwNewPeHdrSize, &dwBytesWrited, NULL);
 
    //写入数据节
    WriteFile(hFile, m_pComSec, m_dwComSecSize, &dwBytesWrited, NULL);
 
    //写入代码节
    WriteFile(hFile, m_pCodeSec, m_dwCodeSecSize, &dwBytesWrited, NULL);
 
    //写入存放表数据节
    WriteFile(hFile, m_pTableSec, m_dwTableSecSize, &dwBytesWrited, NULL);
 
    CloseHandle(hFile);
 
    return true;
}
1.使用Release版(Debug会加地址有关代码)
2.不使用main函数,自己定义一个,放在链接器->高级->入口点(main不是程序真正入口点)
3.关掉代码生成->安全检查
4.关掉增强指令集
5.关掉全程序优化
1.使用Release版(Debug会加地址有关代码)
2.不使用main函数,自己定义一个,放在链接器->高级->入口点(main不是程序真正入口点)
3.关掉代码生成->安全检查
4.关掉增强指令集
5.关掉全程序优化
1.解压缩节表2里面的压缩数据
2.将解压缩数据覆盖到PE头处,连带着空节表1也被覆盖
3.还原节表、导入表、重定位表
1.解压缩节表2里面的压缩数据
2.将解压缩数据覆盖到PE头处,连带着空节表1也被覆盖
3.还原节表、导入表、重定位表
HMODULE GetKernel32()
{
    HMODULE hKer;
    __asm {
 
        mov eax, dword ptr fs:[0x30]
        mov eax, dword ptr[eax + 0x0C]
        mov eax, dword ptr[eax + 0x0C]
        mov eax, dword ptr[eax]
        mov eax, dword ptr[eax]
        mov eax, dword ptr[eax + 0x18]
        mov hKer, eax
    }
 
    return hKer;
}
HMODULE GetKernel32()
{
    HMODULE hKer;
    __asm {
 
        mov eax, dword ptr fs:[0x30]
        mov eax, dword ptr[eax + 0x0C]
        mov eax, dword ptr[eax + 0x0C]
        mov eax, dword ptr[eax]
        mov eax, dword ptr[eax]
        mov eax, dword ptr[eax + 0x18]
        mov hKer, eax
    }
 
    return hKer;
}
FARPROC MyGetProcAddress(HMODULE hMod, LPCSTR lpProcName) {
 
    IMAGE_DOS_HEADER* pDosHdr;
    IMAGE_NT_HEADERS* pNTHdr;
    IMAGE_EXPORT_DIRECTORY* pExpDir;
    DWORD pAddrTbl;
    DWORD pNameTbl;
    DWORD pOrdTbl;
 
    //解析dos头
    pDosHdr = (IMAGE_DOS_HEADER*)hMod;
 
    //nt头
    pNTHdr = (IMAGE_NT_HEADERS*)(pDosHdr->e_lfanew + (DWORD)hMod);
 
    //获取导出表
    pExpDir = (IMAGE_EXPORT_DIRECTORY*)(pNTHdr->OptionalHeader.DataDirectory[0].VirtualAddress + (DWORD)hMod);
 
    //导出函数地址表
    pAddrTbl = (DWORD)(pExpDir->AddressOfFunctions + (DWORD)hMod);
 
    //导出函数名称表
    pNameTbl = (DWORD)(pExpDir->AddressOfNames + (DWORD)hMod);
 
    //导出序号表
    pOrdTbl = (DWORD)(pExpDir->AddressOfNameOrdinals + (DWORD)hMod);
 
    //判断是序号还是名称
    if ((int)lpProcName & 0xffff0000) {
 
        //名称
        int i = 0;
        while (i < pExpDir->NumberOfNames) {
 
            //获取名称地址
            int nNameOff = (int)(*(DWORD*)(pNameTbl + i * 4) + (DWORD)hMod);
 
            //字符串比较
            if (((char*)nNameOff)[0] == 'G'&& ((char*)nNameOff)[1] == 'e'&& ((char*)nNameOff)[2] == 't'&&
                ((char*)nNameOff)[3] == 'P'&& ((char*)nNameOff)[4] == 'r'&& ((char*)nNameOff)[5] == 'o'&&
                ((char*)nNameOff)[6] == 'c'&& ((char*)nNameOff)[7] == 'A'&& ((char*)nNameOff)[8] == 'd'&&
                ((char*)nNameOff)[9] == 'd'&& ((char*)nNameOff)[10] == 'r'&& ((char*)nNameOff)[11] == 'e'&&
                ((char*)nNameOff)[12] == 's'&& ((char*)nNameOff)[13] == 's') {
 
                //找到了, 从导出序号表取出函数地址下标
                int nOrdinal = *(WORD*)(pOrdTbl + i * 2);
 
                //从导出地址表,下标寻址,获取导出函数地址
                int nFuncAddr = *(DWORD*)(pAddrTbl + nOrdinal * 4);
 
 
 
                //不是转发
                nFuncAddr += (int)hMod;
 
 
 
 
                //返回地址
                if (nFuncAddr != NULL) {
 
                    return (FARPROC)nFuncAddr;
                }
            }
 
            i++;
 
        }
    }
 
    else {
 
        //序号
        int nOrdinal = (DWORD)lpProcName - pExpDir->Base;
 
        //从导出地址表,下标寻址,获取导出函数地址
        int nFuncAddr = *(DWORD*)(pAddrTbl + nOrdinal * 4);
 
        //返回地址
        if (nFuncAddr != NULL) {
 
            return (FARPROC)(nFuncAddr + (DWORD)hMod);
        }
 
    }
 
 
    return 0;
}
FARPROC MyGetProcAddress(HMODULE hMod, LPCSTR lpProcName) {
 
    IMAGE_DOS_HEADER* pDosHdr;
    IMAGE_NT_HEADERS* pNTHdr;
    IMAGE_EXPORT_DIRECTORY* pExpDir;
    DWORD pAddrTbl;
    DWORD pNameTbl;
    DWORD pOrdTbl;
 
    //解析dos头
    pDosHdr = (IMAGE_DOS_HEADER*)hMod;
 
    //nt头
    pNTHdr = (IMAGE_NT_HEADERS*)(pDosHdr->e_lfanew + (DWORD)hMod);
 
    //获取导出表
    pExpDir = (IMAGE_EXPORT_DIRECTORY*)(pNTHdr->OptionalHeader.DataDirectory[0].VirtualAddress + (DWORD)hMod);
 
    //导出函数地址表
    pAddrTbl = (DWORD)(pExpDir->AddressOfFunctions + (DWORD)hMod);
 
    //导出函数名称表
    pNameTbl = (DWORD)(pExpDir->AddressOfNames + (DWORD)hMod);
 
    //导出序号表
    pOrdTbl = (DWORD)(pExpDir->AddressOfNameOrdinals + (DWORD)hMod);
 
    //判断是序号还是名称
    if ((int)lpProcName & 0xffff0000) {
 
        //名称
        int i = 0;
        while (i < pExpDir->NumberOfNames) {
 
            //获取名称地址
            int nNameOff = (int)(*(DWORD*)(pNameTbl + i * 4) + (DWORD)hMod);
 
            //字符串比较
            if (((char*)nNameOff)[0] == 'G'&& ((char*)nNameOff)[1] == 'e'&& ((char*)nNameOff)[2] == 't'&&
                ((char*)nNameOff)[3] == 'P'&& ((char*)nNameOff)[4] == 'r'&& ((char*)nNameOff)[5] == 'o'&&
                ((char*)nNameOff)[6] == 'c'&& ((char*)nNameOff)[7] == 'A'&& ((char*)nNameOff)[8] == 'd'&&
                ((char*)nNameOff)[9] == 'd'&& ((char*)nNameOff)[10] == 'r'&& ((char*)nNameOff)[11] == 'e'&&
                ((char*)nNameOff)[12] == 's'&& ((char*)nNameOff)[13] == 's') {
 
                //找到了, 从导出序号表取出函数地址下标
                int nOrdinal = *(WORD*)(pOrdTbl + i * 2);
 
                //从导出地址表,下标寻址,获取导出函数地址
                int nFuncAddr = *(DWORD*)(pAddrTbl + nOrdinal * 4);
 
 
 
                //不是转发
                nFuncAddr += (int)hMod;
 
 
 
 
                //返回地址
                if (nFuncAddr != NULL) {
 
                    return (FARPROC)nFuncAddr;
                }
            }
 
            i++;
 
        }
    }
 
    else {
 
        //序号
        int nOrdinal = (DWORD)lpProcName - pExpDir->Base;
 
        //从导出地址表,下标寻址,获取导出函数地址
        int nFuncAddr = *(DWORD*)(pAddrTbl + nOrdinal * 4);
 
        //返回地址
        if (nFuncAddr != NULL) {
 
            return (FARPROC)(nFuncAddr + (DWORD)hMod);
        }
 
    }
 
 
    return 0;
}
char szLoadLibrary[] = { 'L', 'o','a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' };
    pEnv->pfnLoadLibraryA = (PFN_LoadLibraryA)pEnv->pfnGetProcAddress(hKer, szLoadLibrary);
char szLoadLibrary[] = { 'L', 'o','a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' };
    pEnv->pfnLoadLibraryA = (PFN_LoadLibraryA)pEnv->pfnGetProcAddress(hKer, szLoadLibrary);
//有了LoadLibrary和GetProcAddress,就可以使用任意函数了
    //获取解压缩相关函数
 
    char szCab[] = { 'C','a','b','i','n','e','t', '\0' };
    HMODULE hCab = pEnv->pfnLoadLibraryA(szCab);
 
    char szCreateDecompressor[] = { 'C','r','e','a','t','e','D','e','c','o','m','p','r','e','s','s','o','r', '\0' };
    pEnv->pfnCreateDecompressor = (PFN_CreateDecompressor)pEnv->pfnGetProcAddress(hCab, szCreateDecompressor);
 
    char szDecompress[] = { 'D','e','c','o','m','p','r','e','s','s', '\0' };
    pEnv->pfnDecompress = (PFN_Decompress)pEnv->pfnGetProcAddress(hCab, szDecompress);
 
    char szVirtualAlloc[] = { 'V','i','r','t','u','a','l','A','l','l','o','c', '\0' };
    pEnv->pfnVirtualAlloc = (PFN_VirtualAlloc)pEnv->pfnGetProcAddress(hKer, szVirtualAlloc);
 
    char szVirtualProtect[] = { 'V','i','r','t','u','a','l','P','r','o','t','e','c','t','\0' };
    pEnv->pfnVirtualProtect = (PFN_VirtualProtect)pEnv->pfnGetProcAddress(hKer, szVirtualProtect);
 
 
//解压缩
 
    LPBYTE pPEBuff = (LPBYTE)env.pfnVirtualAlloc(NULL, dwDeComSize, MEM_COMMIT, PAGE_READWRITE);
 
    DECOMPRESSOR_HANDLE hDecompressor;
    BOOL bSuccess = env.pfnCreateDecompressor(
        COMPRESS_ALGORITHM_XPRESS_HUFF,
        NULL,
        &hDecompressor
    );
 
    DWORD dwDecompressedBufferSize = 0;
    bSuccess = env.pfnDecompress(
        hDecompressor,
        pComData,
        dwComSize,
        pPEBuff,
        dwDeComSize,
        &dwDecompressedBufferSize
    );
//有了LoadLibrary和GetProcAddress,就可以使用任意函数了
    //获取解压缩相关函数
 

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

最后于 2022-8-23 12:21 被橘喵Cat编辑 ,原因:
收藏
免费 12
支持
分享
打赏 + 80.00雪花
打赏次数 1 雪花 + 80.00
 
赞赏  Editor   +80.00 2022/08/25 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (11)
雪    币: 10088
活跃值: (4491)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2022-8-13 11:40
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2022-8-16 14:42
0
雪    币: 74
活跃值: (748)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2022-8-17 11:08
0
雪    币: 3751
活跃值: (3156)
能力值: ( LV8,RANK:147 )
在线值:
发帖
回帖
粉丝
5
看样子仅支持32位程序,楼主可以改一改,支持64位
2022-8-18 10:21
0
雪    币: 631
活跃值: (3026)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2022-8-18 15:40
0
雪    币: 4543
活跃值: (3042)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2022-8-20 11:14
0
雪    币: 1243
活跃值: (1449)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2022-8-22 17:27
0
雪    币: 986
活跃值: (1693)
能力值: ( LV6,RANK:97 )
在线值:
发帖
回帖
粉丝
9
Roger 看样子仅支持32位程序,楼主可以改一改,支持64位
还没学64位汇编
2022-8-23 20:29
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
老哥可以甩一份github嘛 学不太费QAQ
2022-9-1 07:06
0
雪    币: 152
活跃值: (1637)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
11
这个壳怕不是很难遇到了。UPX典型
2022-9-1 18:05
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
有源码咩,礼貌求一份
2024-9-23 19:08
0
游客
登录 | 注册 方可回帖
返回
//