羽夏壳世界——实现篇小结
写在前面
此系列是本人一个字一个字码出来的,包括代码实现和效果截图。如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读 羽夏壳世界——序 ,方便学习本教程。
小结
前面我们详细介绍了本项目的实现的每一个细节,最终的结构图如下:
介绍完了实现,我们来简单谈谈加密相关的流程,先看相关代码:
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
派发入口函数,然后跳回原来的入口地址,开始执行之后的正常流程。
有关该加密壳是实现就这么多,剩余的小总结性的说明将会在下一篇介绍。
下一篇
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
本文来自博客园,作者:寂静的羽夏 ,一个热爱计算机技术的菜鸟
转载请注明原文链接:https://www.cnblogs.com/wingsummer/p/16135659.html
本文来自博客园,作者:寂静的羽夏 ,一个热爱计算机技术的菜鸟
转载请注明原文链接:https://www.cnblogs.com/wingsummer/p/16135659.html