Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1448

[VB6] List and view Alternate Data Streams using GetFileInformationByHandleEx

$
0
0

So I was playing around with this last night and thought it would make a good demo, since while it seems like a single API would be straightforward it turns out this is fairly complex.

Alternate Data Streams are a hidden part of regular files that you can't normally see. They can be any length, but only the first one is reported in Windows size counts, so a 1KB file could actually be hiding 1GB in an alternate stream. The most common use of alternate streams is web browsers marking files downloaded from the internet, which is how Windows knows to ask you to confirm if you really want to run something you downloaded-- this is shown in the picture above, and getting/setting that was the subject of [VB6] Code Snippet: Get/set/del file zone identifier (Run file from internet? source). There's already code samples about these streams, notably Karl Peterson's, but I still wanted to post this since it's highly simplified and uses a different API- haven't seen any others that do it with GetFileInformationByHandleEx.


Code:

Option Explicit


Public Type FileStream
    StrmName As String
    StrmSize As Currency
    StrmAllocSize As Currency
End Type

Public Declare Function GetFileInformationByHandleEx Lib "kernel32" (ByVal hFile As Long, ByVal FileInformationClass As FILE_INFO_BY_HANDLE_CLASS, ByVal lpFileInformation As Long, ByVal dwBufferSize As Long) As Long
Public Declare Function CreateFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public Const GENERIC_READ    As Long = &H80000000
Public Const FILE_SHARE_READ = &H1&
Public Const OPEN_EXISTING = 3&
Public Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Public Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
End Type
Public Type FILE_STREAM_INFO
  NextEntryOffset As Long
  StreamNameLength As Long
  StreamSize As LARGE_INTEGER
  StreamAllocationSize As LARGE_INTEGER
  StreamName(0) As Integer
End Type
Public Enum FILE_INFO_BY_HANDLE_CLASS
    FileBasicInfo = 0
    FileStandardInfo = 1
    FileNameInfo = 2
    FileRenameInfo = 3
    FileDispositionInfo = 4
    FileAllocationInfo = 5
    FileEndOfFileInfo = 6
    FileStreamInfo = 7
    FileCompressionInfo = 8
    FileAttributeTagInfo = 9
    FileIdBothDirectoryInfo = 10 ' 0xA
    FileIdBothDirectoryRestartInfo = 11 ' 0xB
    FileIoPriorityHintInfo = 12 ' 0xC
    FileRemoteProtocolInfo = 13 ' 0xD
    FileFullDirectoryInfo = 14 ' 0xE
    FileFullDirectoryRestartInfo = 15 ' 0xF
    FileStorageInfo = 16 ' 0x10
    FileAlignmentInfo = 17 ' 0x11
    FileIdInfo = 18 ' 0x12
    FileIdExtdDirectoryInfo = 19 ' 0x13
    FileIdExtdDirectoryRestartInfo = 20 ' 0x14
    MaximumFileInfoByHandlesClass = 2
End Enum
Public Declare Sub ZeroMemory Lib "NTDLL.DLL" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As Long)
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Const INVALID_HANDLE_VALUE = -1&
Public Function LargeIntToCurrency(li As LARGE_INTEGER) As Currency
    CopyMemory LargeIntToCurrency, li, LenB(li)
    LargeIntToCurrency = LargeIntToCurrency * 10000
End Function
Public Function GetFileStreams(sFile As String, tStreams() As FileStream) As Long
ReDim tStreams(0)

Dim hFile As Long
hFile = CreateFileW(StrPtr(sFile), GENERIC_READ, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
If hFile <> INVALID_HANDLE_VALUE Then
    Dim tFSI As FILE_STREAM_INFO
    Dim byBuf() As Byte
    Dim byName() As Byte
    Dim nErr2 As Long
    Dim dwNameOffset As Long
    Dim dwDirOffset As Long
    Dim nEntryNum As Long
   
    ReDim byBuf((LenB(tFSI) + CLng(260 * 2 - 3)) * CLng(&H10000))
    ReDim byName(0)
   
    If GetFileInformationByHandleEx(hFile, FileStreamInfo, VarPtr(byBuf(0)), UBound(byBuf) + 1) Then
'    nErr2 = GetLastError()
'    Debug.Print "lasterr=0x" & Hex$(nErr2)
    dwDirOffset = 0
    Do While 1
        ReDim Preserve tStreams(nEntryNum)
        ZeroMemory tFSI, LenB(tFSI)
        CopyMemory tFSI, ByVal VarPtr(byBuf(dwDirOffset)), LenB(tFSI)
        Erase byName
       
        dwNameOffset = dwDirOffset + &H18
        dwNameOffset = VarPtr(byBuf(dwNameOffset))
        ReDim byName(tFSI.StreamNameLength - 1)
        CopyMemory byName(0), ByVal dwNameOffset, tFSI.StreamNameLength

        tStreams(nEntryNum).StrmSize = LargeIntToCurrency(tFSI.StreamSize)
        tStreams(nEntryNum).StrmAllocSize = LargeIntToCurrency(tFSI.StreamAllocationSize)
        tStreams(nEntryNum).StrmName = CStr(byName)
        nEntryNum = nEntryNum + 1
       
        If tFSI.NextEntryOffset = 0 Then Exit Do
        dwDirOffset = dwDirOffset + tFSI.NextEntryOffset
    Loop
    GetFileStreams = nEntryNum
    End If
clhn:
    CloseHandle hFile
End If
End Function

Once you know the stream name, you can address it with normal file functions to open, save, and delete it. The sample project uses VB's Open:
Code:

Private Sub List1_Click()
If List1.ListIndex <> -1 Then
    Text2.Text = LoadFile(Text1.Text & tStrm(List1.ListIndex).StrmName)
End If
End Sub


Public Function LoadFile(ByVal FileName As String) As String
  Dim hFile As Long
  On Error GoTo Hell
  hFile = FreeFile
  Open FileName For Binary As #hFile
      LoadFile = Space$(LOF(hFile))
      Get #hFile, , LoadFile
  Close #hFile
  Exit Function
Hell:
    Debug.Print "LoadFile::" & Err.Description
End Function

Attached Files

Viewing all articles
Browse latest Browse all 1448

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>