0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C++写壳详细教程(下)

jf_78858299 来源:看雪论坛九阳道人 作者:看雪论坛九阳道人 2023-03-17 14:49 次阅读

2. 处理stub.dll

配置stub工程

将工程设置release版本,如果不想代码被优化,可以禁止优化。

大概流程如下:

① 将数据段,只读数据段和代码段进行合并

② 编写代码获取API的地址

③ 加入混淆指令,反调试

④ 解密/解压缩

⑤ 加密IAT等等

之后会把存根文件stub.dll的.data,.rdata这2个区段合并到.text段并设置为可读可写可执行属性,需要前置代码

//把数据段融入代码段
#pragma comment(linker,"/merge:.data=.text")
//把只读数据段融入代码段
#pragma comment(linker,"/merge:.rdata=.text")
//设置代码段为可读可写可执行
#pragma comment(linker,"/section:.text,RWE")

根据之前说的已经知道壳区段就是新添加的区段了,里面将保存移植过来的stub的.text段里的所有内容,称之为壳代码。

而使用壳代码的时候要注意,因为加完壳后,在壳代码中无法使用导入表,因此,需要自己动态获取需要使用的API函数的地址。

只要获取到LoadLibraryExA和GetProcAddress两个函数的地址,我们就可以根据LoadLibraryExA来获取任意模块dll的基地址,再使用GetProcAddress函数获取到任意API函数的地址了。

根据kernel32基址可获取到GetProcAddress地址。

下面是我获取kernel32基址的内联汇编代码。

__asm
{
push esi;
mov esi, fs:[0x30]; //得到PEB地址
mov esi, [esi + 0xc]; //指向PEB_LDR_DATA结构的首地址
mov esi, [esi + 0x1c];//一个双向链表的地址
mov esi, [esi]; //得到第2个条目kernelBase的链表
mov esi, [esi]; //得到第3个条目kernel32的链表(win10系统)
mov esi, [esi + 0x8]; //kernel32.dll地址
mov g_hKernel32, esi;
pop esi;
}

然后是获取GetProcAddress函数的汇编代码,可以使用C语言方式获取,但我觉得用汇编写,它就这样赤裸裸呈现,能更加清晰的了解找到一个函数地址的过程。

//获取GetProcAddress函数地址
void MyGetFunAddress()
{
__asm
{
pushad;
mov ebp, esp;
sub esp, 0xc;
mov edx, g_hKernel32;
mov esi, [edx + 0x3c]; //NT头的RVA
lea esi, [esi + edx]; //NT头的VA
mov esi, [esi + 0x78]; //Export的Rva
lea edi, [esi + edx]; //Export的Va

mov esi, [edi + 0x1c]; //Eat的Rva
lea esi, [esi + edx]; //Eat的Va
mov[ebp - 0x4], esi; //保存Eat

mov esi, [edi + 0x20]; //Ent的Rva
lea esi, [esi + edx]; //Ent的Va
mov[ebp - 0x8], esi; //保存Ent

mov esi, [edi + 0x24]; //Eot的Rva
lea esi, [esi + edx]; //Eot的Va
mov[ebp - 0xc], esi; //保存Eot

xor ecx, ecx;
jmp _First;
_Zero:
inc ecx;
_First:
mov esi, [ebp - 0x8]; //Ent的Va
mov esi, [esi + ecx * 4]; //FunName的Rva

lea esi, [esi + edx]; //FunName的Va
cmp dword ptr[esi], 050746547h;// 47657450 726F6341 64647265 7373;
jne _Zero; // 上面的16进制是GetProcAddress的ASCII
cmp dword ptr[esi + 4], 041636f72h;
jne _Zero;
cmp dword ptr[esi + 8], 065726464h;
jne _Zero;
cmp word ptr[esi + 0ch], 07373h;
jne _Zero;

xor ebx,ebx
mov esi, [ebp - 0xc]; //Eot的Va
mov bx, [esi + ecx * 2]; //得到序号

mov esi, [ebp - 0x4]; //Eat的Va
mov esi, [esi + ebx * 4]; //FunAddr的Rva
lea eax, [esi + edx]; //FunAddr
mov MyGetProcAddress, eax;
add esp, 0xc;
popad;
}
}

然后再获取下MessageBoxW函数,弹出一个对话框,测试是否成功。

//运行函数
void RunFun()
{
MyLoadLibraryExA = (FuLoadLibraryExA)MyGetProcAddress(g_hKernel32, "LoadLibraryExA");
g_hUser32 = MyLoadLibraryExA("user32.dll", 0, 0);
MyMessageBoxW = (FuMessageBoxW)MyGetProcAddress(g_hUser32, "MessageBoxW");
MyMessageBoxW(0, L"大家好我是一个壳", L"提示", 0);
}

它在运行原代码之前先运行了壳代码,测试成功。

图片

四、代码段加密

我们在逆向破解的时候通常第一方法是找到关键字符串,关键代码等,他们都是存在于代码段的,那么只要把代码段进行加密,这种方式就不可行了。

先在加壳器中加密,这使用简单的亦或加密。

//加密代码段
//1.获取代码段首地址
char* pTarText = GetSecHeader(pTarBuff, ".text")->PointerToRawData + pTarBuff;
//2.获取代码段实际大小
int nSize = GetSecHeader(pTarBuff, ".text")->Misc.VirtualSize;
for (int i = 0; i < nSize; ++i)
{
pTarText[i] ^= 0x15;
}

再到壳代码里解密,自己写了一个对比字符串的函数。

//自写strcmp
int StrCmpText(const char* pStr, char* pBuff)
{
int nFlag = 1;
__asm
{
mov esi, pStr;
mov edi, pBuff;
mov ecx, 0x6;
cld;
repe cmpsb;
je _end;
mov nFlag, 0;
_end:
}
return nFlag;
}

//解密
void Decryption()
{
//获取.text的区段头
auto pNt = GetNtHeader((char*)g_hModule);
DWORD dwSecNum = pNt->FileHeader.NumberOfSections;
auto pSec = IMAGE_FIRST_SECTION(pNt);

//找到代码区段
for (size_t i = 0; i < dwSecNum; i++)
{
if (StrCmpText(".text", (char*)pSec[i].Name))
{
pSec += i;
break;
}
}

//获取代码段首地址
char* pTarText = pSec->VirtualAddress + (char*)g_hModule;
int nSize = pSec->Misc.VirtualSize;
DWORD old = 0;
//解密代码段
MyVirtualProtect(pTarText, nSize, PAGE_READWRITE, &old);
for (int i = 0; i < nSize; ++i) {
pTarText[i] ^= 0x15;
}
MyVirtualProtect(pTarText, nSize, old, &old);
}

五、压缩

压缩是一个比较复杂的过程,对于一个主要功能的加密的壳来说,压缩也有一定的加密效果,如果使用了一些加密库加密,即使你压缩了,会发现加壳后的文件比没加壳之前还要大!

图片

这说一下压缩大概思路,首先不能压缩头部,考虑到后面要处理TLS,还有一个程序的图标在资源段,所以不压缩这两个段。

在加壳器中把原文件的中除了.tls和.rsrc段的其他段的数据一个一个的按顺序取出来,然后拼接在一起,然后对这份拼接后数据进行一个整体的压缩,之后需要再添加一个区段专门用于存放压缩后的数据,这个过程中,需要把压缩后的区段的文件偏移和文件大小都清零,如下图所示,把.tsl段和.rsrc段移动到头部的后面。

值得注意的是没有处理TLS时要把TLS表的RVA和大小清零,TLS在数据目录表的第九项。

auto pData = GetOptHeader(pTarBuff)->DataDirectory;
pData[9].Size = 0;
pData[9].VirtualAddress = 0;

运行时,先在壳代码中进行解压缩,再解密,然后程序就能正常运行了。

到此一个简单的加密压缩壳就完成了,在这个过程中实际出现了很多bug,因为涉及到DLL文件无法用VS调试, 所以使用OD或者x64dbg进行调试,推荐使用x64dbg(x32dbg),这个软件一直在更新,而且字符串提示更友好,更方便快捷。OD主要用于脱壳破解,逆向还是x64dbg更方便。

最后再说一下VS2017使用配置:

有2个工程文件 一个是加壳器,一个是sutb。

加壳器使用x32debug编译

sutb使用x32Release编译

找到工程所在文件夹,新建一个bin目录,把这两个工程属性中的输出目录改为bin,这样操作起来方便一些,不改也行,但是加载stub时路径就要填写正确才行。

图片

一个壳的基本框架就搭建完成了,而加壳主要是为了防止被别人破解,所以接下来就可以执行加密操作了,下一次再说说IAT加密,Hash加密,动态解密,反调试等技术吧。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • WINDOWS
    +关注

    关注

    3

    文章

    3545

    浏览量

    88693
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73650
  • PE文件
    +关注

    关注

    0

    文章

    4

    浏览量

    5441
收藏 人收藏

    评论

    相关推荐

    C++一个http服务器

    本篇文章不会涉及到很多复杂的概念,也没有很难读懂的模板函数,代码简单可读,本篇文章送给每一个想自己用C++一个http服务器的小伙伴!高手们、大佬们当然可以不用看的啦!
    发表于 09-30 10:47 2238次阅读

    详细讲解C++串口的相关知识

    大家可以先参考一这篇blog,C++串口通信里面详细讲解了C++串口的相关知识,以及一些函数的讲解。下面我也会根据他的blog再讲解。二、实现过程1、打开串口:使用函数:HANDLE
    发表于 08-24 06:56

    详述不用c++网页的理由

    C++在web开发中地位如何,进来一探究竟吧。
    的头像 发表于 12-22 10:07 5953次阅读

    基于fpgrowth的c++实现详细资料免费下载

    本文档的主要内容详细介绍的是基于fpgrowth的c++实现详细资料免费下载
    发表于 08-02 08:00 1次下载

    如何提高cc++的安全编程能力?《CC++安全编码》带你详细学习

    ,既详细阐述了C/C++语言及其相关库固有的安全问题和陷阱,系统总结了导致软件漏洞的各种常见编码错误,并给出了应对错误的解决方案;又对C/C++
    发表于 08-28 08:00 0次下载

    如何进行高质量的CC++编程?高质量C++C编程指南详细资料免费下载

    本文档的作用内容详细介绍的是如何进行高质量的CC++编程?高质量C++C编程指南详细资料免费
    发表于 09-10 08:00 30次下载

    VISUAL C++教程之VISUAL C++的安装和使用方法

    本文档的主要内容详细介绍的是VISUAL C++教程之VISUAL C++的安装和使用方法资料免费下载。
    发表于 12-27 16:32 19次下载
    VISUAL <b class='flag-5'>C++</b>教程之VISUAL <b class='flag-5'>C++</b>的安装和使用方法

    C++的cast最完整最详细的解释资料说明

    本文档的主要内容详细介绍的是C++的cast最完整最详细的解释资料说明。
    发表于 01-29 15:26 0次下载
    <b class='flag-5'>C++</b>的cast最完整最<b class='flag-5'>详细</b>的解释资料说明

    C++程序设计教程之C++的初步知识的详细资料说明

    C++程序设计教程之C++的初步知识的详细资料说明包括了:1. 从CC++,2 . 最简单的C++
    发表于 03-14 14:48 31次下载
    <b class='flag-5'>C++</b>程序设计教程之<b class='flag-5'>C++</b>的初步知识的<b class='flag-5'>详细</b>资料说明

    C++程序设计教程之C++工具的详细资料说明

    本文档的详细介绍的是C++程序设计教程之C++工具的详细资料说明主要内容包括了:1. 异常处理,2. 命名空间,3. 使用早期的函数库
    发表于 03-14 16:39 4次下载
    <b class='flag-5'>C++</b>程序设计教程之<b class='flag-5'>C++</b>工具的<b class='flag-5'>详细</b>资料说明

    C++程序设计的基础知识初步了解C++的资料免费下载

    本文档的主要内容详细介绍的是C++程序设计的基础知识初步了解C++的资料免费下载包括了:1 认识C++,2 C++的现状和发展,3
    发表于 06-10 08:00 25次下载
    <b class='flag-5'>C++</b>程序设计的基础知识初步了解<b class='flag-5'>C++</b>的资料免费下载

    C++语言编码规范详细说明

    本文档的主要内容详细介绍的是C++语言编码规范详细说明。
    发表于 01-07 16:19 14次下载
    <b class='flag-5'>C++</b>语言编码规范<b class='flag-5'>详细</b>说明

    C语言和C++的特点与用法详细说明

    本文档的主要内容详细介绍的是C语言和C++的特点与用法详细说明。
    的头像 发表于 12-26 10:58 4420次阅读

    qt用C++的2048小游戏源代码

    qt用C++的2048小游戏源代码
    发表于 09-27 11:48 1次下载

    C++详细教程(上)

    本文基于Windows平台对PE文件加的项目,经过一个月的缓冲,决定复习总结及分享的我的心得。
    的头像 发表于 03-17 14:49 821次阅读
    <b class='flag-5'>C++</b><b class='flag-5'>写</b><b class='flag-5'>壳</b><b class='flag-5'>详细</b>教程(上)