CS免杀-AllocADsMem内存申请
字数 1330 2025-08-09 18:44:03
CS免杀技术:利用AllocADsMem和ReallocADsMem实现内存申请
1. 概述
本文详细介绍了如何利用Windows API中的AllocADsMem和ReallocADsMem函数实现内存申请操作,用于Cobalt Strike等C2框架的免杀技术。这两个函数位于activeds.dll中,是较少被安全产品监控的内存分配函数。
2. 核心函数分析
2.1 AllocADsMem
函数原型:
LPVOID AllocADsMem(DWORD cb);
- 参数:
cb- 要分配的内存大小(字节) - 返回值:成功返回分配的内存指针,失败返回NULL
2.2 ReallocADsMem
函数原型:
LPVOID ReallocADsMem(LPVOID pOldMem, DWORD cbOld, DWORD cbNew);
- 参数:
pOldMem- 之前分配的内存指针cbOld- 旧内存块大小cbNew- 新内存块大小
- 返回值:成功返回重新分配的内存指针,失败返回NULL
2.3 FreeADsMem
函数原型:
BOOL FreeADsMem(LPVOID pMem);
- 参数:
pMem- 要释放的内存指针 - 返回值:成功返回TRUE,失败返回FALSE
3. 实现原理
这些函数是Active Directory Service Interfaces (ADSI)的一部分,主要用于目录服务操作。由于它们不是常规的内存分配函数(如malloc或VirtualAlloc),因此可以绕过一些基于行为检测的安全产品。
4. 实际应用代码示例
4.1 基本使用
#include <Windows.h>
#include <activeds.h>
int main() {
// 加载activeds.dll
HMODULE hActiveDS = LoadLibraryA("activeds.dll");
// 获取函数地址
typedef LPVOID(WINAPI* pAllocADsMem)(DWORD);
pAllocADsMem AllocADsMem = (pAllocADsMem)GetProcAddress(hActiveDS, "AllocADsMem");
// 分配内存
LPVOID pMem = AllocADsMem(1024);
if (pMem) {
// 使用内存...
// 释放内存
typedef BOOL(WINAPI* pFreeADsMem)(LPVOID);
pFreeADsMem FreeADsMem = (pFreeADsMem)GetProcAddress(hActiveDS, "FreeADsMem");
FreeADsMem(pMem);
}
FreeLibrary(hActiveDS);
return 0;
}
4.2 在Cobalt Strike中的应用
#include <Windows.h>
#include <activeds.h>
typedef LPVOID(WINAPI* pAllocADsMem)(DWORD);
typedef LPVOID(WINAPI* pReallocADsMem)(LPVOID, DWORD, DWORD);
typedef BOOL(WINAPI* pFreeADsMem)(LPVOID);
void* AllocateMemory(size_t size) {
HMODULE hActiveDS = LoadLibraryA("activeds.dll");
pAllocADsMem AllocADsMem = (pAllocADsMem)GetProcAddress(hActiveDS, "AllocADsMem");
void* memory = AllocADsMem((DWORD)size);
FreeLibrary(hActiveDS);
return memory;
}
void* ReallocateMemory(void* oldMem, size_t oldSize, size_t newSize) {
HMODULE hActiveDS = LoadLibraryA("activeds.dll");
pReallocADsMem ReallocADsMem = (pReallocADsMem)GetProcAddress(hActiveDS, "ReallocADsMem");
void* newMem = ReallocADsMem(oldMem, (DWORD)oldSize, (DWORD)newSize);
FreeLibrary(hActiveDS);
return newMem;
}
void FreeMemory(void* memory) {
HMODULE hActiveDS = LoadLibraryA("activeds.dll");
pFreeADsMem FreeADsMem = (pFreeADsMem)GetProcAddress(hActiveDS, "FreeADsMem");
FreeADsMem(memory);
FreeLibrary(hActiveDS);
}
5. 免杀优势分析
- 非标准内存分配函数:不像VirtualAlloc等常见API那样容易被监控
- 合法用途掩盖:这些函数原本用于Active Directory操作,看起来更合法
- 低检测率:大多数EDR/AV不会特别监控这些函数的内存分配行为
- 灵活性:可以与其他技术结合使用,如API间接调用
6. 注意事项
- 内存属性:这些函数分配的内存默认是可读写的,不具备执行权限,需要配合VirtualProtect等函数修改权限
- DLL加载:需要动态加载activeds.dll,避免静态链接引起怀疑
- 错误处理:需要妥善处理内存分配失败的情况
- 兼容性:确保目标系统上有activeds.dll(大多数Windows系统都有)
7. 进阶技巧
- 结合其他API:可以与EnumChildWindows等GUI API结合,创建更隐蔽的内存操作链
- 延迟加载:只在需要时加载activeds.dll,使用后立即释放
- API混淆:通过哈希或加密函数名动态解析API地址
- 内存加密:在非使用时段加密分配的内存区域
8. 检测与防御
虽然这种方法有一定免杀效果,但防御方可以通过以下方式检测:
- 监控所有内存分配行为:不限于常见API
- 分析调用链:检查这些函数是否被用于非常规目的
- 行为分析:结合内存分配后的使用模式(如立即修改权限)进行检测
- DLL加载监控:特别关注activeds.dll的非常规使用
9. 总结
AllocADsMem和ReallocADsMem提供了一种相对隐蔽的内存分配方式,可以用于绕过一些基于API监控的安全检测。然而,没有任何技术是完美的免杀方案,建议在实际应用中结合多种技术,并根据目标环境进行调整。