Thread: C++ ADS Viewer Code

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    3

    C++ ADS Viewer Code

    First things first, i'm not a programmer as such, i have dabbled in the past, i work in security and have recently been researching into how an Alternate Data Stream viewer can be programmed.

    I am interested in c++ and found the following source for an exe to view ADS's.

    However i get numerous errors when i attempt to compile it in DEV C++ including:

    " precomp.h: No such file or directory "
    " Entry was not declared in this scope "
    "HANDLE was not declared in this scope "


    Does anyone know what i must do to get it working? what libraries etc to include?

    Any help greatly appreciated, thanks, i intend to start learning c++ properly (i've dabbled before) very shortly.

    Code:
    #include <precomp.h>
    
    #ifndef _NO_WIN_FS
    
    //#include "winfs.h"
    
    
    int ScanNTFSStreams(Entry* entry, HANDLE hFile)
    {
    	PVOID ctx = 0;
    	DWORD read, seek_high;
    	Entry** pnext = &entry->_down;
    	int cnt = 0;
    
    	for(;;) {
    		struct NTFS_StreamHdr : public WIN32_STREAM_ID {
    			WCHAR name_padding[_MAX_FNAME];	// room for reading stream name
    		} hdr;
    
    		if (!BackupRead(hFile, (LPBYTE)&hdr, (LPBYTE)&hdr.cStreamName-(LPBYTE)&hdr, &read, FALSE, FALSE, &ctx) ||
    			(long)read!=(LPBYTE)&hdr.cStreamName-(LPBYTE)&hdr)
    			break;
    
    		if (hdr.dwStreamId == BACKUP_ALTERNATE_DATA) {
    			if (hdr.dwStreamNameSize &&
    				BackupRead(hFile, (LPBYTE)hdr.cStreamName, hdr.dwStreamNameSize, &read, FALSE, FALSE, &ctx) &&
    				read==hdr.dwStreamNameSize)
    			{
    				++cnt;
    
    				int l = hdr.dwStreamNameSize / sizeof(WCHAR);
    				LPCWSTR p = hdr.cStreamName;
    				LPCWSTR e = hdr.cStreamName + l;
    
    				if (l>0 && *p==':') {
    					++p, --l;
    
    					e = p;
    
    					while(l>0 && *e!=':')
    						++e, --l;
    
    					l = e - p;
    				}
    
    				Entry* stream_entry = new WinEntry(entry);
    
    				memcpy(&stream_entry->_data, &entry->_data, sizeof(WIN32_FIND_DATA));
    				lstrcpy(stream_entry->_data.cFileName, String(p, l));
    
    				stream_entry->_down = NULL;
    				stream_entry->_expanded = false;
    				stream_entry->_scanned = false;
    				stream_entry->_level = entry->_level + 1;
    
    				*pnext = stream_entry;
    				pnext = &stream_entry->_next;
    			}
    		}
    
    		 // jump to the next stream header
    		if (!BackupSeek(hFile, ~0, ~0, &read, &seek_high, &ctx)) {
    			DWORD error = GetLastError();
    
    			if (error != ERROR_SEEK) {
    				BackupRead(hFile, 0, 0, &read, TRUE, FALSE, &ctx);	// terminate BackupRead() loop
    				THROW_EXCEPTION(error);
    				//break;
    			}
    
    			hdr.Size.QuadPart -= read;
    			hdr.Size.HighPart -= seek_high;
    
    			BYTE buffer[4096];
    
    			while(hdr.Size.QuadPart > 0) {
    				if (!BackupRead(hFile, buffer, sizeof(buffer), &read, FALSE, FALSE, &ctx) || read!=sizeof(buffer))
    					break;
    
    				hdr.Size.QuadPart -= read;
    			}
    		}
    	}
    
    	if (ctx)
    		if (!BackupRead(hFile, 0, 0, &read, TRUE, FALSE, &ctx))	// terminate BackupRead() loop
    			THROW_EXCEPTION(GetLastError());
    
    	return cnt;
    }
    
    
    void WinDirectory::read_directory(int scan_flags)
    {
    	CONTEXT("WinDirectory::read_directory()");
    
    	int level = _level + 1;
    
    	Entry* first_entry = NULL;
    	Entry* last = NULL;
    	Entry* entry;
    
    	LPCTSTR path = (LPCTSTR)_path;
    	TCHAR buffer[MAX_PATH], *pname;
    	for(pname=buffer; *path; )
    		*pname++ = *path++;
    
    	lstrcpy(pname, TEXT("\\*"));
    
    	WIN32_FIND_DATA w32fd;
    	HANDLE hFind = FindFirstFile(buffer, &w32fd);
    
    	if (hFind != INVALID_HANDLE_VALUE) {
    		do {
    			lstrcpy(pname+1, w32fd.cFileName);
    
    			if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    				entry = new WinDirectory(this, buffer);
    			else
    				entry = new WinEntry(this);
    
    			if (!first_entry)
    				first_entry = entry;
    
    			if (last)
    				last->_next = entry;
    
    			memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
    			entry->_level = level;
    
    			 // display file type names, but don't hide file extensions
    			g_Globals._ftype_mgr.set_type(entry, true);
    
    			if (!(scan_flags & SCAN_DONT_ACCESS)) {
    				HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
    											0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
    
    				if (hFile != INVALID_HANDLE_VALUE) {
    					if (GetFileInformationByHandle(hFile, &entry->_bhfi))
    						entry->_bhfi_valid = true;
    
    					if (ScanNTFSStreams(entry, hFile))
    						entry->_scanned = true;	// There exist named NTFS sub-streams in this file.
    
    					CloseHandle(hFile);
    				}
    			}
    
    			last = entry;	// There is always at least one entry, because FindFirstFile() succeeded and we don't filter the file entries.
    		} while(FindNextFile(hFind, &w32fd));
    
    		if (last)
    			last->_next = NULL;
    
    		FindClose(hFind);
    	}
    
    	_down = first_entry;
    	_scanned = true;
    }
    
    
    const void* WinDirectory::get_next_path_component(const void* p) const
    {
    	LPCTSTR s = (LPCTSTR) p;
    
    	while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
    		++s;
    
    	while(*s==TEXT('\\') || *s==TEXT('/'))
    		++s;
    
    	if (!*s)
    		return NULL;
    
    	return s;
    }
    
    
    Entry* WinDirectory::find_entry(const void* p)
    {
    	LPCTSTR name = (LPCTSTR)p;
    
    	for(Entry*entry=_down; entry; entry=entry->_next) {
    		LPCTSTR p = name;
    		LPCTSTR q = entry->_data.cFileName;
    
    		do {
    			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
    				return entry;
    		} while(tolower(*p++) == tolower(*q++));
    
    		p = name;
    		q = entry->_data.cAlternateFileName;
    
    		do {
    			if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
    				return entry;
    		} while(tolower(*p++) == tolower(*q++));
    	}
    
    	return NULL;
    }
    
    
     // get full path of specified directory entry
    bool WinEntry::get_path(PTSTR path, size_t path_count) const
    {
    	return get_path_base(path, path_count, ET_WINDOWS);
    }
    
    ShellPath WinEntry::create_absolute_pidl() const
    {
    	CONTEXT("WinEntry::create_absolute_pidl()");
    
    	TCHAR path[MAX_PATH];
    
    	if (get_path(path, COUNTOF(path)))
    		return ShellPath(path);
    
    	return ShellPath();
    }
    
    #endif // _NO_WIN_FS
    Last edited by zebbi; 03-24-2008 at 06:30 AM.

  2. #2
    Registered User
    Join Date
    May 2006
    Posts
    903
    Well obviously you're missing some files. You don't even have an entry point (main(), WinMain() ..).

  3. #3
    Registered User
    Join Date
    Mar 2008
    Posts
    3
    Thanks, how difficult would it be to give this code an entry point and get this working?, do you know of any complete examples of an ADS viewer in c++?
    Last edited by zebbi; 03-24-2008 at 09:55 AM.

  4. #4
    Registered User
    Join Date
    May 2006
    Posts
    903
    Honestly I don't even know what an ADS is. Giving it an entry point is not the solution, you have to find the missing files because you're missing declarations (and maybe other definitions).

  5. #5
    Registered User
    Join Date
    Mar 2008
    Posts
    3
    Alternate Data Steams exist on NTFS flesystems, they allow files to be hidden with other files which seem innocent, and can be created via the command prompt.

    Although they cannot be seen via explorer the BackupRead and BackupSeek API's allow files to be read stream by stream like backup software and can be used to examine files for ADS's.

    There is a fully working program and source available from this link:

    http://www.codeproject.com/KB/winsdk...ataStream.aspx

    but i don't know what compiler was used and how to use the source to compile it from scratch, any thoughts? i need working source for a program like this, or the source from this to be taken and simplified perhaps, no GUI etc.
    Last edited by zebbi; 03-24-2008 at 11:01 AM.

  6. #6
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    A very basic viewer which is run from the command line. It can be compiled using any basic compiler such as Microsoft's CL.EXE

    Code:
    #pragma comment( lib, "advapi32.lib" )   // Search for advapi32.lib while linking
    #include <windows.h>
    #include <stdio.h>
    
    typedef enum _FILE_INFORMATION_CLASS {
        FileDirectoryInformation = 1,     
            FileFullDirectoryInformation, 
            FileBothDirectoryInformation, 
            FileBasicInformation,         
            FileStandardInformation,      
            FileInternalInformation,      
            FileEaInformation,            
            FileAccessInformation,        
            FileNameInformation,          
            FileRenameInformation,        
            FileLinkInformation,          
            FileNamesInformation,         
            FileDispositionInformation,   
            FilePositionInformation,      
            FileModeInformation = 16,        // 16     
            FileAlignmentInformation,     
            FileAllInformation,           
            FileAllocationInformation,        
            FileEndOfFileInformation,         
            FileAlternateNameInformation,     
            FileStreamInformation,            
            FilePipeInformation,              
            FilePipeLocalInformation,         
            FilePipeRemoteInformation,        
            FileMailslotQueryInformation,     
            FileMailslotSetInformation,       
            FileCompressionInformation,       
            FileObjectIdInformation,          
            FileCompletionInformation,        
            FileMoveClusterInformation,       
            FileQuotaInformation,             
            FileReparsePointInformation,      
            FileNetworkOpenInformation,       
            FileAttributeTagInformation,      
            FileTrackingInformation           
    } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
    
    typedef INT NTSTATUS;
    
    #define BUFFER_OVERFLOW        ((NTSTATUS)0x80000005L)
    
    typedef struct _IO_STATUS_BLOCK {
        NTSTATUS Status;
        ULONG Information;
    } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
    
    #pragma pack(push, 4)
    typedef struct _FILE_STREAM_INFORMATION { // Information Class 22
        ULONG NextEntryOffset;
        ULONG StreamNameLength;
        LARGE_INTEGER EndOfStream;
        LARGE_INTEGER AllocationSize;
        WCHAR StreamName[1];
    } FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
    #pragma pack(pop)
    
    typedef NTSTATUS (NTAPI *NTQUERYINFORMATIONFILE)( 
    IN HANDLE FileHandle,
        OUT PIO_STATUS_BLOCK IoStatusBlock,
        OUT PVOID FileInformation,
        IN ULONG Length,
        IN FILE_INFORMATION_CLASS FileInformationClass);
    
    int  main(int argc, char *argv[])
    {
        NTQUERYINFORMATIONFILE NtQueryInformationFile;
        LPBYTE pInfoBlock = NULL;
        ULONG uInfoBlockSize = 0;
        IO_STATUS_BLOCK ioStatus;
        NTSTATUS status;
        HANDLE hFile;
    
        (FARPROC&)NtQueryInformationFile = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationFile");
        if (NtQueryInformationFile == NULL)
        {
            printf("NtQueryInformationFile failed\n");
            return -1;
        }
        hFile = CreateFile(argv[1], 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            printf("Invalid file handle\n");
            return -1;
        }
        do
        {
            uInfoBlockSize += 16384;
            delete [] pInfoBlock;
            pInfoBlock = new BYTE [uInfoBlockSize];
            ((PFILE_STREAM_INFORMATION)pInfoBlock)->StreamNameLength = 0;
            status = NtQueryInformationFile(hFile, &ioStatus, (LPVOID)pInfoBlock, uInfoBlockSize, FileStreamInformation);
        } while (status == BUFFER_OVERFLOW);
        CloseHandle(hFile);
        PFILE_STREAM_INFORMATION pStreamInfo = (PFILE_STREAM_INFORMATION)(LPVOID)pInfoBlock;
        LARGE_INTEGER liFileSize;
        WCHAR wszStreamName[MAX_PATH];
        char szStreamName[MAX_PATH], szFilePath[MAX_PATH];
        LPSTR pszName;
        int iLength;
        if (!GetFullPathName(argv[1], MAX_PATH, szFilePath, &pszName))
        {
            printf("GetFullPathName failed\n");
            return -1;
        }
        printf("%s\n", szFilePath);
        for (;;)
        {
            // Check if stream info block is empty
            if (pStreamInfo->StreamNameLength == 0)
                break; 
            // Get stream name
            memcpy(wszStreamName, pStreamInfo->StreamName, pStreamInfo->StreamNameLength);
            wszStreamName[pStreamInfo->StreamNameLength / sizeof(WCHAR)] = L'\0';
            // Remove attribute tag and convert to char
            LPWSTR pTag = wcsstr(wszStreamName, L":$DATA");
            if (pTag) *pTag = L'\0';
            iLength = WideCharToMultiByte(CP_ACP, 0, wszStreamName, -1, szStreamName, MAX_PATH, NULL, NULL);
            // Full path including stream name
            strcpy(szFilePath, argv[1]);
            if (strcmp(szStreamName, ":"))
            {
                strcat(szFilePath, szStreamName);   // Named stream - attach stream name
            }
            // Get stream size
            hFile = CreateFile(szFilePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
            if (hFile == INVALID_HANDLE_VALUE)
            {
                printf("CreateFilePath failed\n");
                return -1;   
            }
            if (!GetFileSizeEx(hFile, &liFileSize))
            {
                printf("GetFileSizeEx failed\n");
                return -1;
            }
            CloseHandle(hFile);
            if (iLength < 40)
            {
                strcat(szStreamName, "                                        ");
                szStreamName[40] = '\0';
            }
            else
                strcat(szStreamName, " ");
            printf("  %s%I64u\n", szStreamName, liFileSize.QuadPart);
            if (pStreamInfo->NextEntryOffset == 0) break;   // No more stream info records
            pStreamInfo = (PFILE_STREAM_INFORMATION)((LPBYTE)pStreamInfo + pStreamInfo->NextEntryOffset);   // Next stream record
        }
        return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Enforcing Machine Code Restrictions?
    By SMurf in forum Tech Board
    Replies: 21
    Last Post: 03-30-2009, 07:34 AM
  2. Values changing without reason?
    By subtled in forum C Programming
    Replies: 2
    Last Post: 04-19-2007, 10:20 AM
  3. Obfuscated Code Contest
    By Stack Overflow in forum Contests Board
    Replies: 51
    Last Post: 01-21-2005, 04:17 PM
  4. Interface Question
    By smog890 in forum C Programming
    Replies: 11
    Last Post: 06-03-2002, 05:06 PM
  5. Replies: 0
    Last Post: 02-21-2002, 06:05 PM