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

写在前面

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

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

小结

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

IMAGE_IMPORT_DESCRIPTOR
IMAGE_IMPORT_DESCRIPTOR
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
IMAGE_IMPORT_BY_NAME
IMAGE_IMPORT_BY_NAME
"Kernel32.dll"
IAT Functions Table
Import Dll's Function Count Table
Buffer of Import Dll Names
Import FuctionNames Table
FirstThunk RVA Table
ShellCode For IAT
ShellCode For IAT Dispatch
TLS Buffer
TLS Buffer Shadow
ShellCode For TLS
ShellCode For TLS Dispatcher
Relocation Table For TLS
Compressed Data Field
ShellCode For Decompression
ShellCode For Loading
GetProcAddress
LoadLibraryA
Kernel32.dll
GetLastError
OpenProcess
CloseHandle
ExitThread
……
27
9
5
36
……
VCRUNTIME140D.dll\0KERNEL32.dll\0……
GetLastError\0OpenProcess\0……
0x20150
0x201F8
0x20D38
0x20EE0
……
OEP (.wing)
Decompress Code Section
XOR-Decode Code Section
Decrypt IAT
Enable TLS Dispatch
Running
ASM
ASM
ASM
0x1601200
0x1608E00
0x1615200
0x161E800
……
0
0
0
0
……
ASM
IMAGE_BASE_RELOCATION
IMAGE_BASE_RELOCATION
Compressed Binary Data
ASM
ASM
WingSection Memory Layout
By. WingSummer (寂静的羽夏)

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

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 @   寂静的羽夏  阅读(214)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?

喜欢请打赏

扫描二维码打赏

支付宝打赏

点击右上角即可分享
微信分享提示