羽夏壳世界——实现篇小结

写在前面

  此系列是本人一个字一个字码出来的,包括代码实现和效果截图。如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我

你如果是从中间插过来看的,请仔细阅读 羽夏壳世界——序 ,方便学习本教程。

小结

  前面我们详细介绍了本项目的实现的每一个细节,最终的结构图如下:

  介绍完了实现,我们来简单谈谈加密相关的流程,先看相关代码:

BOOL CWingProtect::Proctect(UINT protections)
{
    auto ret = TRUE;
    auto reloc = peinfo.OptionalHeaderDllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
    auto antidebug = ProtectionsHasFlag(protections,Protections::AnitDebug);
    auto fakecode = ProtectionsHasFlag(protections, Protections::JunkCode);

    if (EnableIATEncrypt && ProtectionsHasFlag(protections, Protections::IATEncrypt))
    {
        ret &= IATEncrypt(antidebug,fakecode);
    }

    DestoryRelocation();
    ProcessTLS(ProtectionsHasFlag(protections, Protections::TLSEncrypt));

    if (ProtectionsHasFlag(protections, Protections::XOREncrypt))
    {
        ret &= XORCodeSection(reloc, fakecode);
        reloc = FALSE;
    }

    if (ProtectionsHasFlag(protections, Protections::Compress))
    {
        ret &= CompressSeciton(reloc,fakecode);
        reloc = FALSE;        
    }

    //最后根据保护,生成 ShellCode
    GenerateLoadingShellCode(protections, fakecode);

    return ret;
}

  首先,加密的时候首先判断有没有IAT加密标识,有的话启用加密,然后摧毁导入表,处理TLS,如果有异或加密,就先异或。接着如果有压缩,就压缩,最后生成引导汇编代码,指导整个PE的解密和执行。
  下面我们看看GenerateLoadingShellCode具体细节:

//
// GNU AFFERO GENERAL PUBLIC LICENSE
//Version 3, 19 November 2007
//
//Copyright(C) 2007 Free Software Foundation, Inc.
//Everyone is permitted to copyand distribute verbatim copies
//of this license document, but changing it is not allowed.
// Author : WingSummer (寂静的羽夏)
// 
//Warning: You can not use it for any commerical use,except you get 
// my AUTHORIZED FORM ME!This project is used for tutorial to teach
// the beginners what is the PE structure and how the packer of the PE files works.
// 
// 注意:你不能将该项目用于任何商业用途,除非你获得了我的授权!该项目用来
// 教初学者什么是 PE 结构和 PE 文件加壳程序是如何工作的。
//
// Statement : It cost me about one week to write all these nearly 2500 lines of code. 
// The Assembly Engine of this project is asmjit , which is a Amazing and Fantastic toolkit 
// for generating assembly code, of course it has more powerful functions.Please keep these 
// statements  and declarations.Thanks!
// 
// 声明:该项目的代码编写用了我将近一个周的时间来写差不多2500行代码,使用的汇编引擎是 asmjit ,
// 它是一个能够生成汇编代码的强大而惊人的工具,当然它还有更多的功能。请保留这些声明,万分感谢。
//

void CWingProtect::GenerateLoadingShellCode(UINT protections, BOOL FakeCode)
{
    auto buffer = GetPointerByOffset(peinfo.WingSecitonBuffer, peinfo.PointerOfWingSeciton);

    encryptInfo.ShellCodeLoader = (UINT)peinfo.PointerOfWingSeciton;

    using namespace asmjit;
    if (is64bit)
    {
        Environment env(Arch::kX64);
        CodeHolder holder;
        holder.init(env);
        x86::Assembler a(&holder);

        x86::Mem mem;
        mem.setSegment(x86::gs);
        mem.setOffset(0x60);

        a.mov(x86::rax, mem);
        a.mov(x86::rax, x86::qword_ptr(x86::rax, 0x10));

        auto rvabase = peinfo.AnalysisInfo.MinAvailableVirtualAddress;
#define AddRVABase(offset) ((UINT)offset + (UINT)rvabase)

        if (ProtectionsHasFlag(protections,Protections::IATEncrypt))
        {
            a.push(x86::rax);
            a.add(x86::rax, AddRVABase(encryptInfo.IATShellCode));
            a.call(x86::rax);
            a.pop(x86::rax);
            a.nop();
        }

        if (ProtectionsHasFlag(protections,Protections::Compress))
        {
            a.push(x86::rax);
            a.add(x86::rax, AddRVABase(encryptInfo.ShellCodeDeCompress));
            a.call(x86::rax);
            a.pop(x86::rax);
            a.nop();
        }

        if (ProtectionsHasFlag(protections,Protections::XOREncrypt))
        {
            a.push(x86::rax);
            a.add(x86::rax, AddRVABase(encryptInfo.XORDecodeShellCode));
            a.call(x86::rax);
            a.pop(x86::rax);
            a.nop();
        }

        if (HasTLS)
        {
            Label loop = a.newLabel();
            Label loop_j = a.newLabel();
            Label addn = a.newLabel();

            a.push(x86::rax);
            a.push(x86::rdi);
            a.push(x86::rsi);
            a.push(x86::rbx);

            a.mov(x86::rsi, encryptInfo.OldTLSCallBacks);
            a.mov(x86::rdi, AddRVABase(encryptInfo.TLSBuffer));
            a.add(x86::rsi, x86::rax);
            a.add(x86::rdi, x86::rax);

            a.bind(loop);
            a.mov(x86::rbx, x86::qword_ptr(x86::rsi));
            a.test(x86::ebx, x86::ebx);
            a.jz(loop_j);

            a.cmp(x86::rbx, x86::rax);        //如果没开 TLS 保护,则表示 RVA ,需要转化为地址
            a.ja(addn);
            a.add(x86::rbx, x86::rax);
            a.bind(addn);

            a.mov(x86::qword_ptr(x86::rdi), x86::rbx);
            a.add(x86::rsi, 8);
            a.add(x86::rdi, 8);
            a.jmp(loop);
            a.bind(loop_j);

            a.pop(x86::rbx);
            a.pop(x86::rsi);
            a.pop(x86::rdi);
            a.pop(x86::rax);
            a.nop();
        }

        a.add(x86::rax, peinfo.AddressOfEntryPoint);
        a.jmp(x86::rax);

        BYTE* shellcode = a.bufferData();
        UINT codesize = (UINT)holder.codeSize();

        memcpy_s(buffer, codesize, shellcode, codesize);
        peinfo.PointerOfWingSeciton += codesize;
    }
    else
    {
        Environment env(Arch::kX86);
        CodeHolder holder;
        holder.init(env);
        x86::Assembler a(&holder);

        x86::Mem mem;
        mem.setSegment(x86::fs);
        mem.setOffset(0x30);

        a.mov(x86::eax, mem);
        a.mov(x86::eax, x86::qword_ptr(x86::eax, 0x10));
        a.push(x86::ebx);

        auto rvabase = peinfo.AnalysisInfo.MinAvailableVirtualAddress;
#define AddRVABase(offset) ((UINT)offset + (UINT)rvabase)

        if (ProtectionsHasFlag(protections, Protections::IATEncrypt))
        {
            a.push(x86::eax);
            a.mov(x86::ebx, AddRVABase(encryptInfo.IATShellCode));
            a.add(x86::ebx, x86::eax);
            a.call(x86::ebx);
            a.pop(x86::eax);
            a.nop();
        }

        if (ProtectionsHasFlag(protections, Protections::Compress))
        {
            a.push(x86::eax);
            a.mov(x86::ebx, AddRVABase(encryptInfo.ShellCodeDeCompress));
            a.add(x86::ebx, x86::eax);
            a.call(x86::ebx);
            a.pop(x86::eax);
            a.nop();
        }

        if (ProtectionsHasFlag(protections, Protections::XOREncrypt))
        {
            a.push(x86::eax);
            a.mov(x86::ebx, AddRVABase(encryptInfo.XORDecodeShellCode));
            a.add(x86::ebx, x86::eax);
            a.call(x86::ebx);
            a.pop(x86::eax);
            a.nop();
        }

        a.pop(x86::ebx);
        a.add(x86::eax, peinfo.AddressOfEntryPoint);
        a.jmp(x86::eax);

        BYTE* shellcode = a.bufferData();
        UINT codesize = (UINT)holder.codeSize();

        memcpy_s(buffer, codesize, shellcode, codesize);
        peinfo.PointerOfWingSeciton += codesize;
    }
}

  通过生成的汇编我们可以看出,每一个负责解密的ShellCode都会通过call的方式进行调用返回,如果TLS开启了保护,就等所有解密完毕后,填写正确的TLS派发入口函数,然后跳回原来的入口地址,开始执行之后的正常流程。
  有关该加密壳是实现就这么多,剩余的小总结性的说明将会在下一篇介绍。

下一篇

  羽夏壳世界——结语

posted @ 2022-04-12 16:17  寂静的羽夏  阅读(204)  评论(0编辑  收藏  举报