zgrp
asked on
How to detect NTFS ADS files in C.
Hello,
I want a source code example with comments that explain how to detect if my partition is NTFS and if yes, how to scan the entire disc to search ADS (Alternate Data Stream) files.
ps: Good algorithms to make the disc search for ADS is welcome.
ps2: Is possible in C delete (not clean the content of the ADS) a NTFS file ?
Thank you.
Regards,
I want a source code example with comments that explain how to detect if my partition is NTFS and if yes, how to scan the entire disc to search ADS (Alternate Data Stream) files.
ps: Good algorithms to make the disc search for ADS is welcome.
ps2: Is possible in C delete (not clean the content of the ADS) a NTFS file ?
Thank you.
Regards,
Take a look at http://www.codeproject.com/csharp/CsADSDetectorArticle.asp
Checking for NTFS is quite easy, just call 'GetVolumeInformation()' for the volume in question.
To dump all the stream information in a file, use http://www.ntsecurity.net/Files/15/16189/Listing_01.txt
#define UNICODE
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <string>
using namespace std;
void DumpStreamId( BYTE* pBuf, DWORD read )
{
WIN32_STREAM_ID* pStreamId = ( WIN32_STREAM_ID* )pBuf;
// always check inputs
if( pStreamId == NULL )
{
assert( false );
return;
}
// there can be multiple streams in a read
// determining the offset is a little odd
// if the stream isn't named, then the size of the
// WIN32_STREAM_ID struct that precedes the data is
// actually sizeof( WIN32_STREAM_ID ) - sizeof( WCHAR* )
//
// this means that the number of bytes that a particular stream contains is:
// bytes = sizeof( WIN32_STREAM_ID ) + dwStreamNameSize
// - sizeof( WCHAR* ) + Size
// also note that Size is a large integer
while( (BYTE* )pStreamId - pBuf < read )
{
// print the name of the stream
// this is trickier than it looks - use a wstring to get around
// the fact that the name isn't null terminated
if( pStreamId->dwStreamNameSiz e > 0 )
{
wstring name;
// remember that dwStreamNameSize is in BYTEs,
// not characters
name.append( pStreamId->cStreamName,
pStreamId->dwStreamNameSiz e/sizeof( WCHAR ));
wprintf( L"Stream Name = %s\n", name.c_str( ) );
}
// convert the stream ID number to text
switch( pStreamId->dwStreamId )
{
case BACKUP_DATA:
wprintf( L"Standard data\n" );
break;
case BACKUP_EA_DATA:
wprintf( L"Extended attribute data\n" );
break;
case BACKUP_SECURITY_DATA:
wprintf( L"Security descriptor data\n" );
break;
case BACKUP_ALTERNATE_DATA:
wprintf( L"Alternative data stream\n" );
break;
case BACKUP_LINK:
wprintf( L"Hard link information\n" );
break;
case BACKUP_PROPERTY_DATA:
wprintf( L"Property data\n" );
break;
case BACKUP_OBJECT_ID:
wprintf( L"Objects identifiers\n" );
break;
case BACKUP_REPARSE_DATA:
wprintf( L"Reparse points\n" );
break;
case BACKUP_SPARSE_BLOCK:
wprintf( L"Sparse file\n" );
break;
default:
wprintf( L"Unknown stream ID %d\n", pStreamId->dwStreamId );
break;
}
// more than one flag could be set here - have to AND it
if( pStreamId->dwStreamAttribu tes & STREAM_MODIFIED_WHEN_READ )
wprintf( L"Stream modified when read\n" );
if( pStreamId->dwStreamAttribu tes & STREAM_CONTAINS_SECURITY )
wprintf( L"Stream contains security information\n" );
wprintf( L"Stream size: High DWORD = %d, Low DWORD = %d\n",
pStreamId->Size.HighPart, pStreamId->Size.LowPart );
//figure out where the next stream is -
if( pStreamId->Size.HighPart != 0 )
{
// this is a very big stream ( > 4GB ) - bail out
return;
}
pStreamId = ( WIN32_STREAM_ID * )( (BYTE* )pStreamId +
sizeof( WIN32_STREAM_ID ) - sizeof( WCHAR* ) +
pStreamId->dwStreamNameSiz e + // offset for name
pStreamId->Size.LowPart ); // offset for data
printf( "\n" );
}
}
bool EnableBackupRights( void )
{
HANDLE hToken;
TOKEN_PRIVILEGES token_priv;
//open current process to adjust privileges
if( !OpenProcessToken( GetCurrentProcess( ),
TOKEN_ADJUST_PRIVILEGES,
&hToken ))
{
printf( "Cannot open process token - err = %d\n", GetLastError( ) );
return false;
}
//let's build the token privilege struct -
//first, look up the LUID for the backup privilege
if( !LookupPrivilegeValue( NULL, //this system
SE_BACKUP_NAME, //the name of the privilege
&( token_priv.Privileges[0].L uid )) ) //result
{
printf( "Cannot lookup backup privilege - err = %d\n", GetLastError( ) );
return false;
}
token_priv.PrivilegeCount = 1;
token_priv.Privileges[0].A ttributes = SE_PRIVILEGE_ENABLED;
// now set the privilege
// because we're going to exit right after dumping the streams, there isn't
// any need to save current state
if( !AdjustTokenPrivileges( hToken, //our process token
false, //we're not disabling everything
&token_priv, //address of structure
sizeof( token_priv ), //size of structure
NULL, NULL )) //don't save current state
{
//this function is a little tricky - if we were adjusting
//more than one privilege, it could return success but not
//adjust them all - in the general case, you need to trap this
printf( "Could not enable backup privileges - err = %d\n", GetLastError( ) );
return false;
}
else
{
return true;
}
}
// this application reads a file and reports all data streams present
int wmain( int argc, WCHAR* argv[] )
{
HANDLE hFile;
// allocate enough space for the stream ID struct, plus
// enough to hold the name of the stream and some data
BYTE Buf[sizeof( WIN32_STREAM_ID ) + 1024];
DWORD bufsize = sizeof( Buf );
DWORD read;
void* context;
if( argc != 2 )
{
wprintf( L"Usage is %s [file name]\n", argv[0] );
wprintf( L"Note that this also works on directories\n" );
return -1;
}
// prints errors in function
if( !EnableBackupRights( ) )
return -1;
hFile = CreateFile( argv[1], // filename
GENERIC_READ, // access level
FILE_SHARE_READ, // share mode
NULL, // security attirubtes not needed
OPEN_EXISTING, // don't create a new file
FILE_FLAG_BACKUP_SEMANTICS ,
// if this flag isn't set we
// only read standard data
NULL ); // no template file
if( hFile == INVALID_HANDLE_VALUE )
{
wprintf( L"Cannot open %s - error = %d\n", argv[1], GetLastError( ) );
return -1;
}
// now it is time to read the streams
wprintf( L"Stream information on %s:\n", argv[1] );
// always initialize the context to NULL
context = NULL;
while( 1 )
{
if( !BackupRead( hFile, // file handle
Buf, // buffer to write the data
sizeof( Buf ), // size of the buffer
&read, // return value for bytes read
FALSE, // used to clear the data
// pointed to by context
TRUE, // back up the security descriptor
&context ))
{
wprintf( L"BackupRead failed - error = %d\n", GetLastError( ) );
break;
}
else
{
if( read == 0 )
{
//end of file condition
break;
}
//dump this stream buffer
DumpStreamId( Buf, read );
if( read == bufsize )
{
// now seek to the next stream
DWORD lowseek, highseek;
if( !BackupSeek( hFile,
~0,
~0,
&lowseek,
&highseek,
&context ))
{
DWORD err = GetLastError( );
if( err == ERROR_INVALID_HANDLE )
{
// end of file
break;
}
else if( err == ERROR_SEEK )
{
continue;
}
else
{
wprintf( L"Error seeking to end of stream err = %d\n",
err );
break;
}
}
}
}
}
// call this once more to clear the context structures
if( !BackupRead( hFile, // file handle
NULL, // buffer to write the data
0, // size of the buffer
&read, // return value for bytes read
TRUE, // used to clear the data
// pointed to by context
FALSE, // back up the security descriptor
&context ))
CloseHandle( hFile );
return 0;
}
To dump all the stream information in a file, use http://www.ntsecurity.net/Files/15/16189/Listing_01.txt
#define UNICODE
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <string>
using namespace std;
void DumpStreamId( BYTE* pBuf, DWORD read )
{
WIN32_STREAM_ID* pStreamId = ( WIN32_STREAM_ID* )pBuf;
// always check inputs
if( pStreamId == NULL )
{
assert( false );
return;
}
// there can be multiple streams in a read
// determining the offset is a little odd
// if the stream isn't named, then the size of the
// WIN32_STREAM_ID struct that precedes the data is
// actually sizeof( WIN32_STREAM_ID ) - sizeof( WCHAR* )
//
// this means that the number of bytes that a particular stream contains is:
// bytes = sizeof( WIN32_STREAM_ID ) + dwStreamNameSize
// - sizeof( WCHAR* ) + Size
// also note that Size is a large integer
while( (BYTE* )pStreamId - pBuf < read )
{
// print the name of the stream
// this is trickier than it looks - use a wstring to get around
// the fact that the name isn't null terminated
if( pStreamId->dwStreamNameSiz
{
wstring name;
// remember that dwStreamNameSize is in BYTEs,
// not characters
name.append( pStreamId->cStreamName,
pStreamId->dwStreamNameSiz
wprintf( L"Stream Name = %s\n", name.c_str( ) );
}
// convert the stream ID number to text
switch( pStreamId->dwStreamId )
{
case BACKUP_DATA:
wprintf( L"Standard data\n" );
break;
case BACKUP_EA_DATA:
wprintf( L"Extended attribute data\n" );
break;
case BACKUP_SECURITY_DATA:
wprintf( L"Security descriptor data\n" );
break;
case BACKUP_ALTERNATE_DATA:
wprintf( L"Alternative data stream\n" );
break;
case BACKUP_LINK:
wprintf( L"Hard link information\n" );
break;
case BACKUP_PROPERTY_DATA:
wprintf( L"Property data\n" );
break;
case BACKUP_OBJECT_ID:
wprintf( L"Objects identifiers\n" );
break;
case BACKUP_REPARSE_DATA:
wprintf( L"Reparse points\n" );
break;
case BACKUP_SPARSE_BLOCK:
wprintf( L"Sparse file\n" );
break;
default:
wprintf( L"Unknown stream ID %d\n", pStreamId->dwStreamId );
break;
}
// more than one flag could be set here - have to AND it
if( pStreamId->dwStreamAttribu
wprintf( L"Stream modified when read\n" );
if( pStreamId->dwStreamAttribu
wprintf( L"Stream contains security information\n" );
wprintf( L"Stream size: High DWORD = %d, Low DWORD = %d\n",
pStreamId->Size.HighPart, pStreamId->Size.LowPart );
//figure out where the next stream is -
if( pStreamId->Size.HighPart != 0 )
{
// this is a very big stream ( > 4GB ) - bail out
return;
}
pStreamId = ( WIN32_STREAM_ID * )( (BYTE* )pStreamId +
sizeof( WIN32_STREAM_ID ) - sizeof( WCHAR* ) +
pStreamId->dwStreamNameSiz
pStreamId->Size.LowPart ); // offset for data
printf( "\n" );
}
}
bool EnableBackupRights( void )
{
HANDLE hToken;
TOKEN_PRIVILEGES token_priv;
//open current process to adjust privileges
if( !OpenProcessToken( GetCurrentProcess( ),
TOKEN_ADJUST_PRIVILEGES,
&hToken ))
{
printf( "Cannot open process token - err = %d\n", GetLastError( ) );
return false;
}
//let's build the token privilege struct -
//first, look up the LUID for the backup privilege
if( !LookupPrivilegeValue( NULL, //this system
SE_BACKUP_NAME, //the name of the privilege
&( token_priv.Privileges[0].L
{
printf( "Cannot lookup backup privilege - err = %d\n", GetLastError( ) );
return false;
}
token_priv.PrivilegeCount = 1;
token_priv.Privileges[0].A
// now set the privilege
// because we're going to exit right after dumping the streams, there isn't
// any need to save current state
if( !AdjustTokenPrivileges( hToken, //our process token
false, //we're not disabling everything
&token_priv, //address of structure
sizeof( token_priv ), //size of structure
NULL, NULL )) //don't save current state
{
//this function is a little tricky - if we were adjusting
//more than one privilege, it could return success but not
//adjust them all - in the general case, you need to trap this
printf( "Could not enable backup privileges - err = %d\n", GetLastError( ) );
return false;
}
else
{
return true;
}
}
// this application reads a file and reports all data streams present
int wmain( int argc, WCHAR* argv[] )
{
HANDLE hFile;
// allocate enough space for the stream ID struct, plus
// enough to hold the name of the stream and some data
BYTE Buf[sizeof( WIN32_STREAM_ID ) + 1024];
DWORD bufsize = sizeof( Buf );
DWORD read;
void* context;
if( argc != 2 )
{
wprintf( L"Usage is %s [file name]\n", argv[0] );
wprintf( L"Note that this also works on directories\n" );
return -1;
}
// prints errors in function
if( !EnableBackupRights( ) )
return -1;
hFile = CreateFile( argv[1], // filename
GENERIC_READ, // access level
FILE_SHARE_READ, // share mode
NULL, // security attirubtes not needed
OPEN_EXISTING, // don't create a new file
FILE_FLAG_BACKUP_SEMANTICS
// if this flag isn't set we
// only read standard data
NULL ); // no template file
if( hFile == INVALID_HANDLE_VALUE )
{
wprintf( L"Cannot open %s - error = %d\n", argv[1], GetLastError( ) );
return -1;
}
// now it is time to read the streams
wprintf( L"Stream information on %s:\n", argv[1] );
// always initialize the context to NULL
context = NULL;
while( 1 )
{
if( !BackupRead( hFile, // file handle
Buf, // buffer to write the data
sizeof( Buf ), // size of the buffer
&read, // return value for bytes read
FALSE, // used to clear the data
// pointed to by context
TRUE, // back up the security descriptor
&context ))
{
wprintf( L"BackupRead failed - error = %d\n", GetLastError( ) );
break;
}
else
{
if( read == 0 )
{
//end of file condition
break;
}
//dump this stream buffer
DumpStreamId( Buf, read );
if( read == bufsize )
{
// now seek to the next stream
DWORD lowseek, highseek;
if( !BackupSeek( hFile,
~0,
~0,
&lowseek,
&highseek,
&context ))
{
DWORD err = GetLastError( );
if( err == ERROR_INVALID_HANDLE )
{
// end of file
break;
}
else if( err == ERROR_SEEK )
{
continue;
}
else
{
wprintf( L"Error seeking to end of stream err = %d\n",
err );
break;
}
}
}
}
}
// call this once more to clear the context structures
if( !BackupRead( hFile, // file handle
NULL, // buffer to write the data
0, // size of the buffer
&read, // return value for bytes read
TRUE, // used to clear the data
// pointed to by context
FALSE, // back up the security descriptor
&context ))
CloseHandle( hFile );
return 0;
}
ASKER
Hello,
Thank you for all assistence.
I found a intersting article explain how to code it too, that can be useful to understand the code sent from jkr.
http://www.codeproject.com/w2k/AlternateDataStream.asp
I will test it, if work I will PAQ the thread.
Thank you,
Regards,
Thank you for all assistence.
I found a intersting article explain how to code it too, that can be useful to understand the code sent from jkr.
http://www.codeproject.com/w2k/AlternateDataStream.asp
I will test it, if work I will PAQ the thread.
Thank you,
Regards,
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you, perfect it is what I were looking. ;)
Closing this thread. I also want to invite you specialists at my thread opened withput replys in the programming area.
- Suggestion about anti-reversing (https://www.experts-exchange.com/questions/21833007/Anti-reverse-engineering-Win.html). *Low priority*
- Get CD information in Java (https://www.experts-exchange.com/questions/21832998/Get-CDROM-metric-information-with-Java.html) *high priority*
- Example of a on access scanner using DDK (https://www.experts-exchange.com/questions/21832990/On-Access-Scanner-example-Kernel-Level-Win32.html) *high priority*
- Access registry and HardDrive in raw mode (open device and registry file and parse it) https://www.experts-exchange.com/questions/21833012/Dump-Registry-and-Files-in-low-level.html *Urgent priority*
Thank you.
Closing this thread. I also want to invite you specialists at my thread opened withput replys in the programming area.
- Suggestion about anti-reversing (https://www.experts-exchange.com/questions/21833007/Anti-reverse-engineering-Win.html). *Low priority*
- Get CD information in Java (https://www.experts-exchange.com/questions/21832998/Get-CDROM-metric-information-with-Java.html) *high priority*
- Example of a on access scanner using DDK (https://www.experts-exchange.com/questions/21832990/On-Access-Scanner-example-Kernel-Level-Win32.html) *high priority*
- Access registry and HardDrive in raw mode (open device and registry file and parse it) https://www.experts-exchange.com/questions/21833012/Dump-Registry-and-Files-in-low-level.html *Urgent priority*
Thank you.
ASKER