Code to View NTFS Alternative Data Streams via streams.exe

Share your advanced PureBasic knowledge/code with the community.
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 796
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Code to View NTFS Alternative Data Streams via streams.exe

Post 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
Last edited by Zebuddi123 on Mon Jan 14, 2013 7:11 pm, edited 3 times in total.
malleo, caput, bang. Ego, comprehendunt in tempore
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

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

Post 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?
Anthony Jordan
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 796
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

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

Post 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
malleo, caput, bang. Ego, comprehendunt in tempore
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

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

Post by blueznl »

( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Nico
Enthusiast
Enthusiast
Posts: 274
Joined: Sun Jan 11, 2004 11:34 am
Location: France

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

Post 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
;
;}

User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 796
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

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

Post 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
;
; }
malleo, caput, bang. Ego, comprehendunt in tempore
User avatar
electrochrisso
Addict
Addict
Posts: 989
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

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

Post 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)
PureBasic! Purely the best 8)
Nico
Enthusiast
Enthusiast
Posts: 274
Joined: Sun Jan 11, 2004 11:34 am
Location: France

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

Post by Nico »

@Zebuddi123

Good job :D
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

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

Post by jassing »

Nico: nice job, but here, I have files with multiple ads, code only lists 1st one. Haven't yet figured out why...
kvitaliy
Enthusiast
Enthusiast
Posts: 162
Joined: Mon May 10, 2010 4:02 pm

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

Post by kvitaliy »

Very nice :!:
Nico
Enthusiast
Enthusiast
Posts: 274
Joined: Sun Jan 11, 2004 11:34 am
Location: France

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

Post 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
;
;}

jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

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

Post by jassing »

nice!
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

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

Post 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
   ==     ===     ===     ==     |     ==     ===     ==    |     ==     ===     =      |    ===     ===     ===

User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

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

Post 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
;
; }
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

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

Post by Kwai chang caine »

Thanks at you two for update this usefull code 8)
ImageThe happiness is a road...
Not a destination
Post Reply