Search code examples
delphioperating-systemdelphi-xe2hidden-files

How to make files really hidden in a directory?


I downloaded a program yesterday, it is for encryption and security. I won't name it here unless someone asks me to but it has a feature to make files inside a specified folder completely invisible.

I have Hidden Files and Folders - Selected and also Hide protected operating system files - Unselected yet the files are gone completely from view and don't show up in a search either. I copied the folder over from VMware Workstation to my main machine and still the files are super hidden! There are zero files in the folder according to Windows.

How is this voodoo magick possible? I want to emulate this using Delphi in my own encryption program. I have not found any way on here and via Google that suggests how it is possible but the actual programs help file says they are still in the folder but do not register with most normal Windows software that process files.

This is one of those questions where I can not give any code to show what I have tried, but rather open to suggestions of what I can try or maybe someone here knows exactly how it is done?


Solution

  • Since less informa One possebility would be using alternative filestreams on NTFS, which can be added to files and folders. You can just try this by typing "notepad C:\temp:hidden1.txt" at the comandline, new filestream will be created if you aswer with yes. After saving you can reopen it exact the same way. This can also be done from delphi (loading/saving). Will only work if NTFS is used. I don't know if this method is used in described case, finding ADS can be done with following code:

    unit u_ListADS;
    
    // 20120928 by Thomas Wassermann
    // www.devworx.de
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, StrUtils;
    
     Procedure GetADS(List: TStrings; const Path, WildCard: String; Recursiv: Boolean = false);
    
    function NtQueryInformationFile(FileHandle: Cardinal; IoStatusBlock: Pointer; FileInformation: Pointer; FileInformationLength: Cardinal;
      FileInformationClass: Cardinal): Cardinal; stdcall; external 'ntdll.dll';
    
    implementation
    
    type
      _FILE_STREAM_INFORMATION = record
        NextEntryOffset: Cardinal;
        StreamNameLength: Cardinal;
        StreamSize: int64;
        StreamAllocationSize: int64;
        StreamName: array [0 .. MAX_PATH] of WideChar;
      end;
    
      PFILE_STREAM_INFORMATION = ^_FILE_STREAM_INFORMATION;
    
    function GetStreams(aFilename: String): TStringList;
    var
      FileHandle: Integer;
      FileName: array [0 .. MAX_PATH] of WideChar;
      StreamName: String;
      InfoBlock: _FILE_STREAM_INFORMATION;
      StatusBlock: record Status: Cardinal;
                          Information: PDWORD;
                   end;
    
      Procedure Analyze;
        begin
          CopyMemory(@FileName, @InfoBlock.StreamName, InfoBlock.StreamNameLength);
          StreamName := Copy(Filename, 1, PosEx(':', Filename, 2) - 1);
          if StreamName <> ':' then Result.Add(StreamName);
        end;
    begin
      Result := TStringList.Create;
      FileHandle := FileOpen(aFilename, GENERIC_READ);
      NtQueryInformationFile(FileHandle, @StatusBlock, @InfoBlock, SizeOf(InfoBlock), 22);
      FileClose(FileHandle);
      if InfoBlock.StreamNameLength <> 0 then
        Repeat
    
          if (InfoBlock.NextEntryOffset <> 0) then
            begin
            InfoBlock := PFILE_STREAM_INFORMATION(PByte(@InfoBlock) + InfoBlock.NextEntryOffset)^;
            Analyze;
            end;
        until InfoBlock.NextEntryOffset = 0
    end;
    
    Procedure GetADS(List: TStrings; const Path, WildCard: String; Recursiv: Boolean = false);
      Var
        SR: SysUtils.TSearchRec;
        RES: Integer;
        SP: String;
        StreamList: TStringList;
        i: Integer;
      begin
        if length(Path) = 0 then
          exit;
        if length(WildCard) = 0 then
          exit;
        SP := IncludeTrailingBackSlash(Path) + WildCard;
        RES := FindFirst(IncludeTrailingBackSlash(Path) + '*.*', faDirectory, SR);
        While RES = 0 Do
        Begin
          If (SR.attr And faDirectory) <> 0 Then
            If SR.Name[1] <> '.' Then
              if Recursiv then
                GetADS(List, IncludeTrailingBackSlash(Path) + SR.Name, WildCard, Recursiv);
          RES := FindNext(SR);
        End;
        SysUtils.FindClose(SR);
        RES := FindFirst(SP, $27, SR);
        While RES = 0 Do
        Begin
          StreamList := GetStreams(IncludeTrailingBackSlash(Path) + SR.Name);
          for i := 0 to StreamList.Count - 1 do
            List.Add(IncludeTrailingBackSlash(Path) + SR.Name + StreamList[i]);
          StreamList.Free;
          RES := FindNext(SR);
        End;
        SysUtils.FindClose(SR);
      end;
    
    end.
    

    Call could be e.g.

      GetADS(Listbox1.Items,Directory.Text, WildCards.Text,rekursiv.checked);