安全矩阵

 找回密码
 立即注册
搜索
查看: 350|回复: 0

无可执行权限加载 ShellCode 技术原理

[复制链接]

57

主题

57

帖子

181

积分

注册会员

Rank: 2

积分
181
发表于 2024-6-16 17:02:35 | 显示全部楼层 |阅读模式
1. 介绍

无需解密,无需 X 内存,直接加载运行 R 内存中的 ShellCode 密文。

x64 项目: https://github.com/HackerCalico/No_X_Memory_ShellCode_Loader

2. 常规 ShellCode 加载器

在大家刚开始学习 ShellCode 的时候,通常不明白 ShellCode 本身是什么,而是仅仅学习了以下加载器的写法:

unsigned char buf[] = "ShellCode 密文";

void* p = VirtualAlloc(NULL, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, buf, sizeof buf);

// ShellCode 解密

((void(*)())p)();

上述加载器直接将 ShellCode 密文写入 RWX (可读可写可执行) 内存解密,进而调用。此时进程内存中出现了少见且敏感的 RWX 内存空间,容易被查杀。

为了避免使用 RWX 内存属性,大家开始先将 ShellCode 密文写入 RW 内存解密,再将内存属性改为 RX 运行。如果 Hook CS 直接生成的后门程序,就会发现在执行一些敏感功能时,后门采取了这种来回修改内存属性的操作,容易被行为查杀。

于是我开始思考是否存在完全规避以上问题的方法。

3. ShellCode 作用原理

为了找到新的 ShellCode 加载方式,我决定深入了解 ShellCode。

ShellCode 是一段地址无关机器码。机器码就是代码对应的汇编指令的硬编码,通常存在于程序文件的 .text 段中,比如以下 MyMessageBoxA_Not 函数:

该函数的硬编码与汇编指令:

48 83 EC 38       ------> SUB RSP, 0X38
C6 44 24 20 00    ------> MOV BYTE PTR [RSP + 0X20], 0
41 B9 40 00 00 00 ------> MOV R9D, 0X40
4C 8D 44 24 20    ------> LEA R8, [RSP + 0X20]
48 8D 54 24 20    ------> LEA RDX, [RSP + 0X20]
33 C9             ------> XOR ECX, ECX
FF 15 2F 12 00 00 ------> CALL QWORD PTR [RIP + 0X122F]
48 83 C4 38       ------> ADD RSP, 0X38
C3                ------> RET

可以看到通过 Call 指令调用 MessageBoxA 这个 Windows API,但是很明显 MessageBoxA 的地址存储在其他位置,所以如果单独运行这段机器码会运行失败。

ShellCode 地址无关,意味着不直接使用这种外部的地址。实现的方法是,在写代码的过程中不直接调用 Windows API,而是主动获取 Windows API 的地址进行调用,比如以下 MyMessageBoxA 函数:

typedef int(WINAPI* pMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);

#pragma code_seg(".shell")

void MyMessageBoxA(pMessageBoxA funcMessageBoxA) {
    char text[] = { '\0' };
    funcMessageBoxA(0, text, text, MB_ICONINFORMATION);
}

#pragma code_seg(".text")

int main() {
    MyMessageBoxA(MessageBoxA);
}

该函数使用的 MessageBoxA 的地址通过参数从外部传入,所以该函数的机器码可以作为 ShellCode 直接运行。

4. 新型加载器的实现分析

通过对 ShellCode 深入了解,可以知道 ShellCode 其实就是按照地址无关标准编写的代码对应的汇编指令的硬编码,而汇编指令与硬编码是相对应的。

所以可以说,运行 ShellCode 就是运行其汇编指令,只要实现了其汇编指令的等效功能,就是实现了 ShellCode 的等效运行。

于是当前的研究转化为其汇编指令实现了什么功能。

通过学习汇编语言,可以知道这些汇编指令简单来说就是不断修改寄存器、栈、内存的值,通过不断的修改构造好调用 Windows API 所需的参数,进而成功调用 Windows API。

函数参数的构造过程可以通过上文的 MyMessageBoxA 来简单解释,该函数通过以下代码调用:

MyMessageBoxA(MessageBoxA)

该行代码实际上就构造好了函数的参数,其汇编指令:

mov rcx,qword ptr [__imp_MessageBoxA]
call MyMessageBoxA

汇编指令将 MessageBoxA 的地址放入了 RCX 寄存器,这就是一个简单的构造过程。复杂的过程比如要对字符串循环解密等,可以统一认为是构造函数参数的过程。

于是当前的研究转化为如何用其他办法构建好 Windows API 的参数来调用。

我想到的办法是实现汇编指令的解释器。解释器是一种逐行对代码进行词法、语法、语义等分析进行运行的程序。

只要我传入汇编指令的文本,解释器逐条指令解析实现对应的功能即可。这里涉及到几个问题。比如解释到 mov rsp, 0x00,此时不应该将真实 RSP 寄存器的值改为 0x00,这样会导致解释器本身错误。解决办法是实现虚拟寄存器和虚拟栈,将虚拟的 vtRSP 改为 0x00。在解释 Windows API 的调用指令时,先将虚拟寄存器的值覆盖真实寄存器,此时 Windows API 的参数为构造完整的状态,之后直接调用 Windows API 即可成功。

下面以 MyMessageBoxA 为例演示解释过程:

该函数的汇编指令:

MOV QWORD PTR [RSP + 8], RCX
SUB RSP, 0X38
MOV BYTE PTR [RSP + 0X20], 0
MOV R9D, 0X40
LEA R8, [RSP + 0X20]
LEA RDX, [RSP + 0X20]
XOR ECX, ECX
CALL QWORD PTR [RSP + 0X40]
ADD RSP, 0X38
RET

模拟解释器:

以下代码忽略了汇编指令的解析过程,直接模拟每条指令对虚拟值修改进而构造好 Windows API 的参数,将虚拟值覆盖真实值后成功调用 Windows API。

注:需要配置 Clang 环境以支持 x64 内联汇编。

Visual Studio Installer ------> 单个组件 ------> LLVM (clang-cl) + Clang ------> 安装

Visual Studio ------> 项目属性 ------> 常规 ------> 平台工具集 (LLVM (clang-cl))

// 虚拟栈
PVOID vtStack = malloc(0x10000);
// 虚拟栈顶
DWORD64 vtRSP = (DWORD64)vtStack + 0x9000;

// mov rcx,qword ptr [__imp_MessageBoxA]
DWORD64 vtRCX = (DWORD64)MessageBoxA;
// call MyMessageBoxA
vtRSP -= 8;

// MOV QWORD PTR [RSP + 8], RCX
*(PDWORD64)(vtRSP + 8) = vtRCX;
// SUB RSP, 0x38
vtRSP -= 0x38;
// MOV BYTE PTR [RSP + 0x20], 0
*(PBYTE)(vtRSP + 0x20) = 0;
// MOV R9D, 0x40
DWORD64 vtR9 = 0x40;
// LEA R8, [RSP + 0x20]
DWORD64 vtR8 = vtRSP + 0x20;
// LEA RDX, [RSP + 0x20]
DWORD64 vtRDX = vtRSP + 0x20;
// XOR ECX, ECX
vtRCX ^= vtRCX;

// 虚拟寄存器 覆盖 真实寄存器
__asm {
    mov rcx, vtRCX
    mov rdx, vtRDX
    mov r8, vtR8
    mov r9, vtR9
    mov rsp, vtRSP
}

// CALL QWORD PTR [RSP + 0x40]
__asm {
    call qword ptr[rsp + 0x40]
}

// ADD RSP, 0x38
vtRSP += 0x38;

// RET
vtRSP += 8;

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-9-8 09:14 , Processed in 0.013409 second(s), 20 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表