Sunday, June 22, 2008

PowerShell Deleting NTFS Alternate Data Streams

This post provides various command-line methods of creating, referencing, extracting and deleting NTFS alternate data streams. The PowerShell script was originally intended to delete NTFS attributes other than $data, but I don't think this is possible using DeleteFile from Kernel32.

The PowerShell script is really just a wrapper around a simple call to DeleteFile in VB.Net, using the syntax %file%:%stream%:%Attribute, eg test.txt:stream1:$DATA

Included below the script are methods to create streams using echo and type in files and directory objects, run executable code from an alternate stream, and display detail on the streams using nfi.exe and streams.exe.
 

#-- DeleteNTFSStream.ps1

param(
   [string] $filename,
   [string] $attribute,
   [string] $stream
   )

#
# Description:
#  Delete an NTFS alternate data stream for the specified file
#
# Author: 
#  Wayne Martin, 22/06/2008, http://waynes-world-it.blogspot.com/
#
# Usage
#  powershell . .\DeleteNTFSStream.ps1 -f "d:\temp\test.txt" -a "`$Data" -s "stream1"
#
# References:
#  Accessing alternative data-streams of files on an NTFS volume
#  http://www.codeproject.com/KB/cs/ntfsstreams.aspx

$provider = new-object Microsoft.VisualBasic.VBCodeProvider
$params = new-object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$params.ReferencedAssemblies.AddRange($refs)

$VBCode = @'
Imports System

Class DeleteNTFSStream

    '''Return Type: BOOL->int
    '''lpFileName: LPCWSTR->WCHAR*
      _
    Public Shared Function DeleteFileW( ByVal lpFileName As String) As  Boolean
    End Function

    Sub main(ByVal lpFileName As String, ByVal lpAttributeName As String, Optional ByVal lpStreamName As String = "")

        Dim lpFile As String = ""
        lpFile = lpFileName + ":" + lpStreamName + ":" + lpAttributeName
    
        If (lpFile <> "") Then
            console.writeline("Deleting " + lpFile)
            DeleteFileW(lpFile)
        End If
    End Sub
End class
'@

$cr = $provider.CompileAssemblyFromSource($params, $VBCode)
if ($cr.Errors.Count) {
    $codeLines = $VBCode.Split("`n");
    foreach ($ce in $cr.Errors)
    {
        write-host "Error: $($codeLines[$($ce.Line - 1)])"
        write-host $ce
        #$ce out-default
    }
    Throw "INVALID DATA: Errors encountered while compiling code"
 }
$mAssembly = $cr.CompiledAssembly
$instance = $mAssembly.CreateInstance("DeleteNTFSStream")

$result = $instance.main($filename, $attribute, $stream)
write-host $result

#--


Add a string to a stream $Data attribute:
echo this content will be stored in the file sub stream > test.txt:stream1

Add the contents of a file to an alternate data strem
type file.txt > test.txt:stream1

Create a new file in an alternate stream as part of a directory:
md test & echo alternate stream > test:stream1

Display the stream:
more < test.txt:stream1

Display the NTFS attributes for the file
nfi c:\temp\test.txt
NTFS File Sector Information Utility.
Copyright (C) Microsoft Corporation 1999. All rights reserved.

\Temp\test.txt
$STANDARD_INFORMATION (resident)
$FILE_NAME (resident)
$DATA (resident)
$DATA stream1 (resident)

Add an executable as an alternate stream (the stream is attached to a directory in this case)
type c:\windows\system32\notepad.exe > test:test.exe

Run the executable in the alternate stream
cmd /c start .\test:test.exe

View the directory and its alternate stream containing notepad.exe
nfi c:\temp\test
\Temp\Test
$STANDARD_INFORMATION (resident)
$FILE_NAME (resident)
$DATA test.exe (nonresident)
logical sectors 659144-659151 (0xa0ec8-0xa0ecf)
logical sectors 660312-660319 (0xa1358-0xa135f)
logical sectors 646776-646791 (0x9de78-0x9de87)
logical sectors 701064-701095 (0xab288-0xab2a7)
logical sectors 5101080-5101143 (0x4dd618-0x4dd657)
logical sectors 27656944-27656951 (0x1a602f0-0x1a602f7)
$INDEX_ROOT $I30 (resident)
$INDEX_ALLOCATION $I30 (nonresident)
logical sectors 11436456-11436463 (0xae81a8-0xae81af)
$BITMAP $I30 (resident)

Retrieve the binary file from the stream and store in the default stream of a new file (using win32 port of Unix Cat)
cat test:test.exe > note.exe

Remove a stream (does not maintain timestamps)
type test.txt>test1.txt

Delete an alternate data stream
streams -d test.txt

References

nfi.exe, part of OEM Support Tools Phase 3 Service Release 2 Availability
http://support.microsoft.com/kb/q253066/


Streams v1.56
http://technet.microsoft.com/en-us/sysinternals/bb897440.aspx

Accessing alternative data-streams of files on an NTFS volume
http://www.codeproject.com/KB/cs/ntfsstreams.aspx

Find and delete NTFS Alternate Data Streams (ADS)
http://www.codeproject.com/KB/files/ntfsguiextension.aspx

How To Use NTFS Alternate Data Streams
http://support.microsoft.com/kb/105763

Practical Guide to Alternative Data Streams in NTFS
http://www.irongeek.com/i.php?page=security/altds

Named Attributes
http://blogs.sun.com/rajendrag/entry/named_attributes

Viewing NTFS information with nfi and diskedit
http://waynes-world-it.blogspot.com/2008/03/viewing-ntfs-information-with-nfi-and.html


Wayne's World of IT (WWoIT), Copyright 2008 Wayne Martin.

No comments:

Post a Comment