Alternate Data Streams verwijderen

Status
Niet open voor verdere reacties.

caveman

Meubilair
Lid geworden
18 aug 2001
Berichten
8.787
Is er een tool om ADS informatie te verwijderen?

Momenteel heb ik alleen een programma om te kijken of en welke ADS er zijn op een NTFS partitie, maar verwijderen lukt nog alleen door de bestanden naar een FAT partitie te verplaatsen en weer terug.
 
Nee, niet gezien. Ik ben bang dat dit ook nog lang op zich zal laten w88.:(

PS.Voor de mensen die denken: ADS? wtf is that?:confused: -->info.
 
Hmm, ik zal dit soort vragen ook maar niet meer stellen hier.
 
geloof niet dat het er is .. Maar snap niet helemaal waarom niet. Het zoeken naar ads informatie lijkt mij juist het moeilijkst. Voor het verwijderen kan je toch iets van:

c:\ads>type myfile.txt > myfile.bat

c:\ads>del myfile.txt

c:\ads>ren myfile.bat myfile.txt

snap niet dat dat dan niet in LADS zit of CrucialADS !!??

Je zou ook het programma kunnen uitbreiden om de files gewoon volautmatisch te kopieren naar een fat drive en weer terug. Maar zou even niet weten hoe ik moet zoeken naar ADS !!?? Aangezien het niet in windows geviewed kan worden, bestaat er vast geen API functies voor.

Ben eigenlijk heel benieuwd hoe ze dat doen !!??
 
hmmm, heb mezelf deze programmeertaal niet aangeleerd, maar misschien dat iemand het kan aanpassen:

Code:
//
// return code type
//
typedef INT NTSTATUS;

//
// Check for success
//
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

//
// The NT return codes we care about
//
#define STATUS_BUFFER_OVERFLOW           ((NTSTATUS)0x80000005L)

//--------------------------------------------------------------------
//     N T F S C O N T R O L F I L E   D E F I N I T I O N S
//--------------------------------------------------------------------

//
// Prototype for NtFsControlFile and data structures
// used in its definition
//

//
// Io Status block (see NTDDK.H)
//
typedef struct _IO_STATUS_BLOCK {
    NTSTATUS Status;
    ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;


//
// Apc Routine (see NTDDK.H)
//
typedef VOID (*PIO_APC_ROUTINE) (
				PVOID ApcContext,
				PIO_STATUS_BLOCK IoStatusBlock,
				ULONG Reserved
			);

//
// File information classes (see NTDDK.H)
//
typedef enum _FILE_INFORMATION_CLASS {
// end_wdm
    FileDirectoryInformation       = 1,
    FileFullDirectoryInformation, // 2
    FileBothDirectoryInformation, // 3
    FileBasicInformation,         // 4  wdm
    FileStandardInformation,      // 5  wdm
    FileInternalInformation,      // 6
    FileEaInformation,            // 7
    FileAccessInformation,        // 8
    FileNameInformation,          // 9
    FileRenameInformation,        // 10
    FileLinkInformation,          // 11
    FileNamesInformation,         // 12
    FileDispositionInformation,   // 13
    FilePositionInformation,      // 14 wdm
    FileFullEaInformation,        // 15
    FileModeInformation,          // 16
    FileAlignmentInformation,     // 17
    FileAllInformation,           // 18
    FileAllocationInformation,    // 19
    FileEndOfFileInformation,     // 20 wdm
    FileAlternateNameInformation, // 21
    FileStreamInformation,        // 22
    FilePipeInformation,          // 23
    FilePipeLocalInformation,     // 24
    FilePipeRemoteInformation,    // 25
    FileMailslotQueryInformation, // 26
    FileMailslotSetInformation,   // 27
    FileCompressionInformation,   // 28
    FileObjectIdInformation,      // 29
    FileCompletionInformation,    // 30
    FileMoveClusterInformation,   // 31
    FileQuotaInformation,         // 32
    FileReparsePointInformation,  // 33
    FileNetworkOpenInformation,   // 34
    FileAttributeTagInformation,  // 35
    FileTrackingInformation,      // 36
    FileMaximumInformation
// begin_wdm
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;


//
// Streams information
//
#pragma pack(4)
typedef struct {
	ULONG    	        NextEntry;
	ULONG    	        NameLength;
	LARGE_INTEGER    	Size;
	LARGE_INTEGER    	AllocationSize;
	USHORT    	        Name[1];
} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
#pragma pack()

en

Code:
#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 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 )
{
    PFILE_STREAM_INFORMATION  streamInfo, streamInfoPtr;
    ULONG    streamInfoSize = 0;
    BOOLEAN  printedFile = FALSE;
    NTSTATUS status;
    HANDLE   fileHandle;
    WCHAR    streamName[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"\rFailed to open %s: ", 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;
                }
                wprintf(L"   %20s\t%I64d\n", streamName, streamInfoPtr->Size.QuadPart );
            }

            if( !streamInfoPtr->NextEntry ) break;

            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 )
{
	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( 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( 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));
			}
		} 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 );

			}
		} while( FindNextFile( dirHandle, &foundFile ));
	}

	FindClose( dirHandle );
}


int Usage( WCHAR *ProgramName ) 
{
    wprintf(L"usage: %s [-s] <file or directory>\n", ProgramName );
    wprintf(L"-s     Recurse subdirectories\n\n");
    return -1;
}


int wmain( int argc, WCHAR *argv[] ) 
{
    BOOLEAN    recurse;
    WCHAR       *name;
    PWCHAR      filePart;
    WCHAR       searchPattern[MAX_PATH];
	WCHAR		searchPath[MAX_PATH];

    //
    // Print banner and perform parameter check
    //
    wprintf(L"\nStreams v1.3 - Enumerate alternate NTFS data streams\n" );
    wprintf(L"Copyright (C) 1999-2001 Mark Russinovich\n");
    wprintf(L"Sysinternals - [url]www.sysinternals.com\n\n[/url]");

    if( argc != 2 && argc !=3 ) {

        return Usage( argv[0] );
    }

    if( argc == 3 && 
        wcsicmp( argv[1], L"/s" ) &&
        wcsicmp( argv[1], L"-s" )) {

        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);
	}
    
    //
    // Read the name argument
    //
    if( argc == 3 ) {
        
        name = argv[2];
        recurse = TRUE;

    } else {

        name = argv[1];
        recurse = FALSE;
    }

    //
    // Now go and process directories
    //
	GetFullPathName( argv[argc-1], MAX_PATH, searchPath, &filePart );
    ProcessDirectory( searchPath, searchPattern, recurse );
    return 0;
}
 
Laatst bewerkt:
heb hier geen ntfs bestandssysteem om zelf ff te proberen, maar mag je niet gewoon

del file:stream

doen om alleen de ads los te koppelen van de file? 'del' en 'erase' zijn tenslotte net zo goed shell-commands voor bestandsverwijdering als bijvoorbeeld 'echo' voor het koppelen van een binair bestand, en een stream ís hier een bestand
 
Laatst bewerkt:
heb nu ook even geen ntfs. Dus kan het pas dinsdag ofzo proberen ..

maar dat staat niet gedocumenteerd ergens, alleen:

c:\ads>type myfile.txt > myfile.bat

c:\ads>del myfile.txt

c:\ads>ren myfile.bat myfile.txt

waarom zouden ze zo moeilijk doen dan ????

Maar zou je dat in de code kunnen plaatsen. Ken veel statements in die code niet namelijk !!??
 
nee het stuk code wat jij noemt is een c-programma.

wil dat best eens op m'n gemak bekijken, maar 't is nu alweer half 5 :confused: . bovendien heb ik helaas geen tijd en testmogelijkheden om zelf een prog te schrijven om ads binnen ntfs aan te passen (geen ntfs-systeem hier).

dit:

c:\ads>type myfile.txt > myfile.bat

c:\ads>del myfile.txt

c:\ads>ren myfile.bat myfile.txt

zijn opdrachten aan de ms-dos commandline. dit zal zeker werken om de ads-info weg te krijgen uit een tekstfile en lijkt me al eleganter dan heen-en-weer kopieren naar en van een ander bestandssysteem zoals fat. zal ze hieronder ff uitleggen. let erop dat deze bewerking voor een niet-tekstfile net even iets anders in z'n werk gaat.

even voor de duidelijkheid:
ads is dus in ntfs net zo goed als system, hidden, archive, readonly en subdirectory een attribuut bij een bestand. verschil is dat ads een hele stream is van bytes. de andere attributen zijn maar één byte en staan met z'n allen in een tabel vlak achter de bootsector. die bytesstream zullen in veel gevallen een bestand representeren. het beste voorbeeld is de bijlage bij een e-mailtje. de stream wordt fysiek gekoppeld aan het bestand. bij opdrachten als 'dir' zul je alleen de grootte van het bestand zelf zien, ongeacht de grootte van het ads.

de bovenste van de 3 opdrachten:

* type myfile.txt > myfile.bat

is een omleiding die feitelijk de ads-attributen verwijdert. het bestand myfile.txt wordt gekopieerd in een bestand dat eerst met deze zelfde opdracht nieuw wordt aangemaakt: myfile.bat.
stond er

type myfile.txt > myfile.bat:readme.txt

dan zouden alle bytes uit het bestand readme.txt achter myfile.bat worden 'geplakt' als ads-info. je zou de losse stream dan alleen kunnen lezen en bewerken door een opdracht als

notepad myfile.bat:readme.txt

te gebruiken, terwijl daarna

notepad myfile.bat

de tekst van myfile.bat zelf onveranderd zou laten zien. in onze opdracht staat er niks achter myfile.bat, dus wordt de ads van myfile.bat ook leeggelaten. de ads van myfile.txt blijft ongewijzigd. we hebben dus het oude bestand myfile.txt, maar nu zónder ads.

alleen heet ie nu myfile.bat en we willen 'm terughebben naar myfile.txt. dus verwijderen we eerst het originele bestand myfile.txt met

* del myfile.txt

zodat het oude bestand mét ads-info vernietigd wordt. nu kunnen we ons nieuwe bestand zónder ads de originele naam teruggeven met

* ren myfile.bat myfile.txt

de pagina die caveman noemt geeft een soortgelijke manier van verwijdering
 
ok, maar caveman is op zoek naar een tool. Je kan makkelijk een tool schrijven waar je alleen de path naar het bestand ingeeft en dat dan de ads van dat bestand verwijdert word, maar goed weet niet of caveman daar dan weer tevreden mee is.
Hij zal wel willen zoeken naar ads en dan een bestand selecteren en de ads verwijderen (lui hoor :) )
 
een goed idee om gauw verder te kunnen luieren is een batchbestand onder de shell!
 
denk dat ik caveman wat te bieden heb in visual basic, maar heb morgen een machine learning tentamen ! Dus moet me nu echt bezig gaan houden met genetische algoritmen, artificial neural networks, naive bayes classifier en meer van die god*** dingen, die een mens direct in slaap wiegen .....
 
Way over my head maar wat is het nut van het verwijderen van deze data? Privacy?
 
Geplaatst door @temptation
Way over my head maar wat is het nut van het verwijderen van deze data? Privacy?

je kan aan elke file een ads stream koppelen. Je kan deze informatie dus niet zien in windows verkenner. We hebben het hier gehad over txt files, maar je kan er ook exe file's aan koppelen.

Je kan dus makkelijk via een dos command of API call explorer.exe:Trojan.exe starten zonder ook maar explorer daadwerkelijk te runnen. vroeger zag je in de taakbalk van windows zelfs alleen explorer.exe staan. Nu is dat inmiddels opgelost.

Maar goed, bottom-line is dat je dus een trojan of virus op je computer kan hebben zonder dat je ze kan zien ... Lijkt mij vrij ernstig ...

Maar heb denk ik nog wel een oplossing, maar even geduld. Heb weinig tijd nu ...
 
Ik ben er inmiddels uit. Er is een command line tooltje voor zodat het niet nodig is per bestand de ADS te verwijderen. De link geef ik nog wel (vergeten de site in de bookmarks te zetten...).

@temptation> wat Vaat zegt, maar voor mij was de reden dat ik Inoculate een tijdje heb aangekeken en deze ADS informatie aan bestanden kan toevoegen om deze de status 'veilig' mee te geven. Erg handig, maar als je de scanner deïnstalleerd heb je nog wel de ADS informatie in de bestanden zitten en daar was ik niet zo blij mee.
 
Geplaatst door caveman
Ik ben er inmiddels uit. Er is een command line tooltje voor zodat het niet nodig is per bestand de ADS te verwijderen. De link geef ik nog wel (vergeten de site in de bookmarks te zetten...).


hmmm, misschien ga ik er toch nog even mee aan de slag in het weekend. Tenzij dat tooltje enorm handig werkt, want dan heeft het geen zin ......
 
tja,

heb het niet getest allemaal, maar het doet zijn werk wel volgens mij. Jammer dat het niet allemaal in 1 progie zit ......

Maar goed, jou probleem is weer opgelost. Wel zelf gedaan, maar heb liever wel dat je ze op helpmij post. Wekt mijn nieuwsgierig ook weer namelijk.

Doe het maar voor mij dan .. :)
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan