Page 1 of 1

Code to View NTFS Alternative Data Streams via streams.exe

Posted: Mon Jan 14, 2013 3:26 pm
by Zebuddi123
Hi to All

If anyone's interested just a small Console code example to parse System Internals streams.exe output to view the NTFS Alternative Data Sreams in your file system. just to be nosey and see whats there :lol:

Zebuddi. :D

http://technet.microsoft.com/en-us/sysinternals

Code: Select all

;-----------------------------------------------------------------------------------------------
;-----------------------------------------------------------------------------------------------
;Display NTFS Alternative Data Streams via parsing Sysytem Internals streams.exe
;
; create an output via redirection from streams.exe
; from cmd  stream.exe -s > c:\users\YOURNAME\desktop\streams.txt
; Author Zebuddi. 12/1/2013
;-----------------------------------------------------------------------------------------------
;-----------------------------------------------------------------------------------------------
Structure ads
	f$
	List ads$()
EndStructure
Define.i
NewList f.ads()

ProcedureDLL.s __GetLastErrorAsText(LastError.l) ; Used to get Last Win32 API Error
  
  If LastError 
    *ErrorBuffer = AllocateMemory(1024) 
    FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, LastError, 0, *ErrorBuffer, 1024, 0) 
    message.s=PeekS(*ErrorBuffer) 
    FreeMemory(*ErrorBuffer) 
  EndIf 
  
  ProcedureReturn message
EndProcedure
ProcedureDLL __GetLastError() ; Return the last Win32 API error as a string
  ; Error 1309 or 0 = No error 
  
  LastError=GetLastError_()
  If LastError=1309 : LastError=0 : EndIf
  ProcedureReturn LastError
EndProcedure


file$="C:\Users\"+UserName()+"\Desktop\streams.txt" ; place file and path in file$
; username()  requires PB5.10x
If OpenConsole("Alternative  Data Sreams: Viewer")
	EnableGraphicalConsole(1)
	If ReadFile(0,file$)
		For i=1 To 4
			ReadString(0) ; ignore file info
		Next
		; filter out  any streams and it`s main filename into linkedlist that we want
		While Eof(0)=0
			a$=LCase(Trim(ReadString(0)))
			If  Not FindString(a$,"Error opening") Or Not FindString(a$,"cannot") Or Not a$="" Or Not a$="." Or Not  a$=".." Or Not a$="..."
				If FindString(a$,"c:\")
					counter=0
					AddElement(f())
					f()\f$= a$
				ElseIf FindString(a$,"$data")
					AddElement(f()\ads$())
					counter+1
					f()\ads$()=a$
				EndIf
			EndIf
		Wend
		CloseFile(0)
	Else 
		ConsoleColor(12,0)
		ConsoleLocate(2,2)
		Print("Cannot open file "+file$)
		ConsoleLocate(2,4)
		PrintN("ERROR: "+__GetLastErrorAsText(__GetLastError()))
		ConsoleLocate(2,6)
		Print("Press any key to Quit!")
		Input()
		FreeList(f())
		End
	EndIf
		
	;process linkedlist read streams and display
	ResetList(f())
	FirstElement(f())
	ForEach f()
		ForEach f()\ads$()
			fecounter+1
			ads$=Mid(f()\ads$(),2)
			x=FindString(ads$,":")
			ads$=Mid(ads$,1,x-1)
			f$=f()\f$+ads$
			If ReadFile(0,f$)
				d+1: page+1
				PrintN(Str(d)+". "+ GetFilePart(f$))
				If page=15
					ConsoleColor(12,0)
					PrintN("")
					PrintN("Paging: press any key to continue!")
					Input()
					page=0
				EndIf
				ConsoleColor(10,0)
				PrintN( ReadString(0))
				ConsoleColor(15,0)
				PrintN(" ")
				CloseFile(0)
			EndIf
		Next
	Next
	
	If fecounter=0
		PrintN("")
		PrintN("No Alternative Data Streams Found")
		PrintN("")
		PrintN("Press Any key To Quit!")
	EndIf
	Input()
Else
	PrintN("cannot open file"+file$)
	PrintN("ERROR: "+__GetLastErrorAsText(__GetLastError()))
	PrintN("Press Any key To Quit!")
	Input()
EndIf
FreeList(f())
CloseConsole()
End

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Mon Jan 14, 2013 4:54 pm
by akj
@Zebuddi123:

PB 5.10PB running your program under Windows 7 complains it cannot open the streams.txt file.
The containing Desktop folder does already exist.

Have you any ideas on this?

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Mon Jan 14, 2013 7:05 pm
by Zebuddi123
Hi akj
1. Have you downloaded system internals suite or the streams.exe seperatly, streams.exe is part of the system internals suite.
2. Have you run streams.exe from the command line interpreter (cmd.exe) with streams.exe -s > c:\users\YourUserNameHere\desktop\streams.txt
you should cd in the directory where you have placed streams.exe
3. change the file$ paramater in the program to point to the file streams.exe has generated ie "c:\users\YourUserNameHere\desktop\streams.txt"

if you have done the above then make sure that access right to read from the directory streams.txt is in. try alternatively "c:\users\YourUserNameHere\documents\streams.txt"

copy the program again i have put last error check for you to help.

Zebuddi. :D

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Tue Jan 15, 2013 9:55 pm
by blueznl

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Thu Jan 31, 2013 11:16 pm
by Nico
Here a code to scan alternate data stream

Code: Select all

; ---------------------------------------------------------------
; PureBasic 4.51
;----------------------------------------------------------------
; Version 1.0
; Fonctionne à partir de Window 2000 (Système de Fichier NTFS)
;----------------------------------------------------------------
; --> Compiler en Unicode et Activer la gestion des Threads ! <--
;----------------------------------------------------------------
; Ce code permet seulement de lister les streams "Alternate Data"
; contenus dans les fichiers ou les dossiers
;----------------------------------------------------------------

;{- Enumerations / DataSections
;{ Windows
Enumeration
  #Window_Main
EndEnumeration
;}
;{ Gadgets
Enumeration
  #String_Dossier_Fichier
  #Button_Dossier
  #Button_Fichier
  #ListIcon_Stream
  #Button_Scan
  #Button_StopperScan
  #Button_SupprimerleStream
  #Button_EditeravecNotepad
  #Button_Extrairevers
  #Button_Quitter
  #Text_Info
  #Button_OuvrirExplorateur
  #BarreEtat
EndEnumeration
;}
;}

Global Chemin$
Global NomStream.s,StreamSize.q
Global FinRecherche.l

Procedure ReadStream(CheminDossier_CheminFichier.s)
  Protected file_h.i, z.i,*stream.WIN32_STREAM_ID
  Protected context.l=0, bytes_read.l=0, bytes_read1.l=0, seek_l = 0, seek_h = 0, Result.l=0
  Protected namesize.l,streamHight.q,streamLow.q
  
  file_h = CreateFile_(@CheminDossier_CheminFichier, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
  
  If file_h <> 0
    
    *stream.WIN32_STREAM_ID = AllocateMemory(20)
    z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    
    While (bytes_read <> 0 ) And Result=0
      
      namesize = *stream\dwStreamNameSize
      If namesize > 0
        *buffer = AllocateMemory(namesize)
        BackupRead_(file_h,*buffer,namesize,@bytes_read1,0,1,@context)
        NomStream= PeekS(*buffer,namesize/2,#PB_Unicode)
        FreeMemory(*buffer)
      EndIf
      
      If *stream\dwStreamID=#BACKUP_ALTERNATE_DATA
        streamHight.q=*stream\Size\highpart & $FFFFFFFF
        streamLow.q=*stream\Size\lowpart & $FFFFFFFF
        StreamSize.q =  streamHight<<32 |  streamLow
        Result=1
      EndIf 
      
      BackupSeek_(file_h, *stream\Size\lowpart, *stream\Size\highpart, @seek_l, @seek_h, @context)
      
      FreeMemory(*stream)
      *stream.WIN32_STREAM_ID = AllocateMemory(20)
      bytes_read = 0
      z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    Wend 
    
    FreeMemory(*stream)
    
    BackupRead_(file_h,0,0,@bytes_read,1,0,@context)
    CloseHandle_(file_h)
    
  EndIf 
  ProcedureReturn Result
EndProcedure 


Procedure.s ParseDirectory(folder.s, id.l = 0)
  Protected Type.s
  
  If Right(folder, 1) <> "\" 
    folder + "\" 
  EndIf  
  If ExamineDirectory(id, folder, "*.*") 
    If FinRecherche<2
      While NextDirectoryEntry(id)  
        If DirectoryEntryName(id) <> "." And DirectoryEntryName(id) <> ".."  
          ;########################################## 
          StatusBarText(#BarreEtat, 0, folder + DirectoryEntryName(id))
          If ReadStream(folder + DirectoryEntryName(id))
            If DirectoryEntryType(id)= #PB_DirectoryEntry_Directory 
              Type.s="Dossier"
            Else
              Type.s="Fichier"
            EndIf
            
            AddGadgetItem(#ListIcon_Stream, -1, NomStream+Chr(10)+Str(StreamSize)+Chr(10)+Type+Chr(10)+folder + DirectoryEntryName(id))
          EndIf
          ;##########################################  
          If DirectoryEntryType(id) = #PB_DirectoryEntry_Directory 
            ParseDirectory(folder + DirectoryEntryName(id), id + 1) 
          EndIf  
        EndIf  
      Wend
    EndIf 
    FinishDirectory(id) 
  EndIf  
EndProcedure   

Procedure ParseCheminFichierouDossier(folder.s)
  Protected Type.s
  
  If FileSize(folder)=-2
      Type.s="Dossier"
  Else
      Type.s="Fichier"
  EndIf
  If ReadStream(folder)
    AddGadgetItem(#ListIcon_Stream, -1, NomStream+Chr(10)+Str(StreamSize)+Chr(10)+Type+Chr(10)+folder)
  EndIf
  If Type="Dossier"
    ParseDirectory(folder)
  EndIf 
EndProcedure

Procedure DisableGadgetGroup1(Etat.l)
  DisableGadget(#Button_Dossier,Etat)
  DisableGadget(#Button_Fichier,Etat)
  DisableGadget(#Button_Scan,Etat)
  DisableGadget(#Button_Quitter,Etat)
EndProcedure

Procedure DisableGadgetGroup2(Etat.l)
  DisableGadget(#Button_SupprimerleStream,Etat)
  DisableGadget(#Button_EditeravecNotepad,Etat)
  DisableGadget(#Button_Extrairevers,Etat)
  DisableGadget(#Button_OuvrirExplorateur,Etat)
EndProcedure

Procedure Thread(lParam.i)
  ParseCheminFichierouDossier(Chemin$)
  StatusBarText(#BarreEtat, 0, "")
  FinRecherche=0
  DisableGadget(#Button_StopperScan,1)
  DisableGadgetGroup1(0)
EndProcedure

Procedure OpenWindow_Window_Main()
  If OpenWindow(#Window_Main, 200, 200, 610, 460, "Alternate Data Stream SPY", #PB_Window_SystemMenu|#PB_Window_TitleBar)
    StringGadget(#String_Dossier_Fichier, 10, 25, 520, 25, "", #PB_String_ReadOnly)
    ButtonGadget(#Button_Dossier, 540, 10, 60, 25, "Dossier")
    ButtonGadget(#Button_Fichier, 540, 40, 60, 25, "Fichier")
    ListIconGadget(#ListIcon_Stream, 10, 110, 590, 250, "Nom du Stream", 100, #PB_ListIcon_AlwaysShowSelection|#PB_ListIcon_FullRowSelect|#PB_ListIcon_GridLines)
    AddGadgetColumn(#ListIcon_Stream, 1, "Taille", 60)
    AddGadgetColumn(#ListIcon_Stream, 2, "Type", 60)
    AddGadgetColumn(#ListIcon_Stream, 3, "Chemin", 360)
    ButtonGadget(#Button_Scan, 110, 70, 170, 25, "Scan Alternate Data Stream")
    ButtonGadget(#Button_StopperScan, 340, 70, 155, 25, "Stopper le Scan")
    ButtonGadget(#Button_SupprimerleStream, 300, 370, 150, 25, "Supprimer le Stream")
    ButtonGadget(#Button_EditeravecNotepad, 10, 370, 140, 25, "Editer avec Notepad")
    ButtonGadget(#Button_Extrairevers, 150, 370, 150, 25, "Extraire le Stream vers...")
    ButtonGadget(#Button_Quitter, 240, 405, 130, 25, "Quitter")
    TextGadget(#Text_Info, 10, 5, 520, 20, "Vous pouvez glisser-déposer un Fichier ou un Dossier dans la zone de texte ci-dessous")
    ButtonGadget(#Button_OuvrirExplorateur, 450, 370, 150, 25, "Ouvrir dans l'explorateur")
    
    CreateStatusBar(#BarreEtat, WindowID(#Window_Main))
    AddStatusBarField(#PB_Ignore)
    
    EnableGadgetDrop(#String_Dossier_Fichier, #PB_Drop_Files, #PB_Drag_Copy)
    
    DisableGadget(#Button_StopperScan,1)
    DisableGadgetGroup2(1)
  EndIf
EndProcedure

OpenWindow_Window_Main()

;{- Event loop
Repeat
  Select WaitWindowEvent()
      ; ///////////////////
    Case #PB_Event_GadgetDrop
      Select EventGadget()
        Case #String_Dossier_Fichier
          Files$ = EventDropFiles()
          Count  = CountString(Files$, Chr(10)) + 1
          SetGadgetText(#String_Dossier_Fichier,StringField(Files$, 1, Chr(10)))
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Button_Dossier
          Chemin$ = PathRequester("Choisissez un répertoire:", "C:\")
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #Button_Fichier
          Chemin$ = OpenFileRequester("Choisissez un fichier:", "C:\", "*.*",0)
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #ListIcon_Stream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            DisableGadgetGroup2(0)
          Else
            DisableGadgetGroup2(1)
          EndIf 
          
        Case #Button_Scan
          ClearGadgetItems(#ListIcon_Stream)
          Chemin$=GetGadgetText(#String_Dossier_Fichier)
          If FileSize(Chemin$) <>-1
            DisableGadgetGroup1(1)
            DisableGadgetGroup2(1)
            DisableGadget(#Button_StopperScan,0)
            FinRecherche=1
            CreateThread(@Thread(),0)
          Else
            MessageRequester("Info","Choisissez un chemin de Dossier ou de Fichier valide !")
          EndIf 
          
        Case #Button_StopperScan
          FinRecherche=2
          DisableGadget(#Button_StopperScan,1)
          DisableGadgetGroup1(0)
          
        Case #Button_EditeravecNotepad
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            MessageRequester("Info","Dans certain cas, Notepad ne sera pas en mesure d'ouvrir le Stream !"+Chr(13)+"mais vous pouvez toujours faire une Extraction puis ensuite éditer le Fichier ainsi obtenu.")
            RunProgram("Notepad.exe",CheminStream+":"+NameStream,"")
          EndIf 
          
        Case #Button_Extrairevers
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            Taille.s=GetGadgetItemText(#ListIcon_Stream, Index , 1)
            If Taille<>"0"
              NomFichier$ = SaveFileRequester("Choisissez un emplacement:", NameStream, "*.*", 0)
              If NomFichier$<>""
                CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
                If ReadFile(0,CheminStream+":"+NameStream)
                  Longueur.q=Lof(0)
                  *Buffer.i=AllocateMemory(Longueur)
                  ReadData(0,*Buffer,Longueur)
                  CloseFile(0)
                  If CreateFile(0,NomFichier$)
                    WriteData(0,*Buffer,Longueur)
                    CloseFile(0)
                  EndIf
                  FreeMemory(*Buffer)
                Else
                  MessageRequester("Erreur","Le Stream n'a pas pu être sauvegardé !")
                EndIf
              EndIf
            Else
              MessageRequester("Info","La Taille de ce Stream est de 0 octet, il est inutile de vouloir le sauvegarder !")
            EndIf
          EndIf
          
        Case #Button_SupprimerleStream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            Type.s=GetGadgetItemText(#ListIcon_Stream, Index , 2)
            Message$="Êtes-vous sûr de vouloir supprimer le Stream : "+NameStream+" ?"+Chr(13)+"du "+Type+" "+CheminStream
            Resultat =MessageRequester("Attention",Message$, #PB_MessageRequester_YesNo)
            If Resultat = #PB_MessageRequester_Yes
              If DeleteFile(CheminStream+":"+NameStream)<>0
                RemoveGadgetItem(#ListIcon_Stream, Index)
              Else
                MessageRequester("Erreur","Le Stream n'a pas pu être effacé !")
              EndIf 
            EndIf 
          EndIf 
          
        Case #Button_OuvrirExplorateur
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            RunProgram("Explorer.exe","/e, /Select,"+CheminStream,"")
          EndIf  
          
        Case #Button_Quitter 
          CloseWindow(#Window_Main)
          Break
      EndSelect
      ; ////////////////////////
    Case #PB_Event_CloseWindow
      Select EventWindow()
        Case #Window_Main
          If FinRecherche=0
            CloseWindow(#Window_Main)
            Break
          Else
            MessageRequester("Info","Cliquez sur le Bouton Stopper le Scan avant de quitter !")
          EndIf 
      EndSelect
  EndSelect
ForEver
;
;}


Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Fri Feb 01, 2013 11:45 am
by Zebuddi123
Thank you Nico & bluznl

@ Nico ironically you posted that just in time. i released CLC beta yesterday to quickly translate pb code from one lanugage to another (strings and comments)
30 seconds later i have an english version :lol:

Zebuddi. :D

http://www.purebasic.fr/english/viewtop ... 14&t=53190

Code: Select all

; -------------------------------------------------- -------------
; PureBasic 4.51
; -------------------------------------------------- --------------
; Version 1.0
; Window Works from 2000 (File Systme NTFS)
; -------------------------------------------------- --------------
; -> Compile Unicode and Enable management Threads! <-
; -------------------------------------------------- --------------
; This code allows only list the streams "Alternate Data"
; contained in the files or folders
; -------------------------------------------------- --------------

; {- Enumerations / DataSections
; {Windows
Enumeration
  #Window_Main
EndEnumeration
; }
; {Toys
Enumeration
  #String_Dossier_Fichier
  #Button_Dossier
  #Button_Fichier
  #ListIcon_Stream
  #Button_Scan
  #Button_StopperScan
  #Button_SupprimerleStream
  #Button_EditeravecNotepad
  #Button_Extrairevers
  #Button_Quitter
  #Text_Info
  #Button_OuvrirExplorateur
  #BarreEtat
EndEnumeration
; }
; }

Global Chemin$
Global NomStream.s,StreamSize.q
Global FinRecherche.l

Procedure ReadStream(CheminDossier_CheminFichier.s)
  Protected file_h.i, z.i,*stream.WIN32_STREAM_ID
  Protected context.l=0, bytes_read.l=0, bytes_read1.l=0, seek_l = 0, seek_h = 0, Result.l=0
  Protected namesize.l,streamHight.q,streamLow.q
  
  file_h = CreateFile_(@CheminDossier_CheminFichier, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
  
  If file_h <> 0
    
    *stream.WIN32_STREAM_ID = AllocateMemory(20)
    z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    
    While (bytes_read <> 0 ) And Result=0
      
      namesize = *stream\dwStreamNameSize
      If namesize > 0
        *buffer = AllocateMemory(namesize)
        BackupRead_(file_h,*buffer,namesize,@bytes_read1,0,1,@context)
        NomStream= PeekS(*buffer,namesize/2,#PB_Unicode)
        FreeMemory(*buffer)
      EndIf
      
      If *stream\dwStreamID=#BACKUP_ALTERNATE_DATA
        streamHight.q=*stream\Size\highpart & $FFFFFFFF
        streamLow.q=*stream\Size\lowpart & $FFFFFFFF
        StreamSize.q =  streamHight<<32 |  streamLow
        Result=1
      EndIf 
      
      BackupSeek_(file_h, *stream\Size\lowpart, *stream\Size\highpart, @seek_l, @seek_h, @context)
      
      FreeMemory(*stream)
      *stream.WIN32_STREAM_ID = AllocateMemory(20)
      bytes_read = 0
      z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    Wend 
    
    FreeMemory(*stream)
    
    BackupRead_(file_h,0,0,@bytes_read,1,0,@context)
    CloseHandle_(file_h)
    
  EndIf 
  ProcedureReturn Result
EndProcedure 


Procedure.s ParseDirectory(folder.s, id.l = 0)
  Protected Type.s
  
  If Right(folder, 1) <> "\" 
    folder + "\" 
  EndIf  
  If ExamineDirectory(id, folder, "*. *") 
    If FinRecherche<2
      While NextDirectoryEntry(id)  
        If DirectoryEntryName(id) <> "." And DirectoryEntryName(id) <> ".."  
          ; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
          StatusBarText(#BarreEtat, 0, folder + DirectoryEntryName(id))
          If ReadStream(folder + DirectoryEntryName(id))
            If DirectoryEntryType(id)= #PB_DirectoryEntry_Directory 
              Type.s="Back"
            Else
              Type.s="File"
            EndIf
            
            AddGadgetItem(#ListIcon_Stream, -1, NomStream+Chr(10)+Str(StreamSize)+Chr(10)+Type+Chr(10)+folder + DirectoryEntryName(id))
          EndIf
          ; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #  
          If DirectoryEntryType(id) = #PB_DirectoryEntry_Directory 
            ParseDirectory(folder + DirectoryEntryName(id), id + 1) 
          EndIf  
        EndIf  
      Wend
    EndIf 
    FinishDirectory(id) 
  EndIf  
EndProcedure   

Procedure ParseCheminFichierouDossier(folder.s)
  Protected Type.s
  
  If FileSize(folder)=-2
      Type.s="Back"
  Else
      Type.s="File"
  EndIf
  If ReadStream(folder)
    AddGadgetItem(#ListIcon_Stream, -1, NomStream+Chr(10)+Str(StreamSize)+Chr(10)+Type+Chr(10)+folder)
  EndIf
  If Type="Back"
    ParseDirectory(folder)
  EndIf 
EndProcedure

Procedure DisableGadgetGroup1(Etat.l)
  DisableGadget(#Button_Dossier,Etat)
  DisableGadget(#Button_Fichier,Etat)
  DisableGadget(#Button_Scan,Etat)
  DisableGadget(#Button_Quitter,Etat)
EndProcedure

Procedure DisableGadgetGroup2(Etat.l)
  DisableGadget(#Button_SupprimerleStream,Etat)
  DisableGadget(#Button_EditeravecNotepad,Etat)
  DisableGadget(#Button_Extrairevers,Etat)
  DisableGadget(#Button_OuvrirExplorateur,Etat)
EndProcedure

Procedure Thread(lParam.i)
  ParseCheminFichierouDossier(Chemin$)
  StatusBarText(#BarreEtat, 0, "")
  FinRecherche=0
  DisableGadget(#Button_StopperScan,1)
  DisableGadgetGroup1(0)
EndProcedure

Procedure OpenWindow_Window_Main()
  If OpenWindow(#Window_Main, 200, 200, 610, 460, "Alternate Data Stream SPY", #PB_Window_SystemMenu|#PB_Window_TitleBar)
    StringGadget(#String_Dossier_Fichier, 10, 25, 520, 25, "", #PB_String_ReadOnly)
    ButtonGadget(#Button_Dossier, 540, 10, 60, 25, "Back")
    ButtonGadget(#Button_Fichier, 540, 40, 60, 25, "File")
    ListIconGadget(#ListIcon_Stream, 10, 110, 590, 250, "Name of Stream", 100, #PB_ListIcon_AlwaysShowSelection|#PB_ListIcon_FullRowSelect|#PB_ListIcon_GridLines)
    AddGadgetColumn(#ListIcon_Stream, 1, "Size", 60)
    AddGadgetColumn(#ListIcon_Stream, 2, "Type", 60)
    AddGadgetColumn(#ListIcon_Stream, 3, "Path", 360)
    ButtonGadget(#Button_Scan, 110, 70, 170, 25, "Scan Alternate Data Stream")
    ButtonGadget(#Button_StopperScan, 340, 70, 155, 25, "Stop the Scan")
    ButtonGadget(#Button_SupprimerleStream, 300, 370, 150, 25, "Remove Stream")
    ButtonGadget(#Button_EditeravecNotepad, 10, 370, 140, 25, "Edit with Notepad")
    ButtonGadget(#Button_Extrairevers, 150, 370, 150, 25, "Stream to extract the ...")
    ButtonGadget(#Button_Quitter, 240, 405, 130, 25, "Leave")
    TextGadget(#Text_Info, 10, 5, 520, 20, "You can drag dposer a File or Folder in the text box below")
    ButtonGadget(#Button_OuvrirExplorateur, 450, 370, 150, 25, "Open in Browser")
    
    CreateStatusBar(#BarreEtat, WindowID(#Window_Main))
    AddStatusBarField(#PB_Ignore)
    
    EnableGadgetDrop(#String_Dossier_Fichier, #PB_Drop_Files, #PB_Drag_Copy)
    
    DisableGadget(#Button_StopperScan,1)
    DisableGadgetGroup2(1)
  EndIf
EndProcedure

OpenWindow_Window_Main()

; {- Event loop
Repeat
  Select WaitWindowEvent()
      ; / / / / / / / / / / / / / / / / / / /
    Case #PB_Event_GadgetDrop
      Select EventGadget()
        Case #String_Dossier_Fichier
          Files$ = EventDropFiles()
          Count  = CountString(Files$, Chr(10)) + 1
          SetGadgetText(#String_Dossier_Fichier,StringField(Files$, 1, Chr(10)))
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Button_Dossier
          Chemin$ = PathRequester("Select a directory:", "C: \")
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #Button_Fichier
          Chemin$ = OpenFileRequester("Choose a file:", "C: \", "*. *",0)
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #ListIcon_Stream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            DisableGadgetGroup2(0)
          Else
            DisableGadgetGroup2(1)
          EndIf 
          
        Case #Button_Scan
          ClearGadgetItems(#ListIcon_Stream)
          Chemin$=GetGadgetText(#String_Dossier_Fichier)
          If FileSize(Chemin$) <>-1
            DisableGadgetGroup1(1)
            DisableGadgetGroup2(1)
            DisableGadget(#Button_StopperScan,0)
            FinRecherche=1
            CreateThread(@Thread(),0)
          Else
            MessageRequester("Info","Choose a folder path or file valid!")
          EndIf 
          
        Case #Button_StopperScan
          FinRecherche=2
          DisableGadget(#Button_StopperScan,1)
          DisableGadgetGroup1(0)
          
        Case #Button_EditeravecNotepad
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            MessageRequester("Info","In some cases, Notepad will not be able to open the Stream!"+Chr(13)+"but you can always make an Extraction File and then diter obtained.")
            RunProgram("Notepad.exe",CheminStream+":"+NameStream,"")
          EndIf 
          
        Case #Button_Extrairevers
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            Taille.s=GetGadgetItemText(#ListIcon_Stream, Index , 1)
            If Taille<>"0"
              NomFichier$ = SaveFileRequester("Choose a location:", NameStream, "*. *", 0)
              If NomFichier$<>""
                CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
                If ReadFile(0,CheminStream+":"+NameStream)
                  Longueur.q=Lof(0)
                  *Buffer=AllocateMemory(Longueur)
                  ReadData(0,*Buffer,Longueur)
                  CloseFile(0)
                  If CreateFile(0,NomFichier$)
                    WriteData(0,*Buffer,Longueur)
                    CloseFile(0)
                  EndIf
                  FreeMemory(*Buffer)
                Else
                  MessageRequester("Error","Stream could not be Save at!")
                EndIf
              EndIf
            Else
              MessageRequester("Info","Size of this Stream is 0 bytes, it is useless to save it!")
            EndIf
          EndIf
          
        Case #Button_SupprimerleStream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            Type.s=GetGadgetItemText(#ListIcon_Stream, Index , 2)
            Message$="your you sure you want to delete the Stream"+NameStream+"?"+Chr(13)+"of"+Type+" "+CheminStream
            Resultat =MessageRequester("Attention",Message$, #PB_MessageRequester_YesNo)
            If Resultat = #PB_MessageRequester_Yes
              If DeleteFile(CheminStream+":"+NameStream)<>0
                RemoveGadgetItem(#ListIcon_Stream, Index)
              Else
                MessageRequester("Error","Stream could not be erased!")
              EndIf 
            EndIf 
          EndIf 
          
        Case #Button_OuvrirExplorateur
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            RunProgram("Explorer.exe","/ E, / select,"+CheminStream,"")
          EndIf  
          
        Case #Button_Quitter 
          CloseWindow(#Window_Main)
          Break
      EndSelect
      ; / / / / / / / / / / / / / / / / / / / / / / / /
    Case #PB_Event_CloseWindow
      Select EventWindow()
        Case #Window_Main
          If FinRecherche=0
            CloseWindow(#Window_Main)
            Break
          Else
            MessageRequester("Info","Click the button Stop Scan before leaving!")
          EndIf 
      EndSelect
  EndSelect
ForEver
;
; }

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Fri Feb 01, 2013 1:07 pm
by electrochrisso
@ Nico ironically you posted that just in time. i released CLC beta yesterday to quickly translate pb code from one lanugage to another (strings and comments)
30 seconds later i have an english version

Zebuddi.
8)

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Mon Feb 04, 2013 7:45 pm
by Nico
@Zebuddi123

Good job :D

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Sun Sep 01, 2013 11:00 pm
by jassing
Nico: nice job, but here, I have files with multiple ads, code only lists 1st one. Haven't yet figured out why...

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Tue Sep 03, 2013 9:30 am
by kvitaliy
Very nice :!:

Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Sat Sep 07, 2013 9:34 pm
by Nico
jassing wrote:Nico: nice job, but here, I have files with multiple ads, code only lists 1st one. Haven't yet figured out why...
Yes, you are right!

The modified code:

Code: Select all

; ---------------------------------------------------------------
; PureBasic 4.51
;----------------------------------------------------------------
; Version 1.0
; Fonctionne à partir de Window 2000 (Système de Fichier NTFS)
;----------------------------------------------------------------
; --> Compiler en Unicode et Activer la gestion des Threads ! <--
;----------------------------------------------------------------
; Ce code permet seulement de lister les streams "Alternate Data"
; contenus dans les fichiers ou les dossiers
;----------------------------------------------------------------

;{- Enumerations / DataSections
;{ Windows
Enumeration
  #Window_Main
EndEnumeration
;}
;{ Gadgets
Enumeration
  #String_Dossier_Fichier
  #Button_Dossier
  #Button_Fichier
  #ListIcon_Stream
  #Button_Scan
  #Button_StopperScan
  #Button_SupprimerleStream
  #Button_EditeravecNotepad
  #Button_Extrairevers
  #Button_Quitter
  #Text_Info
  #Button_OuvrirExplorateur
  #BarreEtat
EndEnumeration
;}
;}

Global Chemin$
Global NomStream.s, Dim NomStream.s(100), Dim StreamSize.q(100), StreamCount.l
Global FinRecherche.l

Procedure ReadStream(CheminDossier_CheminFichier.s)
  Protected file_h.i, z.i,*stream.WIN32_STREAM_ID
  Protected context.l=0, bytes_read.l=0, bytes_read1.l=0, seek_l = 0, seek_h = 0, Result.l=0
  Protected namesize.l,streamHight.q,streamLow.q,count.l
  
  file_h = CreateFile_(@CheminDossier_CheminFichier, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
  
  If file_h <> 0
    
    *stream.WIN32_STREAM_ID = AllocateMemory(20)
    z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    
    While (bytes_read <> 0 ) ;And Result=0
      
      Debug *stream\dwStreamID
      
      If *stream\dwStreamID=#BACKUP_ALTERNATE_DATA  
        namesize = *stream\dwStreamNameSize
        If namesize > 0
          *buffer = AllocateMemory(namesize)
          BackupRead_(file_h,*buffer,namesize,@bytes_read1,0,1,@context)
          NomStream(count)= PeekS(*buffer,namesize/2,#PB_Unicode)
          FreeMemory(*buffer)
          
          
          
          streamHight.q=*stream\Size\highpart & $FFFFFFFF
          streamLow.q=*stream\Size\lowpart & $FFFFFFFF
          StreamSize(count) =  streamHight<<32 |  streamLow
          StreamCount = count
          count = count + 1
          Result=1
        EndIf
      EndIf   
      
      BackupSeek_(file_h, *stream\Size\lowpart, *stream\Size\highpart, @seek_l, @seek_h, @context)
      
      FreeMemory(*stream)
      *stream.WIN32_STREAM_ID = AllocateMemory(20)
      bytes_read = 0
      z = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    Wend 
    
    FreeMemory(*stream)
    
    BackupRead_(file_h,0,0,@bytes_read,1,0,@context)
    CloseHandle_(file_h)
    
  EndIf 
  ProcedureReturn Result
EndProcedure 


Procedure.s ParseDirectory(folder.s, id.l = 0)
  Protected Type.s
  
  If Right(folder, 1) <> "\" 
    folder + "\" 
  EndIf  
  If ExamineDirectory(id, folder, "*.*") 
    If FinRecherche<2
      While NextDirectoryEntry(id)  
        If DirectoryEntryName(id) <> "." And DirectoryEntryName(id) <> ".."  
          ;########################################## 
          StatusBarText(#BarreEtat, 0, folder + DirectoryEntryName(id))
          If ReadStream(folder + DirectoryEntryName(id))
            If DirectoryEntryType(id)= #PB_DirectoryEntry_Directory 
              Type.s="Dossier"
            Else
              Type.s="Fichier"
            EndIf
            Debug StreamCount 
            For count = 0 To StreamCount 
              AddGadgetItem(#ListIcon_Stream, -1, NomStream(count)+Chr(10)+Str(StreamSize(count))+Chr(10)+Type+Chr(10)+folder + DirectoryEntryName(id))
            Next
            StreamCount = 0
          EndIf
          ;##########################################  
          If DirectoryEntryType(id) = #PB_DirectoryEntry_Directory 
            ParseDirectory(folder + DirectoryEntryName(id), id + 1) 
          EndIf  
        EndIf  
      Wend
    EndIf 
    FinishDirectory(id) 
  EndIf  
EndProcedure   

Procedure ParseCheminFichierouDossier(folder.s)
  Protected Type.s
  
  If FileSize(folder)=-2
    Type.s="Dossier"
  Else
    Type.s="Fichier"
  EndIf
  If ReadStream(folder)
    For count = 0 To StreamCount 
      AddGadgetItem(#ListIcon_Stream, -1, NomStream(count)+Chr(10)+Str(StreamSize(count))+Chr(10)+Type+Chr(10)+folder)
    Next
    StreamCount = 0
  EndIf
  If Type="Dossier"
    ParseDirectory(folder)
  EndIf 
EndProcedure

Procedure DisableGadgetGroup1(Etat.l)
  DisableGadget(#Button_Dossier,Etat)
  DisableGadget(#Button_Fichier,Etat)
  DisableGadget(#Button_Scan,Etat)
  DisableGadget(#Button_Quitter,Etat)
EndProcedure

Procedure DisableGadgetGroup2(Etat.l)
  DisableGadget(#Button_SupprimerleStream,Etat)
  DisableGadget(#Button_EditeravecNotepad,Etat)
  DisableGadget(#Button_Extrairevers,Etat)
  DisableGadget(#Button_OuvrirExplorateur,Etat)
EndProcedure

Procedure Thread(lParam.i)
  ParseCheminFichierouDossier(Chemin$)
  StatusBarText(#BarreEtat, 0, "")
  FinRecherche=0
  DisableGadget(#Button_StopperScan,1)
  DisableGadgetGroup1(0)
EndProcedure

Procedure OpenWindow_Window_Main()
  If OpenWindow(#Window_Main, 200, 200, 610, 460, "Alternate Data Stream SPY", #PB_Window_SystemMenu|#PB_Window_TitleBar)
    StringGadget(#String_Dossier_Fichier, 10, 25, 520, 25, "", #PB_String_ReadOnly)
    ButtonGadget(#Button_Dossier, 540, 10, 60, 25, "Dossier")
    ButtonGadget(#Button_Fichier, 540, 40, 60, 25, "Fichier")
    ListIconGadget(#ListIcon_Stream, 10, 110, 590, 250, "Nom du Stream", 100, #PB_ListIcon_AlwaysShowSelection|#PB_ListIcon_FullRowSelect|#PB_ListIcon_GridLines)
    AddGadgetColumn(#ListIcon_Stream, 1, "Taille", 60)
    AddGadgetColumn(#ListIcon_Stream, 2, "Type", 60)
    AddGadgetColumn(#ListIcon_Stream, 3, "Chemin", 360)
    ButtonGadget(#Button_Scan, 110, 70, 170, 25, "Scan Alternate Data Stream")
    ButtonGadget(#Button_StopperScan, 340, 70, 155, 25, "Stopper le Scan")
    ButtonGadget(#Button_SupprimerleStream, 300, 370, 150, 25, "Supprimer le Stream")
    ButtonGadget(#Button_EditeravecNotepad, 10, 370, 140, 25, "Editer avec Notepad")
    ButtonGadget(#Button_Extrairevers, 150, 370, 150, 25, "Extraire le Stream vers...")
    ButtonGadget(#Button_Quitter, 240, 405, 130, 25, "Quitter")
    TextGadget(#Text_Info, 10, 5, 520, 20, "Vous pouvez glisser-déposer un Fichier ou un Dossier dans la zone de texte ci-dessous")
    ButtonGadget(#Button_OuvrirExplorateur, 450, 370, 150, 25, "Ouvrir dans l'explorateur")
    
    CreateStatusBar(#BarreEtat, WindowID(#Window_Main))
    AddStatusBarField(#PB_Ignore)
    
    EnableGadgetDrop(#String_Dossier_Fichier, #PB_Drop_Files, #PB_Drag_Copy)
    
    DisableGadget(#Button_StopperScan,1)
    DisableGadgetGroup2(1)
  EndIf
EndProcedure

OpenWindow_Window_Main()

;{- Event loop
Repeat
  Select WaitWindowEvent()
      ; ///////////////////
    Case #PB_Event_GadgetDrop
      Select EventGadget()
        Case #String_Dossier_Fichier
          Files$ = EventDropFiles()
          Count  = CountString(Files$, Chr(10)) + 1
          SetGadgetText(#String_Dossier_Fichier,StringField(Files$, 1, Chr(10)))
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Button_Dossier
          Chemin$ = PathRequester("Choisissez un répertoire:", "C:\")
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #Button_Fichier
          Chemin$ = OpenFileRequester("Choisissez un fichier:", "C:\", "*.*",0)
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #ListIcon_Stream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            DisableGadgetGroup2(0)
          Else
            DisableGadgetGroup2(1)
          EndIf 
          
        Case #Button_Scan
          ClearGadgetItems(#ListIcon_Stream)
          Chemin$=GetGadgetText(#String_Dossier_Fichier)
          If FileSize(Chemin$) <>-1
            DisableGadgetGroup1(1)
            DisableGadgetGroup2(1)
            DisableGadget(#Button_StopperScan,0)
            FinRecherche=1
            CreateThread(@Thread(),0)
          Else
            MessageRequester("Info","Choisissez un chemin de Dossier ou de Fichier valide !")
          EndIf 
          
        Case #Button_StopperScan
          FinRecherche=2
          DisableGadget(#Button_StopperScan,1)
          DisableGadgetGroup1(0)
          
        Case #Button_EditeravecNotepad
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            MessageRequester("Info","Dans certain cas, Notepad ne sera pas en mesure d'ouvrir le Stream !"+Chr(13)+"mais vous pouvez toujours faire une Extraction puis ensuite éditer le Fichier ainsi obtenu.")
            RunProgram("Notepad.exe",CheminStream+":"+NameStream,"")
          EndIf 
          
        Case #Button_Extrairevers
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            Taille.s=GetGadgetItemText(#ListIcon_Stream, Index , 1)
            If Taille<>"0"
              NomFichier$ = SaveFileRequester("Choisissez un emplacement:", NameStream, "*.*", 0)
              If NomFichier$<>""
                CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
                If ReadFile(0,CheminStream+":"+NameStream)
                  Longueur.q=Lof(0)
                  *Buffer=AllocateMemory(Longueur)
                  ReadData(0,*Buffer,Longueur)
                  CloseFile(0)
                  If CreateFile(0,NomFichier$)
                    WriteData(0,*Buffer,Longueur)
                    CloseFile(0)
                  EndIf
                  FreeMemory(*Buffer)
                Else
                  MessageRequester("Erreur","Le Stream n'a pas pu être sauvegardé !")
                EndIf
              EndIf
            Else
              MessageRequester("Info","La Taille de ce Stream est de 0 octet, il est inutile de vouloir le sauvegarder !")
            EndIf
          EndIf
          
        Case #Button_SupprimerleStream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            Type.s=GetGadgetItemText(#ListIcon_Stream, Index , 2)
            Message$="Êtes-vous sûr de vouloir supprimer le Stream : "+NameStream+" ?"+Chr(13)+"du "+Type+" "+CheminStream
            Resultat =MessageRequester("Attention",Message$, #PB_MessageRequester_YesNo)
            If Resultat = #PB_MessageRequester_Yes
              If DeleteFile(CheminStream+":"+NameStream)<>0
                RemoveGadgetItem(#ListIcon_Stream, Index)
              Else
                MessageRequester("Erreur","Le Stream n'a pas pu être effacé !")
              EndIf 
            EndIf 
          EndIf 
          
        Case #Button_OuvrirExplorateur
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            RunProgram("Explorer.exe","/e, /Select,"+CheminStream,"")
          EndIf  
          
        Case #Button_Quitter 
          CloseWindow(#Window_Main)
          Break
      EndSelect
      ; ////////////////////////
    Case #PB_Event_CloseWindow
      Select EventWindow()
        Case #Window_Main
          If FinRecherche=0
            CloseWindow(#Window_Main)
            Break
          Else
            MessageRequester("Info","Cliquez sur le Bouton Stopper le Scan avant de quitter !")
          EndIf 
      EndSelect
  EndSelect
ForEver
;
;}


Re: Code to View NTFS Alternative Data Streams via streams.e

Posted: Sat Sep 07, 2013 10:31 pm
by jassing
nice!

Re: Code to View NTFS Alternative Data Streams via streams.exe

Posted: Tue Mar 14, 2023 10:07 pm
by RichAlgeni
Kudos to Blueznl, Zebuddi, Nico and everyone else who contributes to great code. I recently ran into an issue where I have to backup a Quickbooks file, even thought it is very often in use, and therefor locked to read access. I found this wonderful program on streams, which I have modified to work with PB 6.01 on Window 10/11. Unfortunately, between reading Microsoft documentation, and enduring a snow storm in North Swanzey NH, when I really should be in Florida, my brain has been fried beyond the capability of further use today. Can anyone tell me where the file data actually reside here, please? My plan is to use the LZMA packer and write the subsequent file to a NAS drive.
Thanks so much!
Rich

Code: Select all

; ---------------------------------------
; PureBasic 6.01
; Compile to Unicode
; Read Stream for file or directory
;----------------------------------------

EnableExplicit

Define fileHandle.l
Define filename.s
Define context.i     = 0
Define bytes_read0.i = 0
Define bytes_read1.l = 0
Define seek_low.i    = 0
Define seek_high.i   = 0
Define result.i      = 0
Define streamNdx     = 0
Define streamID.i
Define streamHigh.q
Define streamLow.q
Define streamsize.q
Define namesize.l
Define totRead.i
Define *stream.WIN32_STREAM_ID
Define *buffer
Define byteNdx

filename = "D:\dev\ascii_chart.txt"
Debug "start"

; i can read al alternative streams from an open and locked file, using

fileHandle = CreateFile_(@filename, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)

If fileHandle = 0
    Debug "can't open " + filename
    End
Else
    Debug "Processing: " + filename
EndIf

Debug "=========================================="

*stream.WIN32_STREAM_ID = AllocateMemory(20)
totRead = BackupRead_(fileHandle, *stream, 20, @bytes_read0, 0, 1, @context)

While (bytes_read0 <> 0 )
    Debug "totRead = " + Str(totRead)
    streamNdx = streamNdx + 1
    Debug "stream " + Str(streamNdx)
    Debug "bytes read " + Str(bytes_read0)
    streamID = *stream\dwStreamID
    Debug "stream id " + Str(streamID)

;    For byteNdx=0 To 40 Step 2
;        Debug Str(PeekW(*stream + byteNdx))        
;    Next

    Select streamID

    Case #BACKUP_DATA ;0x00000001
        Debug "Standard Data. This corresponds To the NTFS $DATA stream type on the Default (unnamed) Data stream."
    Case #BACKUP_EA_DATA ;0x00000002
        Debug "Extended attribute Data. This corresponds To the NTFS $EA stream type."
    Case #BACKUP_SECURITY_DATA ;0x00000003
        Debug "Security descriptor Data."
    Case #BACKUP_ALTERNATE_DATA ;0x00000004
        Debug "Alternative Data streams. This corresponds To the NTFS $DATA stream type on a named Data stream."
    Case #BACKUP_LINK ;0x00000005
        Debug "Hard link information. This corresponds To the NTFS $FILE_NAME stream type."
    Case 6 ;#BACKUP_PROPERTY_DATA ;0x00000006
        Debug "Property Data."
    Case 7 ;#BACKUP_OBJECT_ID ;0x00000007
        Debug "Objects identifiers. This corresponds To the NTFS $OBJECT_ID stream type."
    Case 8 ;#BACKUP_REPARSE_DATA ;0x00000008
        Debug "Reparse points. This corresponds To the NTFS $REPARSE_POINT stream type."
    Case 9 ;#BACKUP_SPARSE_BLOCK ;0x00000009
        Debug "Sparse file. This corresponds To the NTFS $DATA stream type For a sparse file."
    Case 10 ;#BACKUP_TXFS_DATA ;0x0000000A
        Debug "Transactional NTFS (TxF) Data stream. This corresponds To the NTFS $TXF_DATA stream type."
    Default
        Debug "Stream ID: " + Str(streamID)
    EndSelect

    namesize = *stream\dwStreamNameSize
    If namesize > 0
        Debug "namesize " + Str(namesize)
        *buffer = AllocateMemory(namesize)
        BackupRead_(fileHandle, *buffer, namesize, @bytes_read1, 0, 1, @context)
        Debug PeekS(*buffer, namesize / 2, #PB_Unicode)
        FreeMemory(*buffer)
    EndIf

    streamHigh = *stream\Size\LongPart\HighPart
    streamLow  = *stream\Size\LongPart\LowPart
    streamsize =  streamHigh << 32 | streamLow
    Debug "streamsize = " + Str(streamsize)

    Debug "=========================================="

    result = BackupSeek_(fileHandle, *stream\Size\LongPart\LowPart, *stream\Size\LongPart\HighPart, @seek_low, @seek_high, @context)
    Debug "Result = " + Str(Result)

    FreeMemory(*stream)
    *stream.WIN32_STREAM_ID = AllocateMemory(20)
    bytes_read0 = 0
    totRead = BackupRead_(fileHandle, *stream, 20, @bytes_read0, 0, 1, @context)
Wend

FreeMemory(*stream)

BackupRead_(fileHandle, 0, 0, @bytes_read0, 1, 0, @context)
CloseHandle_(fileHandle)

Debug "done"
Here is the actual file I am reading as a test:

Code: Select all

  Dec     HEx     Char    ctrl   |    Dec     Hex    Char   |    Dec     Hex    Char    |    Dec     Hex    Char
  ===     ===     ====    ===    |    ===     ===    ====   |    ===     ===    ====    |    ===     ===    ====
    0     00h     NUL     ^@     |     32     20h     SP    |     64     40h     @      |     96     60h     `
    1     01h     SOH     ^A     |     33     21h     !     |     65     41h     A      |     97     61h     a
    2     02h     STX     ^B     |     34     22h     "     |     66     42h     B      |     98     62h     b
    3     03h     ETX     ^C     |     35     23h     #     |     67     43h     C      |     99     63h     c
    4     04h     EOT     ^D     |     36     24h     $     |     68     44h     D      |    100     64h     d
    5     05h     ENQ     ^E     |     37     25h     %     |     69     45h     E      |    101     65h     e
    6     06h     ACK     ^F     |     38     26h     &     |     70     46h     F      |    102     66h     f
    7     07h     BEL     ^G     |     39     27h     '     |     71     47h     G      |    103     67h     g
    8     08h     BS      ^H     |     40     28h     (     |     72     48h     H      |    104     68h     h
    9     09h     HT      ^I     |     41     29h     )     |     73     49h     I      |    105     69h     i
   10     0Ah     LF      ^J     |     42     2Ah     *     |     74     4Ah     J      |    106     6Ah     j
   11     0Bh     VT      ^K     |     43     2Bh     +     |     75     4Bh     K      |    107     6Bh     k
   12     0Ch     FF      ^L     |     44     2Ch     ,     |     76     4Ch     L      |    108     6Ch     l
   13     0Dh     CR      ^M     |     45     2Dh     -     |     77     4Dh     M      |    109     6Dh     m
   14     0Eh     SO      ^N     |     46     2Eh     .     |     78     4Eh     N      |    110     6Eh     n
   15     0Fh     SI      ^O     |     47     2Fh     /     |     79     4Fh     O      |    111     6Fh     o
   --     ---     ---     --     |     --     ---     --    |     --     ---     -      |    ---     ---     ---
   16     10h     DLE     ^P     |     48     30h     0     |     80     50h     P      |    112     70h     p
   17     11h     DC1     ^Q     |     49     31h     1     |     81     51h     Q      |    113     71h     q
   18     12h     DC2     ^R     |     50     32h     2     |     82     52h     R      |    114     72h     r
   19     13h     DC3     ^S     |     51     33h     3     |     83     53h     S      |    115     73h     s
   20     14h     DC4     ^T     |     52     34h     4     |     84     54h     T      |    116     74h     t
   21     15h     NAK     ^U     |     53     35h     5     |     85     55h     U      |    117     75h     u
   22     16h     SYN     ^V     |     54     36h     6     |     86     56h     V      |    118     76h     v
   23     17h     ETB     ^W     |     55     37h     7     |     87     57h     W      |    119     77h     w
   24     18h     CAN     ^X     |     56     38h     8     |     88     58h     X      |    120     78h     x
   25     19h     EM      ^Y     |     57     39h     9     |     89     59h     Y      |    121     79h     y
   26     1Ah     SUB     ^Z     |     58     3Ah     :     |     90     5Ah     Z      |    122     7Ah     z
   27     1Bh     ESC     ^[     |     59     3Bh     ;     |     91     5Bh     [      |    123     7Bh     {
   28     1Ch     FS      ^\     |     60     3Ch     <     |     92     5Ch     \      |    124     7Ch     |
   29     1Dh     GS      ^]     |     61     3Dh     =     |     93     5Dh     ]      |    125     7Dh     }
   30     1Eh     RS      ^^     |     62     3Eh     >     |     94     5Eh     ^      |    126     7Eh     ~
   31     1Fh     US      ^_     |     63     3Fh     ?     |     95     5Fh     _      |    127     7Fh     DEL
   ==     ===     ===     ==     |     ==     ===     ==    |     ==     ===     =      |    ===     ===     ===


Re: Code to View NTFS Alternative Data Streams via streams.exe

Posted: Thu Mar 16, 2023 6:44 am
by Thunder93
Updated the code so it wouldn't crash with the PB 6.01 LTS I was testing on. Minor corrections for English translation.

Image

Code: Select all

; ---------------------------------------------------------------
; PureBasic 6.01 LTS (x64 & x86)
; -------------------------------------------------- --------------
; Version 1.01
; Window Works from 2000 (File System NTFS)
; -------------------------------------------------- --------------
; This code allows only list the streams "Alternate Data"
; contained in the files or folders
; -------------------------------------------------- --------------

; {- Enumerations / DataSections
; {Windows
Enumeration
  #Window_Main
EndEnumeration
;}
;{ Gadgets
Enumeration
  #String_Dossier_Fichier
  #Button_Dossier
  #Button_Fichier
  #ListIcon_Stream
  #Button_Scan
  #Button_StopperScan
  #Button_SupprimerleStream
  #Button_EditeravecNotepad
  #Button_Extrairevers
  #Button_Quitter
  #Text_Info
  #Button_OuvrirExplorateur
  #BarreEtat
EndEnumeration
; }
; }

Global Chemin$
Global NomStream.s, Dim NomStream.s(100), Dim StreamSize.q(100), StreamCount.l
Global FinRecherche.l

Procedure ReadStream(CheminDossier_CheminFichier.s)
  Protected file_h.i, totRead.i,*stream.WIN32_STREAM_ID, *buffer
  Protected context.i=0, bytes_read.i=0, bytes_read1.l=0, seek_l.i = 0, seek_h.i = 0, Result.i=0
  Protected namesize.l, streamHight.q, streamLow.q, count.l
 
  file_h = CreateFile_(@CheminDossier_CheminFichier, #READ_CONTROL, 0, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
  
  If file_h <> 0
    
    *stream.WIN32_STREAM_ID = AllocateMemory(20)
    totRead = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    
    While (bytes_read <> 0 ) ;And Result=0
      
      If *stream\dwStreamID=#BACKUP_ALTERNATE_DATA  
        namesize = *stream\dwStreamNameSize
        If namesize > 0
          *buffer = AllocateMemory(namesize)
          BackupRead_(file_h,*buffer,namesize,@bytes_read1,0,1,@context)
          NomStream(count)= PeekS(*buffer,namesize/2,#PB_Unicode)
          FreeMemory(*buffer)         
          
          streamHight.q=*stream\Size\LongPart\highpart & $FFFFFFFF
          streamLow.q=*stream\Size\LongPart\lowpart & $FFFFFFFF
          StreamSize(count) =  streamHight<<32 |  streamLow
          StreamCount = count
          count = count + 1
          Result=1
        EndIf
      EndIf   
      
      BackupSeek_(file_h, *stream\Size\LongPart\lowpart, *stream\Size\LongPart\highpart, @seek_l, @seek_h, @context)
      
      FreeMemory(*stream)
      *stream.WIN32_STREAM_ID = AllocateMemory(20)
      bytes_read = 0
      totRead = BackupRead_(file_h, *stream, 20, @bytes_read, 0, 1, @context)
    Wend 
    
    FreeMemory(*stream)
    
    BackupRead_(file_h,0,0,@bytes_read,1,0,@context)
    CloseHandle_(file_h)
    
  EndIf 
  ProcedureReturn Result
EndProcedure 


Procedure.s ParseDirectory(folder.s, id.l = 0)
  Protected Type.s
  
  If Right(folder, 1) <> "\" 
    folder + "\" 
  EndIf  
  If ExamineDirectory(id, folder, "*.*") 
    If FinRecherche<2
      While NextDirectoryEntry(id)  
        If DirectoryEntryName(id) <> "." And DirectoryEntryName(id) <> ".."  
          ; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
          StatusBarText(#BarreEtat, 0, folder + DirectoryEntryName(id))
          If ReadStream(folder + DirectoryEntryName(id))
            If DirectoryEntryType(id)= #PB_DirectoryEntry_Directory 
              Type.s="Back"
            Else
              Type.s="File"
            EndIf

            For count = 0 To StreamCount 
              AddGadgetItem(#ListIcon_Stream, -1, NomStream(count)+Chr(10)+Str(StreamSize(count))+Chr(10)+Type+Chr(10)+folder + DirectoryEntryName(id))
            Next
            StreamCount = 0
          EndIf
          ; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #  
          If DirectoryEntryType(id) = #PB_DirectoryEntry_Directory 
            ParseDirectory(folder + DirectoryEntryName(id), id + 1) 
          EndIf  
        EndIf  
      Wend
    EndIf 
    FinishDirectory(id) 
  EndIf  
EndProcedure   

Procedure ParseCheminFichierouDossier(folder.s)
  Protected Type.s
 
  If FileSize(folder)=-2
      Type.s="Back"
  Else
      Type.s="File"
  EndIf
   
  If ReadStream(folder)
    For count = 0 To StreamCount 
      AddGadgetItem(#ListIcon_Stream, -1, NomStream(count)+Chr(10)+Str(StreamSize(count))+Chr(10)+Type+Chr(10)+folder)
    Next
    StreamCount = 0
  EndIf
  
  If Type="Back"
    ParseDirectory(folder)
  EndIf 
EndProcedure

Procedure DisableGadgetGroup1(Etat.l)
  DisableGadget(#Button_Dossier,Etat)
  DisableGadget(#Button_Fichier,Etat)
  DisableGadget(#Button_Scan,Etat)
  DisableGadget(#Button_Quitter,Etat)
EndProcedure

Procedure DisableGadgetGroup2(Etat.l)
  DisableGadget(#Button_SupprimerleStream,Etat)
  DisableGadget(#Button_EditeravecNotepad,Etat)
  DisableGadget(#Button_Extrairevers,Etat)
  DisableGadget(#Button_OuvrirExplorateur,Etat)
EndProcedure

Procedure Thread(lParam.i)
  ParseCheminFichierouDossier(Chemin$)
  StatusBarText(#BarreEtat, 0, "")
  FinRecherche=0
  DisableGadget(#Button_StopperScan,1)
  DisableGadgetGroup1(0)
EndProcedure

Procedure OpenWindow_Window_Main()
  If OpenWindow(#Window_Main, 200, 200, 610, 460, "Alternate Data Stream SPY", #PB_Window_SystemMenu|#PB_Window_TitleBar)
    StringGadget(#String_Dossier_Fichier, 10, 25, 520, 25, "", #PB_String_ReadOnly)
    ButtonGadget(#Button_Dossier, 540, 10, 60, 25, "Back")
    ButtonGadget(#Button_Fichier, 540, 40, 60, 25, "File")
    ListIconGadget(#ListIcon_Stream, 10, 110, 590, 250, "Name of Stream", 100, #PB_ListIcon_AlwaysShowSelection|#PB_ListIcon_FullRowSelect|#PB_ListIcon_GridLines)
    AddGadgetColumn(#ListIcon_Stream, 1, "Size", 60)
    AddGadgetColumn(#ListIcon_Stream, 2, "Type", 60)
    AddGadgetColumn(#ListIcon_Stream, 3, "Path", 360)
    ButtonGadget(#Button_Scan, 110, 70, 170, 25, "Scan Alternate Data Stream")
    ButtonGadget(#Button_StopperScan, 340, 70, 155, 25, "Stop the Scan")
    ButtonGadget(#Button_SupprimerleStream, 300, 370, 150, 25, "Remove Stream")
    ButtonGadget(#Button_EditeravecNotepad, 10, 370, 140, 25, "Edit with Notepad")
    ButtonGadget(#Button_Extrairevers, 150, 370, 150, 25, "Stream to extract the ...")
    ButtonGadget(#Button_Quitter, 240, 405, 130, 25, "Leave")
    TextGadget(#Text_Info, 10, 5, 520, 20, "You can drag and drop a File or Folder into the text box below")
    ButtonGadget(#Button_OuvrirExplorateur, 450, 370, 150, 25, "Open in Browser")
    
    CreateStatusBar(#BarreEtat, WindowID(#Window_Main))
    AddStatusBarField(#PB_Ignore)
    
    EnableGadgetDrop(#String_Dossier_Fichier, #PB_Drop_Files, #PB_Drag_Copy)
    
    DisableGadget(#Button_StopperScan,1)
    DisableGadgetGroup2(1)
  EndIf
EndProcedure

OpenWindow_Window_Main()

; {- Event loop
Repeat
  Select WaitWindowEvent()
      ; / / / / / / / / / / / / / / / / / / /
    Case #PB_Event_GadgetDrop
      Select EventGadget()
        Case #String_Dossier_Fichier
          Files$ = EventDropFiles()
          Count  = CountString(Files$, Chr(10)) + 1
          SetGadgetText(#String_Dossier_Fichier,StringField(Files$, 1, Chr(10)))
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Button_Dossier
          Chemin$ = PathRequester("Select a directory:", "C: \")
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #Button_Fichier
          Chemin$ = OpenFileRequester("Choose a file:", "C: \", "*. *",0)
          SetGadgetText(#String_Dossier_Fichier,Chemin$)
          
        Case #ListIcon_Stream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            DisableGadgetGroup2(0)
          Else
            DisableGadgetGroup2(1)
          EndIf 
          
        Case #Button_Scan
          ClearGadgetItems(#ListIcon_Stream)
          Chemin$=GetGadgetText(#String_Dossier_Fichier)
          If FileSize(Chemin$) <>-1
            DisableGadgetGroup1(1)
            DisableGadgetGroup2(1)
            DisableGadget(#Button_StopperScan,0)
            FinRecherche=1
            CreateThread(@Thread(),0)
          Else
            MessageRequester("Info","Choose a folder path or file valid!")
          EndIf 
          
        Case #Button_StopperScan
          FinRecherche=2
          DisableGadget(#Button_StopperScan,1)
          DisableGadgetGroup1(0)
          
        Case #Button_EditeravecNotepad
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            MessageRequester("Info","In some cases, Notepad will not be able to open the Stream!"+Chr(13)+"but you can always make an Extraction File and then edit the resulting File")
            RunProgram("Notepad.exe",CheminStream+":"+NameStream,"")
          EndIf 
          
        Case #Button_Extrairevers
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            Taille.s=GetGadgetItemText(#ListIcon_Stream, Index , 1)
            If Taille<>"0"
              NomFichier$ = SaveFileRequester("Choose a location:", NameStream, "*. *", 0)
              If NomFichier$<>""
                CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
                If ReadFile(0,CheminStream+":"+NameStream)
                  Longueur.q=Lof(0)
                  *Buffer=AllocateMemory(Longueur)
                  ReadData(0,*Buffer,Longueur)
                  CloseFile(0)
                  If CreateFile(0,NomFichier$)
                    WriteData(0,*Buffer,Longueur)
                    CloseFile(0)
                  EndIf
                  FreeMemory(*Buffer)
                Else
                  MessageRequester("Error","Stream could not be Save at!")
                EndIf
              EndIf
            Else
              MessageRequester("Info","Size of this Stream is 0 bytes, it is useless to save it!")
            EndIf
          EndIf
          
        Case #Button_SupprimerleStream
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            NameStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 0)
            NameStream=StringField(NameStream,2,":")
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            Type.s=GetGadgetItemText(#ListIcon_Stream, Index , 2)
            Message$="your you sure you want to delete the Stream"+NameStream+"?"+Chr(13)+"of"+Type+" "+CheminStream
            Resultat =MessageRequester("Attention",Message$, #PB_MessageRequester_YesNo)
            If Resultat = #PB_MessageRequester_Yes
              If DeleteFile(CheminStream+":"+NameStream)<>0
                RemoveGadgetItem(#ListIcon_Stream, Index)
              Else
                MessageRequester("Error","Stream could not be erased!")
              EndIf 
            EndIf 
          EndIf 
          
        Case #Button_OuvrirExplorateur
          Index.l=GetGadgetState(#ListIcon_Stream)
          If Index>-1
            CheminStream.s=GetGadgetItemText(#ListIcon_Stream, Index , 3)
            RunProgram("Explorer.exe","/ E, / select,"+CheminStream,"")
          EndIf  
          
        Case #Button_Quitter 
          CloseWindow(#Window_Main)
          Break
      EndSelect
      ; / / / / / / / / / / / / / / / / / / / / / / / /
    Case #PB_Event_CloseWindow
      Select EventWindow()
        Case #Window_Main
          If FinRecherche=0
            CloseWindow(#Window_Main)
            Break
          Else
            MessageRequester("Info","Click the button Stop Scan before leaving!")
          EndIf 
      EndSelect
  EndSelect
ForEver
;
; }

Re: Code to View NTFS Alternative Data Streams via streams.exe

Posted: Mon Apr 24, 2023 10:53 am
by Kwai chang caine
Thanks at you two for update this usefull code 8)