A. A. Its possible to hide data from both explorer and the dir command within an NTFS file that you cannot see unless you know its stream name. NTFS allows multiple streams to a file in the form of :, you can try it

  1. Start a console windows (cmd.exe)
  2. Run "notepad normal.txt" and enter some text and save. This has to be on an NTFS partition
  3. Now edit the file again but this time with a different stream "notepad normal.txt:hidden". You will be prompted to create a new file. Enter some text and save
  4. Perform a dir and you will see you still see only normal.txt with its original size.

You can have as many streams as you want. If you copy a file it keeps the streams, so copying normal.txt to john.txt, john.txt:hidden would exist. You cannot use streams from the command prompt as it does not allow : in files names except for drive letters.

Microsoft provide no way of detecting or deleting these streams. The two ways to delete are

  • Copy the file to a FAT partition and back again
  • - ren temp.exe
    - cat temp.exe >
    - del temp.exe

One application I have found to detect alternate data steams is by Frank Heyne and can be downloaded from http://www.heysoft.de/nt/ep-lads.htm.

Alternatively you can use Lizp which is downloadable from http://www.lizp.com. I have not used it in earnest, however what I have seen looks very good. An example use would be

Click here to view image

Its also possible to write a function to enumerate every altstream in every file matching c:\winnt\*. To do this, let's define a function, we'll call it las, and it'll take one argument, the wild path. Then we could type
(las 'c:\winnt\*)
and we'd get what we wanted.

Here's such a function definition:

(sequence
    (define
        (las Dir)
        (filter
            '(lambda
                (o)
                (cdr o) )
            (mapcar
                '(lambda
                    (FileInfo)
                    (if
                        (getfilesize
                            (car FileInfo) )
                        (cons
                            (car FileInfo)
                            (getaltstreams
                                (car FileInfo) ) )
                        (cons nil nil) ) )
                (dirlist Dir) ) ) )
    '(Enhanced with las) )

Even though you could type all this in at the prompt, on one long line, it's easier to save the code above to a file. Let's call the file las.lzp.

Now, from the Lizp prompt, you could type

(eval (load 'las.lzp))

and voila, you'll have a new function, las. Now try the thing above:

(las 'c:\winnt\*)

Suppose we think our Lizp should have this functionality always. Then type

(Compile (load 'las.lzp) 'Lizp_with_las.exe true)

and we'll have a new version of Lizp, called Lizp_with_las.exe.

Finally, suppose we wanted a GUI application which asked us for the wild path, and then displayed the alternate streams in a window. Save the following lines to a file, let's call it las_gui.lzp:

(local
    (Result)
    (setq Result
        (las
            (inputbox
                '((Wild path to check for Alt Streams)) ) ) )
    (messagebox
        (if Result Result
            '((No Alt Streams found in path.)) ) )
        (exit) )

Now, from Lizp_with_las' prompt, type

(Compile (load 'las_gui.lzp) 'Las.exe nil

and you'll have a new program, Las.exe, doing what we want. Note the last argument to the Compile function: the first time we compiled, we used "true", this last time we used "nil". This is because the first time we wanted the new program to create a console when run (because it was going to be our new Lizp interpreter). The second time we don't need a console.

Another way to delete these streams is to edit them in notepad and delete all the text. When you quit notepad NT tells you that the file is empty and will be deleted and you only have to confirm.

If you want to write your own programs to detect streams have a look at

Basically the only reliable way of handling streams is to use the BackupRead() function. The only "problem" is that BackupRead() requires SeRestorePrivilege/SeBackupPrivilege rights which most users will not have

BackupRead() actually does is to turn a file and its associated metadata (extended attributes, security data, alternate streams, links) into a stream of bytes. BackupWrite() converts it back.