NTFS Alternate Data Streams简介

一、前言

本文在Win10企业版2016 LTSB 1607(OS Build 14393.4704)上测试。

NTFS ADS (Alternate Data Streams)当年是为了兼容Macintosh Hierarchical File System (HFS)而出场的,NT 3.1开始引入ADS。

文件、目录、根目录都可以有ADS。ADS与”main stream”共用DACLs,无权访问”main stream”时,也无权访问附在其上的ADS。目录可以有ADS,但目录没有”main stream”。

“A:B”存在歧义,OS为规避歧义,始终将之解释成A盘的B文件。若存在名为”A:B”的ADS,为访问它,比须带上路径,比如”<path>\A:B”。

WFP (Windows File Protection)会保护部分系统文件,但在过去,WFP不会阻止拥有相应权限的用户向这些受保护的系统文件追加ADS。sfc.exe (SFC/System File Checker)会检查受保护的系统文件,但不会检查附在其上的ADS。不知现在情况是否有变?

Windows Defender SmartScreen会检查ADS。

二、NTFS ADS 操作手册

1) 向”main stream”写入数据

有个奇技淫巧,在cmd中echo,不出现结尾的\r\n,与本文无关,只是顺带演示

echo | set /p=”unnamed data stream” > some.ext

2) 新增ADS并写入数据

2.1) 输出转向符”>”

输出转向符”>”支持ADS

echo | set /p="secret data stream 0" > some.ext:any_0
echo | set /p="secret data stream 1" > some.ext:any_1
echo | set /p="secret data stream 2" > some.ext:any_2

2.2) powershell

powershell -Command "Set-Content -Path '\\?\X:\path\some.ext' -Stream 'any_3' -Value 'secret data stream 3' -NoNewline"

2.3) 其他方案

下列命令或工具均是OS自带的,此处不罗列第三方工具

type some.exe > any.ext:some.exe
findstr /V /L Nonexist_Magic some.exe > any.ext:some.exe
expand some.exe any.ext:some.exe
esentutl /y some.exe /d any.ext:some.exe
powershell -Command "Get-Content -Encoding Byte -ReadCount 0 -Path some.exe | Set-Content -Encoding Byte -Path any.ext -Stream some.exe"
powershell -Command "&{(Get-Content -Encoding Byte -ReadCount 0 -Path some.exe | Set-Content -Encoding Byte -Path any.ext -Stream some.exe)}"
print /D:any.ext:some.exe some.exe

makecab some.exe tmp.cab
extrac32 /y tmp.cab any.ext:some.exe
del tmp.cab

不推荐print,无法完全保持PE原样,会多一个字节,但不影响执行。

type、findstr实际依赖输出转向符”>”,其余命令自身支持ADS。

3) 显示ADS

3.1) dir /R

从Vista开始dir有个/R开关可以显示ADS

$ dir /R some.ext

03/17/2022 11:51   19 some.ext
            20 some.ext:any_0:$DATA
            20 some.ext:any_1:$DATA
            20 some.ext:any_2:$DATA
     1 File(s)     19 bytes

注意最后一行,只显示”main stream”大小,19字节,未包含ADS大小。

3.2) streams from sysinternals

参[8]

$ streams some.ext

$ streams -s .

some.ext:
 :any_0:$DATA 20
 :any_1:$DATA 20
 :any_2:$DATA 20

这是sysinternals的工具之一,首行是”main stream”,后面各行是ADS,最后一列是
ADS大小,20字节。

3.3) Get-Item

powershell -Command "Get-Item -Path some.ext -Stream * | Where-Object Stream -ne ':$DATA' | Format-Table Filename,Stream,Length"
powershell -Command "Get-ChildItem | Get-Item -Stream * | Where-Object Stream -ne ':$DATA' | Format-Table Filename,Stream,Length"
powershell -Command "gci -Recurse | % { gi $_.FullName -Stream * } | where Stream -ne ':$DATA' | Format-Table Filename,Stream,Length"

gci、gi、where分别是Get-ChildItem、Get-Item、Where-Object的别名

4) 查看ADS内容

4.1) 输入转向符”<”

more不能直接访问ADS,但输入转向符”<“支持ADS

$ more < some.ext:any_2
secret data stream 2

type不支持ADS

$ type some.ext:any_2
The filename, directory name, or volume label syntax is incorrect.

很多工具不支持ADS,比如UltraEdit就不支持。

4.2) Get-Content

$ powershell -Command "Get-Content -Path some.ext -Stream any_2"
secret data stream 2

5) 复制ADS内容

先创建any.ext,其内空是一段文本;再向其追加ADS,其内容源自PE。

echo | set /p="unnamed data stream" > any.ext
type any.exe > any.ext:any.exe
dir /R any.ext

03/17/2022 17:24     19 any.ext
            342,392 any.ext:any.exe:$DATA
      1 File(s)    19 bytes

假设在any.ext的ADS中隐藏了any.exe,现在想将any.exe还原出来。

下面这样干是不行的,因为ADS内容是二进制的、非文本的,more会破坏原始数据。

more < any.ext:any.exe > any_other.exe

看了一下more的帮助,没有保持raw格式的办法,至少Win10上如此。有人用源自Windows Resource Kit的cat,这不是自带工具,需要额外安装,此处不考虑。

5.1) Get-Content + Set-Content

Copy-Item不支持ADS,可以结合Get-Content、Set-Content复制ADS到普通文件

powershell -Command "Get-Content -Encoding Byte -ReadCount 0 -Path any.ext -Stream any.exe | Set-Content -Encoding Byte -Path any_other.exe"
dir /R any_other.exe

我的powershell不够新,不支持”-AsByteStream”,只支持”-Encoding Byte”,二者
效果等价。”-ReadCount 0″表示一次性读取整个文件送往管道,缺省值是1。

5.2) Get-Content + WriteAllBytes

powershell -Command "[IO.File]::WriteAllBytes('any_other.exe', (Get-Content -Encoding Byte -ReadCount 0 -Path any.ext -Stream any.exe))"
dir /R any_other.exe

5.3) 其他方案

下列命令或工具均是OS自带的,此处不罗列第三方工具

expand any.ext:some.exe some_other.exe
esentutl /y any.ext:some.exe /d some_other.exe

6) 删除ADS

先新增名为any_3的ADS

$ echo | set /p="secret data stream 3" > some.ext:any_3

del可以删除”main stream”,也就是some.ext,此时会一并删除附在其上的所有ADS。但是,del没法在保持”main stream”不变的情况下删除指定ADS,del不支持ADS语法。

6.1) streams from sysinternals

sysinternals的streams可以在保持”main stream”不变的情况下删除所有ADS,但做不到删除单个指定ADS。

streams的”-s -d”可以一起用,千万不要对着系统目录用。

6.2) ren + type + del

有一种方案,只依赖cmd内部命令,不依赖其他PE,变相实现保持”main stream”不变的情况下删除所有ADS。为接近实际用途,用二进制目标文件进行演示。

假设有PE文件any.exe,现对其追加3个ADS

echo | set /p="secret data stream 0" > any.exe:any_0
echo | set /p="secret data stream 1" > any.exe:any_1
echo | set /p="secret data stream 2" > any.exe:any_2

下列操作可以变相实现保持”main stream”不变的情况下删除所有ADS

ren any.exe waitdel
type waitdel > any.exe
del waitdel

any.exe只剩下”main stream”。该方案利用了type命令只访问”main stream”的特点,而ren、copy、move等命令会带着ADS。

6.3) Remove-Item

Remove-Item可以只删除指定ADS而保留其他ADS及”main stream”

powershell -Command "Remove-Item -Path some.ext -Stream any_3"

6.4) NTFS->FAT32->NTFS

NTFS支持ADS,FAT32不支持,从NTFS复制文件、目录到FAT32,将自动丢弃ADS,只复制”main stream”过去。然后再从FAT32复制回NTFS,变相实现保持”main stream”不变的情况下删除所有ADS。现在硬盘不太可能出现FAT32了,但很多U盘格成FAT32。

6.5) Win32 API DeleteFile

标准Win32 API支持ADS语法,可以编程删除指定ADS

DeleteFile( "X:\\path\\some.ext:any_3" )

7) notepad受限支持ADS

$ notepad some.ext:any_3

上述命令在ADS名未尾自动增加”.txt”扩展名,实际创建”some.ext:any_3.txt”,无
法改变此行为。

下列命令实际去找”some.ext:any_2.txt”,但找不到,问你要不要新建,换句话说,notepad无法访问”some.ext:any_2″。

$ notepad some.ext:any_2

很奇怪,对于some.exe,notepad可以创建、访问附在其上的ADS。

$ notepad "some.exe:Zone.Identifier"

[ZoneTransfer]
ZoneId=3

若some.exe无此ADS,上述命令可以创建ADS,若已有此ADS,上述命令可以编辑ADS。

8) 执行ADS中的PE

echo | set /p="unnamed data stream" > any.ext
type calc_xp.exe > any.ext:some.exe

特意使用源自XP的calc.exe,这个版本不存在calc.exe.mui的困扰,便于演示。

8.2) wmic process call create

wmic process call create X:\path\any.ext:some.exe

Executing (Win32_Process)->Create()
Method execution successful.
Out Parameters:
instance of __PARAMETERS
{
  ProcessId = 3980;
  ReturnValue = 0;
};

上述输出表示成功执行位于ADS中的PE,PID为3980,计算器弹出。

用wmic执行PE时,应该用绝对路径,不要用相对路径。

8.6) psexec from sysinternals

该法依赖非自带软件,不推荐

psexec -d any.ext:some.exe

计算器弹出。psexec支持相对路径。

8.7) rundll32

del any.ext
echo | set /p="unnamed data stream" > any.ext
type netplwiz_xp.dll > any.ext:some.dll

特意使用源自XP的netplwiz.dll,这个版本不存在netplwiz.dll.mui的困扰,便于演示。

在管理员级cmd中执行如下命令

rundll32.exe any.ext:some.dll,UsersRunDll

8.8) 利用ADS执行代码的其他讨论

参[9]

此处罗列了大量利用ADS执行代码的奇技淫巧。ADS内容可以是cscript、wscript所支持的脚本代码,二者支持ADS语法。如果考虑powershell介入,可能性更广。ADS内容是dll时,还有mavinject.exe可用。若有恶意需求,自行实践之。

9) 附加在目录上的ADS

向目录追加ADS

mkdir some.dir
echo | set /p="secret data stream 0" > some.dir:any_0
echo | set /p="secret data stream 1" > some.dir:any_1
echo | set /p="secret data stream 2" > some.dir:any_2

删除附加在目录上的ADS

streams -d some.dir

下面是另一组演示命令

cd /d X:\path\some.dir
echo | set /p="secret data stream 0" > :any_0
dir /R X:\path\some.dir
more < "X:\path\some.dir:any_0"

9.1) 各盘根目录

向X盘根目录追加ADS

echo | set /p="secret data stream 0" > X:\:any_0
echo | set /p="secret data stream 1" > X:\:any_1
echo | set /p="secret data stream 2" > X:\:any_2
dir /R X:\

上述dir看不到附加在根目录上的ADS。这些ADS附加在X盘根目录下所有一级子目录的”..”项上。

dir /R X:\subdir

03/21/2022 13:59   <DIR> .
03/21/2022 13:59   <DIR> ..
             20 ..:any_0:$DATA
             20 ..:any_1:$DATA
             20 ..:any_2:$DATA
    0 File(s)       0 bytes

访问附加在根目录上的ADS

$ more < X:\:any_2
secret data stream 2

删除附加在根目录上的ADS

$ streams.exe -d X:\

三、ADS的合法用途

1) Zone.Identifier

用IE、Edge、Chrome等现代浏览器下载文件会自动添加名为”Zone.Identifier”的ADS,可以模拟这种场景。

copy calc_xp.exe some.exe
(echo|set /p="[ZoneTransfer]"&echo=&echo|set /p="ZoneId=3") > some.exe:Zone.Identifier
more < some.exe:Zone.Identifier

ADS内容如下

[ZoneTransfer]
ZoneId=3

之后在some.exe右键General面板里出现Unlock字样,Unlock实际就是删除”Zone.Identifier”。

ZoneId的可取值有

0 My Computer
1 Local Intranet Zone
2 Trusted Sites Zone
3 Internet Zone
4 Restricted Sites Zone

Office也认”Zone.Identifier”,打开docx、xlsx、pptx时会有不同。

有时”Zone.Identifier”内容更丰富。

2) favicon

据说IE生成的some.url可能包含名为”favicon”的ADS,用于存放favicon.ico,下面模拟一下此操作。

(echo|set /p="[InternetShortcut]"&echo=&echo|set /p="URL=https://stackoverflow.com/") > T:\path\some.url
notepad T:\path\some.url

some.url内容如下

[InternetShortcut]
URL=https://stackoverflow.com/

type favicon.ico > "T:\path\some.url:favicon"
dir /R "T:\path\some.url"

2022/04/13  10:39    50 some.url
            1,406 some.url:favicon:$DATA
     1 File(s)     50 bytes

3) Win32App_1

未研究其用途,备忘

四、 第三方工具

参[5],streamtools包含这些功能

cs Copy Stream

cs src:srcalt dst:dstalt

ds Delete Stream

ds some:alt

sf Strip File (Delete All Alternate Streams)

sf some

rs Rename Stream

rs some oldalt newalt

ls List Streams

ls some

32位工具,Win10上可用

2) GNU utilities for Win32

参[6],这里有一些用Win32 API编写的GNU工具,好像全部支持ADS,我测了cat、md5sum。

3) AlternateStreamView

参[13],GUI工具,可以对ADS进行View/Copy/Delete操作,操作方便,适合小白。

五、后记

本文主要科普NTFS ADS基本操作,未就ADS恶意应用展开科普,事实上许多恶意软件广泛使用ADS,与此同时,许多杀毒软件会检查ADS。

参考资源

[5] NTFS Alternate Streams: What, When, and How To
http://www.flexhex.com/docs/articles/alternate-streams.phtml
http://www.flexhex.com/docs/articles/download/streamtools.zip
http://www.flexhex.com/docs/articles/download/streams.zip
(有源码)

[6] GNU utilities for Win32
http://unxutils.sourceforge.net/
http://unxutils.sourceforge.net/UnxUpdates.zip

Swiss Unix-in-a-box on Windows
https://github.com/minoca/swiss
(类似busybox)

BusyBox for Windows
https://frippery.org/busybox/
https://frippery.org/files/busybox/busybox.exe
https://frippery.org/files/busybox/busybox64.exe
https://github.com/rmyorston/busybox-w32

[8] Streams
https://docs.microsoft.com/en-us/sysinternals/downloads/streams

[9] Execute from Alternate Streams
https://gist.github.com/api0cradle/cdd2d0d0ec9abb686f0e89306e277b8f

[13]
AlternateStreamView View/Copy/Delete NTFS Alternate Data Streams
https://www.nirsoft.net/utils/alternate_data_streams.html
https://www.nirsoft.net/utils/alternatestreamview.zip
https://www.nirsoft.net/utils/alternatestreamview-x64.zip

版权声明
本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。

Spread the word. Share this post!

Meet The Author

C/ASM程序员