Jump to content
Sign in to follow this  
Skrip

_ADS() UDF

Recommended Posts

HOWTO: Enumerate ADS streams in AutoIt

I've been working on this all evening. Here's a function to enumerate all the ADS streams in a file or directory. To see it work, create some files or directories with ads streams, and change the function calls to match. To create some ads streams easily at a command prompt -

echo Main text file. > ads.txt
echo Contents stream 1 > ads.txt:stream1
echo Contents stream 2 > ads.txt:stream2
REM next lines will show the contents of the streams
more < ads.txt:stream1
more < ads.txt:stream2

REM for a directory
md adsdir
echo Contents stream 1 > adsdir:stream1
echo Contents stream 2 > adsdir:stream2
REM show contents
more < adsdir:stream1
more < adsdir:stream2

For more info, search MSDN for FILE_STREAM_INFO structure, NtQueryInformationFile, NtOpenFile.

Opt("MustDeclareVars", 1)

Global Const $FileDirectoryInformation = 1
Global Const $FileFullDirectoryInformation = 2
Global Const $FileBothDirectoryInformation = 3
Global Const $FileBasicInformation = 4
Global Const $FileStandardInformation = 5
Global Const $FileInternalInformation = 6
Global Const $FileEaInformation = 7
Global Const $FileAccessInformation = 8
Global Const $FileNameInformation = 9
Global Const $FileRenameInformation = 10
Global Const $FileLinkInformation = 11
Global Const $FileNamesInformation = 12
Global Const $FileDispositionInformation = 13
Global Const $FilePositionInformation = 14
Global Const $FileFullEaInformation = 15
Global Const $FileModeInformation = 16
Global Const $FileAlignmentInformation = 17
Global Const $FileAllInformation = 18
Global Const $FileAllocationInformation = 19
Global Const $FileEndOfFileInformation = 20
Global Const $FileAlternateNameInformation = 21
Global Const $FileStreamInformation = 22
Global Const $FilePipeInformation = 23
Global Const $FilePipeLocalInformation = 24
Global Const $FilePipeRemoteInformation = 25
Global Const $FileMailslotQueryInformation = 26
Global Const $FileMailslotSetInformation = 27
Global Const $FileCompressionInformation = 28
Global Const $FileCopyOnWriteInformation = 29
Global Const $FileCompletionInformation = 30
Global Const $FileMoveClusterInformation = 31
Global Const $FileQuotaInformation = 32
Global Const $FileReparsePointInformation = 33
Global Const $FileNetworkOpenInformation = 34
Global Const $FileObjectIdInformation = 35
Global Const $FileTrackingInformation = 36
Global Const $FileOleDirectoryInformation = 37
Global Const $FileContentIndexInformation = 38
Global Const $FileInheritContentIndexInformation = 39
Global Const $FileOleInformation = 40
Global Const $FileMaximumInformation = 41

Global Const $READ_CONTROL = 0x20000
Global Const $GENERIC_READ = 0x80000000
Global Const $SYNCHRONIZE = 0x100000
Global Const $OBJ_CASE_INSENSITIVE = 0x00000040
Global Const $OBJ_INHERIT = 0x2
Global Const $FILE_DIRECTORY_FILE = 0x00000002
Global Const $FILE_NON_DIRECTORY_FILE = 0x00000040
Global Const $FILE_RANDOM_ACCESS = 0x00000800
Global Const $FILE_SHARE_READ = 0x1

Global Const $tagFILESTREAMINFO = "ulong NextEntryOffset;ulong StreamNameLength;int64 StreamSize;int64 StreamAllocationSize;wchar StreamName"
Global Const $tagIOSTATUSBLOCK = "dword Status;dword Information"
Global Const $tagOBJECTATTRIBUTES = "ulong Length;hwnd RootDirectory;ptr ObjectName;ulong Attributes;ptr SecurityDescriptor;ptr SecurityQualityOfService"
Global Const $tagUNICODESTRING = "ushort Length;ushort MaximumLength;ptr Buffer"

EnumADS(@ScriptDir & "\ads.txt")
EnumADS(@ScriptDir & "\adsdir", 1)

Func EnumADS($file, $mode = 0) ; 0 = file, 1 = directory
    Local $hNTDLL = DllOpen("ntdll.dll")

    Local $szName = DllStructCreate("wchar[260]")
    Local $sUS = DllStructCreate($tagUNICODESTRING)
    Local $sOA = DllStructCreate($tagOBJECTATTRIBUTES)
    Local $sISB = DllStructCreate($tagIOSTATUSBLOCK)
    Local $buffer = DllStructCreate("byte[16384]")
    Local $ret, $FILE_MODE
    
    If $mode == 0 Then
        $FILE_MODE = $FILE_NON_DIRECTORY_FILE
    Else
        $FILE_MODE = $FILE_DIRECTORY_FILE
    EndIf

    $file = "\??\" & $file
    ConsoleWrite($file & @CRLF)

    DllStructSetData($szName, 1, $file)
    $ret = DllCall($hNTDLL, "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName))
    ConsoleWrite("Length: " & DllStructGetData($sUS, "Length") & @CRLF)
    ConsoleWrite("Max: " & DllStructGetData($sUS, "MaximumLength") & @CRLF)
    ConsoleWrite("Buff ptr: " & DllStructGetData($sUS, "Buffer") & @CRLF)

    DllStructSetData($sOA, "Length", DllStructGetSize($sOA))
    DllStructSetData($sOA, "RootDirectory", Chr(0))
    DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS))
    DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE)
    DllStructSetData($sOA, "SecurityDescriptor", Chr(0))
    DllStructSetData($sOA, "SecurityQualityOfService", Chr(0))

    $ret = DllCall($hNTDLL, "int", "NtOpenFile", "hwnd*", "", "dword", $GENERIC_READ, "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), _
                                "ulong", $FILE_SHARE_READ, "ulong", BitOR($FILE_MODE, $FILE_RANDOM_ACCESS))
    ConsoleWrite("Return: " & Hex($ret[0]) & @CRLF)
    Local $hFile = $ret[1]
    ConsoleWrite("hFile: " & $hFile & @CRLF)

    $ret = DllCall($hNTDLL, "int", "NtQueryInformationFile", "hwnd", $hFile, "ptr", DllStructGetPtr($sISB), "ptr", DllStructGetPtr($buffer), _
                                "int", 16384, "int", $FileStreamInformation)

    ConsoleWrite("Return: " & Hex($ret[0]) & @CRLF)
    
    If NT_SUCCESS($ret[0]) Then
        ConsoleWrite("->Successful query." & @CRLF)
        ; $tagFILESTREAMINFO = "ulong NextEntryOffset;ulong StreamNameLength;int64 StreamSize;int64 StreamAllocationSize;wchar StreamName"
        Local $pFSO = DllStructGetPtr($buffer)
        Local $sFSO = DllStructCreate($tagFILESTREAMINFO, $pFSO)
        Local $next_offset = DllStructGetData($sFSO, "NextEntryOffset")
        Local $namelength = DllStructGetData($sFSO, "StreamNameLength")
        Local $size = DllStructGetData($sFSO, "StreamSize")
        Local $alloc_size = DllStructGetData($sFSO, "StreamAllocationSize")
        ConsoleWrite(">Next offset: " & $next_offset & @CRLF)
        ConsoleWrite(">Name length: " & $namelength & @CRLF) ; in bytes
        ConsoleWrite(">Stream size: " & $size & @CRLF)
        ConsoleWrite(">Stream allocation size: " & $alloc_size & @CRLF)
        Local $streamName = DllStructCreate("wchar[" & $namelength / 2 & "]", DllStructGetPtr($sFSO, "StreamName"))
        ConsoleWrite(">Stream name: " & DllStructGetData($streamName, 1) & @CRLF)
        ConsoleWrite("->========================================" & @CRLF)
        
        While $next_offset > 0
            ; release structs
            $sFSO = 0
            $streamName = 0
            ; next entry
            $pFSO += $next_offset
            $sFSO = DllStructCreate($tagFILESTREAMINFO, $pFSO)
            $next_offset = DllStructGetData($sFSO, "NextEntryOffset")
            $namelength = DllStructGetData($sFSO, "StreamNameLength")
            $size = DllStructGetData($sFSO, "StreamSize")
            $alloc_size = DllStructGetData($sFSO, "StreamAllocationSize")
            ConsoleWrite(">Next offset: " & $next_offset & @CRLF)
            ConsoleWrite(">Name length: " & $namelength & @CRLF) ; in bytes
            ConsoleWrite(">Stream size: " & $size & @CRLF)
            ConsoleWrite(">Stream allocation size: " & $alloc_size & @CRLF)
            $streamName = DllStructCreate("wchar[" & $namelength / 2 & "]", DllStructGetPtr($sFSO, "StreamName"))
            ConsoleWrite(">Stream name: " & DllStructGetData($streamName, 1) & @CRLF)
            ConsoleWrite("->========================================" & @CRLF)
        WEnd
    Else
        ConsoleWrite("->Error querying file." & @error & @CRLF)
    EndIf

    $ret = DllCall($hNTDLL, "int", "NtClose", "hwnd", $hFile)
    ConsoleWrite("Return: " & Hex($ret[0]) & @CRLF)

    DllClose($hNTDLL)
EndFunc

Func NT_SUCCESS($status)
    If 0 <= $status And $status <= 0x7FFFFFFF Then
        Return True
    Else
        Return False
    EndIf
EndFunc
Edited by wraithdu

Share this post


Link to post
Share on other sites

@Firestorm

While poking around on that site, it looks like you can delete just a specific stream. For example, this deletes a stream named s1 from file ads.txt -

$file = "\\?\" & @ScriptDir & "\ads.txt:s1"
$ret = DllCall("kernel32.dll", "int", "DeleteFileW", "wstr", $file)
ConsoleWrite($ret[0] & @CRLF) ; non-zero means success

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...