home *** CD-ROM | disk | FTP | other *** search
- #define UNICODE 1
- #include <windows.h>
- #include <stdio.h>
- #include "streams.h"
-
-
- //
- // Native functions we use
- //
- NTSTATUS (__stdcall *NtQueryInformationFile)(
- IN HANDLE FileHandle,
- OUT PIO_STATUS_BLOCK IoStatusBlock,
- OUT PVOID FileInformation,
- IN ULONG Length,
- IN FILE_INFORMATION_CLASS FileInformationClass
- );
-
- ULONG (__stdcall *RtlNtStatusToDosError) (
- IN NTSTATUS Status
- );
-
- //
- // Globals
- //
- ULONG FilesWithStreams = 0;
- ULONG FilesProcessed = 0;
- ULONG DotsPrinted = 0;
- BOOLEAN PrintDirectoryOpenErrors = FALSE;
-
- //----------------------------------------------------------------------
- //
- // PrintNtError
- //
- // Formats an error message for the last native error.
- //
- //----------------------------------------------------------------------
- void PrintNtError( NTSTATUS status )
- {
- WCHAR *errMsg;
-
- FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, RtlNtStatusToDosError( status ),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &errMsg, 0, NULL );
- wprintf(L"%s\n", errMsg );
- LocalFree( errMsg );
- }
-
- //--------------------------------------------------------------------
- //
- // PrintWin32Error
- //
- // Translates a Win32 error into a text equivalent
- //
- //--------------------------------------------------------------------
- void PrintWin32Error( DWORD ErrorCode )
- {
- LPVOID lpMsgBuf;
-
- FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, ErrorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf, 0, NULL );
- wprintf(L"%s\n", lpMsgBuf );
- LocalFree( lpMsgBuf );
- }
-
- //----------------------------------------------------------------------
- //
- // EnableTokenPrivilege
- //
- // Enables the load driver privilege
- //
- //----------------------------------------------------------------------
- BOOL EnableTokenPrivilege( PTCHAR PrivilegeName )
- {
- TOKEN_PRIVILEGES tp;
- LUID luid;
- HANDLE hToken;
- TOKEN_PRIVILEGES tpPrevious;
- DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
-
- //
- // Get debug privilege
- //
- if(!OpenProcessToken( GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
- &hToken )) {
-
- return FALSE;
- }
-
- if(!LookupPrivilegeValue( NULL, PrivilegeName, &luid )) return FALSE;
-
- //
- // first pass. get current privilege setting
- //
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Luid = luid;
- tp.Privileges[0].Attributes = 0;
-
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tp,
- sizeof(TOKEN_PRIVILEGES),
- &tpPrevious,
- &cbPrevious
- );
-
- if (GetLastError() != ERROR_SUCCESS) return FALSE;
-
- //
- // second pass. set privilege based on previous setting
- //
- tpPrevious.PrivilegeCount = 1;
- tpPrevious.Privileges[0].Luid = luid;
- tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
- AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tpPrevious,
- cbPrevious,
- NULL,
- NULL
- );
-
- return GetLastError() == ERROR_SUCCESS;
- }
-
-
- //--------------------------------------------------------------------
- //
- // ProcessFile
- //
- // Queries a file to obtain stream information.
- //
- //--------------------------------------------------------------------
- VOID ProcessFile( WCHAR *FileName, BOOLEAN IsDirectory, BOOLEAN Delete )
- {
- PFILE_STREAM_INFORMATION streamInfo, streamInfoPtr;
- ULONG streamInfoSize = 0;
- BOOLEAN printedFile = FALSE;
- NTSTATUS status;
- HANDLE fileHandle;
- WCHAR streamName[MAX_PATH];
- WCHAR fullStreamName[MAX_PATH];
- IO_STATUS_BLOCK ioStatus;
-
- //
- // Open the file
- //
- fileHandle = CreateFile( FileName, GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, 0 );
- if( fileHandle == INVALID_HANDLE_VALUE ) {
-
- if( !IsDirectory || PrintDirectoryOpenErrors ) {
-
- wprintf(L"\rError opening %s:\n", FileName );
- PrintWin32Error( GetLastError() );
- }
- return;
- }
-
- if( !(++FilesProcessed % 500)) {
-
- if( DotsPrinted == 3 ) {
-
- wprintf(L"\r \r");
- DotsPrinted = 0;
-
- } else {
- DotsPrinted++;
- wprintf(L".");
- }
- fflush( stdout );
- }
-
- streamInfoSize = 16384;
- streamInfo = malloc( streamInfoSize );
- status = STATUS_BUFFER_OVERFLOW;
- while( status == STATUS_BUFFER_OVERFLOW ) {
-
- status = NtQueryInformationFile( fileHandle, &ioStatus,
- streamInfo, streamInfoSize,
- FileStreamInformation );
- if( status == STATUS_BUFFER_OVERFLOW ) {
-
- free( streamInfo );
- streamInfoSize += 16384;
- streamInfo = malloc( streamInfoSize );
-
- } else {
-
- break;
- }
- }
-
- //
- // If success, dump the contents
- //
- if( NT_SUCCESS( status ) && ioStatus.Information ) {
-
- streamInfoPtr = streamInfo;
- while( 1 ) {
-
- memcpy( streamName,
- streamInfoPtr->Name,
- streamInfoPtr->NameLength );
- streamName[ streamInfoPtr->NameLength/2 ] = 0;
-
- //
- // Skip the standard Data stream
- //
- if( wcsicmp( streamName, L"::$DATA" )) {
-
- if( !printedFile ) {
- wprintf(L"\r%s:\n", FileName );
- printedFile = TRUE;
- }
-
- if( Delete ) {
-
- swprintf( fullStreamName, L"%s%s", FileName, streamName );
- if( !DeleteFile( fullStreamName )) {
-
- wprintf(L" Error deleting %s:\n", streamName );
- PrintWin32Error( GetLastError());
- } else {
-
- wprintf(L" Deleted %s\n", streamName );
- }
- } else {
-
- wprintf(L" %20s\t%I64d\n", streamName, streamInfoPtr->Size.QuadPart );
- }
- }
-
- if( !streamInfoPtr->NextEntry ) break;
-
- FilesWithStreams++;
- streamInfoPtr = (PFILE_STREAM_INFORMATION) ((char *) streamInfoPtr +
- streamInfoPtr->NextEntry );
- }
-
- } else if( !NT_SUCCESS( status )) {
-
- wprintf(L"\rError on %s: ", FileName );
- PrintNtError( status );
- }
- free( streamInfo );
- CloseHandle( fileHandle );
- }
-
-
-
- //--------------------------------------------------------------------
- //
- // ProcessDirectory
- //
- // Recursive routine that passes files to the stream analyzing
- // function.
- //
- //--------------------------------------------------------------------
- void ProcessDirectory( WCHAR *PathName, WCHAR *SearchPattern,
- BOOLEAN Recurse, BOOLEAN Delete )
- {
- WCHAR subName[MAX_PATH], fileSearchName[MAX_PATH], searchName[MAX_PATH];
- HANDLE dirHandle, patternHandle;
- static BOOLEAN firstCall = TRUE;
- WIN32_FIND_DATA foundFile;
-
- //
- // Scan the files and/or directories if this is a directory
- //
- if( firstCall ) {
-
- if( PathName[ wcslen( PathName ) - 1] == L'\\' ) {
-
- PathName[ wcslen( PathName ) - 1] = 0;
- }
-
- if( wcsrchr( PathName, '*' ) ) {
-
- if( wcsrchr( PathName, '\\' ) ) {
-
- swprintf( SearchPattern, wcsrchr( PathName, '\\' )+1 );
- wcscpy( searchName, PathName );
- wcscpy( wcsrchr( searchName, '\\')+1, L"*.*" );
-
- } else {
-
- swprintf( SearchPattern, PathName );
- wcscpy( searchName, PathName );
- }
- swprintf( fileSearchName, L"%s", PathName );
-
- } else {
-
- swprintf( SearchPattern, L"*.*" );
- if( Recurse ) {
-
- swprintf( searchName, L"%s\\*.*", PathName );
- swprintf( fileSearchName, L"%s\\*.*", PathName );
- } else {
-
- swprintf( searchName, L"%s", PathName );
- swprintf( fileSearchName, L"%s", PathName );
- }
- }
-
- } else {
-
- swprintf( searchName, L"%s\\*.*", PathName );
- swprintf( fileSearchName, L"%s\\%s", PathName, SearchPattern );
- }
-
- //
- // Process all the files, according to the search pattern
- //
- if( (patternHandle = FindFirstFile( fileSearchName, &foundFile )) !=
- INVALID_HANDLE_VALUE ) {
-
- do {
-
- if( firstCall || (wcscmp( foundFile.cFileName, L"." ) &&
- wcscmp( foundFile.cFileName, L".." ))) {
-
- wcscpy( subName, searchName );
- if( wcsrchr( subName, '\\' ) )
- wcscpy( wcsrchr( subName, '\\')+1, foundFile.cFileName );
- else
- wcscpy( subName, foundFile.cFileName );
-
- //
- // Do this file/directory
- //
- ProcessFile( subName,
- (BOOLEAN) (foundFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY),
- Delete );
- }
- } while( FindNextFile( patternHandle, &foundFile ));
- FindClose( patternHandle );
- }
-
- //
- // Now recurse if we're supposed to
- //
- if( Recurse ) {
-
- if( firstCall && !wcsrchr( searchName, L'\\') ) {
-
- if( wcsrchr( searchName, L'*' )) {
-
- if( (dirHandle = FindFirstFile( L"*.*", &foundFile )) ==
- INVALID_HANDLE_VALUE ) {
-
- //
- // Nothing to process
- //
- return;
- }
- } else {
-
- if( (dirHandle = FindFirstFile( searchName, &foundFile )) ==
- INVALID_HANDLE_VALUE ) {
-
- //
- // Nothing to process
- //
- return;
- }
- }
- } else {
-
- if( (dirHandle = FindFirstFile( searchName, &foundFile )) ==
- INVALID_HANDLE_VALUE ) {
-
- //
- // Nothing to process
- //
- return;
- }
- }
- firstCall = FALSE;
-
- do {
-
- if( (foundFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
- wcscmp( foundFile.cFileName, L"." ) &&
- wcscmp( foundFile.cFileName, L".." )) {
-
- wcscpy( subName, searchName );
- if( wcsrchr( subName, '\\' ) )
- wcscpy( wcsrchr( subName, '\\')+1, foundFile.cFileName );
- else
- wcscpy( subName, foundFile.cFileName );
-
- //
- // Go into this directory
- //
- ProcessDirectory( subName, SearchPattern, Recurse, Delete );
-
- }
- } while( FindNextFile( dirHandle, &foundFile ));
- }
-
- FindClose( dirHandle );
- }
-
-
- int Usage( WCHAR *ProgramName )
- {
- wprintf(L"usage: %s [-s] [-d] <file or directory>\n", ProgramName );
- wprintf(L"-s Recurse subdirectories\n");
- wprintf(L"-d Delete streams\n\n");
- return -1;
- }
-
-
- int wmain( int argc, WCHAR *argv[] )
- {
- BOOLEAN recurse = FALSE, delete = FALSE;
- PWCHAR filePart;
- WCHAR volume[] = L"C:\\";
- DWORD fsFlags;
- WCHAR searchPattern[MAX_PATH];
- WCHAR searchPath[MAX_PATH];
- int i;
-
- //
- // Print banner and perform parameter check
- //
- wprintf(L"\nStreams v1.53 - Enumerate alternate NTFS data streams\n" );
- wprintf(L"Copyright (C) 1999-2005 Mark Russinovich\n");
- wprintf(L"Sysinternals - www.sysinternals.com\n\n");
-
- if( argc > 1 ) {
-
- for( i = 1; i < argc; i++ ) {
-
- if( argv[i][0] != L'/' && argv[i][0] != L'-' ) {
-
- if( i != argc-1 ) {
-
- wprintf( argv[i] );
- return Usage( argv[0] );
- }
- continue;
- }
-
- if( argv[i][1] == L's' || argv[i][1] == L'S' ) {
-
- recurse = TRUE;
-
- } else if( argv[i][1] == L'd' || argv[i][1] == 'D' ) {
-
- delete = TRUE;
-
- } else return Usage( argv[0] );
- }
- } else {
-
- return Usage( argv[0] );
- }
-
- //
- // Enable backup privilege if we can
- //
- if( EnableTokenPrivilege( SE_BACKUP_NAME )) {
-
- PrintDirectoryOpenErrors = TRUE;
- }
-
- //
- // Load the NTDLL entry point we need
- //
- if( !(NtQueryInformationFile = (void *) GetProcAddress( GetModuleHandle(L"ntdll.dll"),
- "NtQueryInformationFile" )) ) {
-
- wprintf(L"\nCould not find NtQueryInformationFile entry point in NTDLL.DLL\n");
- exit(1);
- }
- if( !(RtlNtStatusToDosError = (void *) GetProcAddress( GetModuleHandle(L"ntdll.dll"),
- "RtlNtStatusToDosError" )) ) {
-
- wprintf(L"\nCould not find RtlNtStatusToDosError entry point in NTDLL.DLL\n");
- exit(1);
- }
- GetFullPathName( argv[argc-1], MAX_PATH, searchPath, &filePart );
-
- //
- // Make sure that its a FAT volume
- //
- if( searchPath[1] == L':' ) {
-
- fsFlags = 0;
- volume[0] = searchPath[0];
- GetVolumeInformation( volume, NULL, 0, NULL, NULL, &fsFlags, NULL, 0 );
- if( !(fsFlags & FILE_NAMED_STREAMS )) {
-
- wprintf(L"\nThe specified volume does not support streams.\n\n");
- exit(2);
- }
- }
-
- //
- // Now go and process directories
- //
- ProcessDirectory( searchPath, searchPattern, recurse, delete );
-
- if( !FilesWithStreams ) wprintf(L"No files with streams found.\n\n");
- return 0;
- }
-