【Windows攻防】通过代码研究空字节和无文件方式注册表隐藏技术

news/2025/1/16 21:27:49/文章来源:https://www.cnblogs.com/o-O-oO/p/18674731

这篇文章收录于《取证实录》第四季中。

注册表隐藏技术通常用于恶意软件、后门程序或攻击者企图在系统中保持隐蔽,绕过安全检查和防御系统。

常见的隐藏技术有:使用非法字符隐藏注册表项(如PlugX、TDL4/Alureon(Rootkit))、利用默认键值(空字符串)隐藏(如Adwind RAT)、使用深度嵌套的注册表项(如Zlob (DNSChanger)、Rovnix (Rootkit))、重命名标准注册表项(如TrickBot、Dridex)、注册表反射技术(如Zeus(Zbot))、通过注册表权限进行隐藏(如Carberp)、使用模糊键名或随机化键值(如Qakbot、Ursnif)、滥用镜像注册表键(如Rovnix)、注册表软链接(如Necurs(Rootkit)、Max++(Rootkit))、滥用组策略(GPO)注册表项等。

这里,我们通过研究源代码来了解其中的两项技术,通过代码探究它背后的细节,达到知已知彼。

一、 创建Unicode空字节

空字节,就是“0x0000”,就是“\0\0”。对于Windows系统,”” (0x0000)会被识别为字符串的结束符,所以在使用Regedit对该字符串读取的过程中,遇到开头的””,会被解析成结束符,提前截断,导致读取错误。

以SharpHide开源工具为例,“一个很好的后门持久性技巧,用来混淆DFIR调查。使用NtSetValueKey本机API创建隐藏(以空结尾)注册表项。这是通过在UNICODE_STRING键值名称前面添加一个空字节来实现的”。
程序运行后,显示有三个功能:在Run下创建一个键值:“keyvalue=bla.exe”或带参数的“keyvalue=bla.exe argument=arg1 arg2”,以及delete该键。

当程序以sharphide action=create keyvalue="c:\windows\temp\bla.exe"运行时创建成功了键名为“Software\”+键值为“c:\windows\temp\bla.exe”的注册表项。

用regedit却看不到它的内容并报错,阻止查看;分别对应着HKCU和HKLM的一般用户和管理员权限,均在\Software\Mircosoft\Windows\CurrentVersion\Run。

1.1 源码部分:

UIntPtr regKeyHandle = UIntPtr.Zero;string runKeyPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";string runKeyPathTrick = "\0\0SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";uint Status = 0xc0000000;uint STATUS_SUCCESS = 0x00000000;if (IsSystem || IsElevated){Console.WriteLine("\n[+] SharpHide running as elevated user:\r\n Using HKLM\\{0}", runKeyPath);Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, runKeyPath, 0, KEY_SET_VALUE, out regKeyHandle);}else{Console.WriteLine("\n[+] SharpHide running as normal user:\r\n    Using HKCU\\{0}", runKeyPath);Status = RegOpenKeyEx(HKEY_CURRENT_USER, runKeyPath, 0, KEY_SET_VALUE, out regKeyHandle);}UNICODE_STRING ValueName = new UNICODE_STRING(runKeyPathTrick){Length = 2 * 11,MaximumLength = 0};IntPtr ValueNamePtr = StructureToPtr(ValueName);UNICODE_STRING ValueData;if (arguments.ContainsKey("arguments")){ValueData = new UNICODE_STRING("\"" + arguments["keyvalue"] + "\" " + arguments["arguments"]);}else{ValueData = new UNICODE_STRING("\"" + arguments["keyvalue"] + "\"");}Status =NtSetValueKey(regKeyHandle, ValueNamePtr, 0, RegistryKeyType.REG_SZ, ValueData.buffer, ValueData.MaximumLength);

注意一:runKeyPathTrick = “\0\0SOFTWARE\”,这里有个\0\0,经过unicode后就成为了“0x0000”,这在windows里是个截断字符,后面的内容就丢弃,成为了隐藏部分,不显示。但它的值“c:\windows\temp\bla.exe”还是存在的,写了一个显示窗体的bla.exe放在temp目录下,重启后,这个bla运行了,说明这个程序确实在注册表中的启动项了。

注意二:NtSetValueKey是个WIndows Native API,对注册表进行创建、修改和删除等操作;这些操作,单纯的使用 Regedit 查询是查询不到的。

1.2 Native API

1、以Nt开头的是Native API,而不是Windows API,两者有差别。

  • 如果使用 Native API 则导入 ntdll.dll;

  • 如果使用 Win32 API 则导入 advapi32.dll;

2、实现的根本原因:

在Win32 API中,以 NULL结尾的字符串被解释为 ANSI(8位)或宽字符(16位)字符串。在 Native API中,以 NULL结尾的字符串被解释为 Unicode(16位)字符串。尽管平时这个区别并不重要,但是却带来了一个有趣的情况,即当使用 Native API来构造特别的名称时,不能使用Win32 API来对其进行查询。这是因为作为计数的Unicode字符串的名称可以包含NULL 字符(0),例如“key”,这个Unicode字符串长度为4,但是在使用 Win32 API来进行查询,这是因为在Win32 API中,“key”字符串的长度为3,不满足查询条件。

Regedit看不到的原因是因为Regedit使用的是Win32 API;用户模式调用本机系统服务是通过ntdll.dll来实现的。表面上,Win32 函数为编程人员提供了大量的API接口来实现功能,但这些Win32 函数只不过是一个API接口的容器而已,它将Native API包装起来,通过系统服务来实现真正的功能,也就是ntdll.dll是系统调用接口在用户模式下一个外壳。

1.3 工具验证

既然用regedit看不了,
1、那我们用autoruns呢?截图看下:

结果是:发现不了。

2、用wke导出hive文件,截图看下:

用regedit explorer查看,

结果是:发现了空字节。

3、在注册表中直接查询;如果知道名字,用RegScanner查看,

工具读取的是hive文件,所以可以读取到,看下图:

二、无文件的注册表存储二进制

上面的隐藏技术是针对ValueName做的处理,下面介绍的Fileless Malware技术是针对ValueData的内容进行处理。

无文件的注册表存储二进制数据是一种更加隐蔽和持久的恶意软件存储方式,通常不在文件系统中存储任何可疑的文件,而是将恶意的二进制数据或代码隐藏在Windows注册表中。这种技术旨在绕过传统的文件检测机制,因为它避免了通过磁盘上的文件进行存储和加载。这类技术可以显著提高恶意软件的隐蔽性和持久性,以下是其工作原理、常见的实现方式及防御策略。

该技术在查看键值时,也会像第一种一样提示错误,但是除了指定的可见字符外,会将其他内容进行隐藏;与第一种技术一致,该内容无法导出。

char decoy[] = "(value not set)"; ....void writeHiddenBuf(char *buf, DWORD buflen, const char *decoy, char *keyName, const char* valueName){   HKEY hkResult = NULL;   BYTE *buf2 = (BYTE*)malloc(buflen + strlen(decoy) + 1);   strcpy((char*)buf2, decoy);   buf2[strlen(decoy)] = 0;   memcpy(buf2 + strlen(decoy) + 1, buf, buflen);   if (!RegOpenKeyExA(HKEY_CURRENT_USER, keyName, 0, KEY_SET_VALUE, &hkResult))   {       printf("Key opened!n");       LSTATUS lStatus = RegSetValueExA(hkResult, valueName, 0, REG_SZ, (const BYTE *)buf2, buflen + strlen(decoy) + 1);printf("lStatus == %dn", lStatus);       RegCloseKey(hkResult);    }   free(buf2);}

这段代码的主要功能是在Windows注册表中存储数据,并使用一种简单的混淆方法来隐藏实际数据。分析如下:

1、定义 char decoy[] = "(value not set)";

该字符数组定义了一个伪装值(decoy),即在实际数据前插入的字符串,用于混淆存储在注册表中的数据。

2、writeHiddenBuf 函数参数:

buf: 实际数据的指针,用户希望隐藏存储的数据。

buflen: buf 数据的长度。

decoy: 一个伪装值,数据存储前附加的字符串。

keyName: 注册表键的名称,用于定位存储数据的位置。

valueName: 注册表值的名称,用于将数据与键关联。

3、BYTE buf2 = (BYTE)malloc(buflen + strlen(decoy) + 1);

分配内存来存储伪装值和实际数据。总大小为伪装值的长度、实际数据长度以及一个额外的字节(+1)来存储字符串的终止符。

4、strcpy((char*)buf2, decoy);

将伪装值复制到新分配的 buf2 内存中。

5、buf2[strlen(decoy)] = 0;

在伪装字符串的末尾添加一个空字符,以确保 buf2 在伪装值部分是一个有效的字符串。

6、memcpy(buf2 + strlen(decoy) + 1, buf, buflen);

将实际数据存储在伪装值后面。此步骤将实际数据放置在 buf2 中,但在存储前用伪装值隐藏。

7、打开注册表键:

RegOpenKeyExA(HKEY_CURRENT_USER, keyName, 0, KEY_SET_VALUE, &hkResult) 打开指定的注册表键 keyName。如果成功,注册表键将会打开。

8、写入隐藏数据到注册表:

使用 RegSetValueExA 函数将混淆后的数据写入注册表。这个函数将 buf2 的数据作为值写入指定的 valueName 位置。

9、关闭键和释放内存:

在数据写入后,关闭注册表键,并释放之前分配的 buf2 内存。

总结:

该函数的作用是将用户的数据(buf)与一个伪装字符串(decoy)一起存储到Windows注册表的指定键值位置。这样,实际的数据被隐藏在伪装字符串之后,可以用于混淆分析者或恶意检测工具。
这种技术常用于隐藏恶意软件数据。

  • 将decoy设置成 (value not set);

  • 然后将我们利用Fileless Malware 处理过的buffer放在(value not set)后面;

  • 可知,Regedit会自动截断,达到隐藏的效果;

只要RegSetValueExA传递的decoy字符串的长度+隐藏缓冲区的长度,它将把整个缓冲区写入注册表,达到隐藏效果。

三、检测和防御注册表隐藏技术的工具和方法

注册表隐藏技术发起于21世纪,至今仍在推陈出新,面对这种情况,安全研究人员也在不断地研究发展检测和防御技术和工具方法进行对抗。

3.1 检测与防御策略

1、注册表监控

使用实时注册表监控工具(如 Sysmon 和 Windows Auditing),监控对注册表的写入操作,特别是常见的持久化路径(如 Run 键)。

定期审计系统关键注册表项,查找异常的二进制数据或可疑的Base64编码字符串。
2、内存监控和分析

使用内存分析工具(如 Volatility 或 Rekall)定期检查系统内存中的可疑行为,特别是检测无文件恶意软件的加载和执行。

配合 Endpoint Detection and Response (EDR) 工具,监控内存中的代码注入和执行情况。
3、阻止脚本语言滥用

限制PowerShell、WMI和JavaScript的执行权限,启用 PowerShell Constrained Language Mode 或 AppLocker 来阻止未经授权的脚本运行。

配置PowerShell脚本的日志记录(启用PowerShell的全面审计功能)以监控和分析脚本执行行为。
4、加密检测

检查注册表中含有大量Base64编码字符串或可疑二进制数据的项。这些项可能是恶意代码存储的证据。

使用机器学习或基于行为的检测工具来识别通过注册表加载的恶意二进制数据。
5、行为监控

通过行为分析工具监控进程中的异常行为,如从注册表读取大量二进制数据后立即执行、内存中加载未签名代码或脚本执行等行为。

3.2 部分检测工具

Sysinternals Autoruns:该工具可以检测启动项,包括注册表中的隐藏启动项。

RegRipper:这是一个强大的注册表取证工具,可以分析注册表中的可疑行为。

Process Monitor (Procmon):可以监控实时注册表访问,帮助发现隐藏的注册表操作。

Powershell 脚本:可以通过脚本遍历注册表中的所有项,确保未遗漏任何隐藏项。

原创 MicroPest MicroPest 2025年01月12日 15:00 安徽

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/870305.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DVWA靶场学习

暴力破解Brute Force low 输入密码就正常抓包放字典破解得了uploading-image-528180.png medium 同样的操作发现响应速度变慢了,但是还是能暴力破解,不多说了。 uploading-image-408161.png 部分源码解读 $user = $_GET[username]; $user = ((isset($GLOBALS["___mysqli…

推荐几个不错的 Linux 服务器管理工具

前言 选择一款好的 Linux 服务器管理工具能够极大地提高运维效率,保障业务连续性。今天大姚给大家分享3款不错的 Linux 服务器管理工具,希望可以帮助到有需要的同学。 1Panel 1Panel是新一代的 Linux 服务器运维管理面板,旨在通过现代化的 Web 界面帮助用户轻松管理 Linux 服…

学习进度笔记⑩

Tensorflow线性回归 源代码:import tensorflow as tfimport numpy as npimport matplotlib.pyplot as pltimport osos.environ["CUDA_VISIBLE_DEVICES"]="0"#设置训练参数,learning_rate=0.01,training_epochs=1000,display_step=50learning_rate=0.01…

学习进度笔记⑨

tensorflow基本操作(类似numpy) 源代码import tensorflow as tf import os os.environ["CUDA_VISIBLE_DEVICES"]="0" #构造计算图,创建两个常量节点a,b,值分别为2,3 a=tf.constant(2) b=tf.constant(3) #创建一个Session会话对象,调用run方法,运行…

利用AI大模型实现个性化视频配音

最近,作者决定拍摄短视频分享AI技术的应用,并遇到了配音问题。由于家中环境嘈杂且设备不够专业,作者尝试了机器配音,但效果不佳。作者转而想到AI大模型支持语音识别,于是开始寻找语音合成模型。最终在阿里云百炼平台上找到了通义千问-语音合成CosyVoice大模型,多个音色都…

【取证工具】Magnet AXIOM中文绿色版(更新8.4)

Magnet AXIOM取证工具介绍 Magnet AXIOM 是一款功能强大的数字取证工具,专为法律执行人员、调查员和安全专家设计,用于从各种数字设备中提取、分析和报告证据。AXIOM 提供了全面的取证支持,能够从电脑、移动设备、云端服务以及物联网设备中收集并分析数据。多平台支持 Magne…

介绍1个简单好用的英文文本翻转网站,关键还免费不用登录

输入英文,会 生成对应的翻转、反向、镜像、𝕆𝕦𝕥𝕝𝕚𝕟𝕖 𝔽𝕠𝕟𝕥、𝓒𝓾𝓻𝓼𝓲𝓿𝓮 𝓛𝓮𝓽𝓽𝓮𝓻𝓼的文本可以用于生成密码,聊天时发消息,猜字符的场景,欢迎使用和访问,简单免费,无需登录 比如你想她啦,不好意思说…

[Babel] Intro Babel - 01 Introduction

Babel介绍 Babel 是一个编译器,主要用于将最新的 JavaScript 代码转化为向后兼容的代码,以便在老版本的浏览器或环境中运行。 例如,你可能在开发时使用了 ES6、ES7 或者更高级的 JavaScript 特性,但是有些浏览器可能并不支持这些新特性,这时就可以用 Babel 来将代码转化为…

Babel Intro Babel - 01 Introduction

Babel介绍 Babel 是一个编译器,主要用于将最新的 JavaScript 代码转化为向后兼容的代码,以便在老版本的浏览器或环境中运行。 例如,你可能在开发时使用了 ES6、ES7 或者更高级的 JavaScript 特性,但是有些浏览器可能并不支持这些新特性,这时就可以用 Babel 来将代码转化为…

unordered_map-STL容器

时间复杂度和空间复杂度

2 应用层

2 应用层 2.1 网络应用原理 网络应用:能够运行在不同的端系统和通过网络彼此通信的程序。注:在端系统上运行,而不是在网络核心上运行。网络应用是计算机网络存在的理由。 2.1.1 应用体系结构(application architecture) 客户-服务器体系结构(client-server architecture)…

【内网穿透】概念、原理与实现方法

一、内网穿透简介 内网穿透是一种网络技术,它允许外部网络(如互联网)上的设备访问位于内部网络(例如公司或家庭局域网LAN)中没有直接公网IP地址的设备。这对于远程办公、云服务接入以及物联网设备管理等场景至关重要。 二、工作原理 内网穿透主要依赖于NAT(网络地址转换)…