I just noticed a new pair of functions in the Win32 API for Windows Server 2003 – FindFirstStreamW and FindNextStreamW. These are interesting from a security perspective, if for no other reason than that alternate data streams are useful places to hide data.
Before this function, a programmer had to open files with “Backup semantics”, and work his way laboriously through the structure of the streams within the file in order to find out what streams there are. Here’s the sort of code you had to write:
int EnumStreams(const WCHAR *file, StreamEnumProc *func, void *funcarg) { WCHAR wszStreamName[_MAX_PATH+sizeof(WIN32_STREAM_ID)]; WIN32_STREAM_ID &wsId=*((WIN32_STREAM_ID *)wszStreamName); DWORD dwRead, dwStreamHeaderSize, dw1, dw2; LPVOID lpContext=NULL; BOOL bResult=TRUE; HANDLE hFile=CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); ZeroMemory(&wsId,sizeof(wsId)); dwStreamHeaderSize=(LPBYTE)&wsId.cStreamName-(LPBYTE)&wsId; while (bResult) { ZeroMemory(&wsId,sizeof(wsId)); dwRead=0; bResult=BackupRead(hFile, (LPBYTE)&wsId, dwStreamHeaderSize, &dwRead, FALSE, TRUE, &lpContext); if (!bResult || dwRead!=dwStreamHeaderSize) { break; } dwRead=0; if (wsId.dwStreamNameSize+dwStreamHeaderSize>= sizeof(wszStreamName)) return -1; bResult=(!wsId.dwStreamNameSize || BackupRead(hFile, (LPBYTE)&wsId.cStreamName[0], wsId.dwStreamNameSize, &dwRead, FALSE, TRUE, &lpContext)); if (!bResult || dwRead!=wsId.dwStreamNameSize) break; if (bResult) { int nStrLen=wsId.dwStreamNameSize/sizeof(WCHAR); wsId.cStreamName[nStrLen]=0; func(file, &wsId, funcarg); if (wsId.Size.LowPart || wsId.Size.HighPart) BackupSeek(hFile, ULONG_MAX, LONG_MAX, &dw1, &dw2, &lpContext); } } BackupRead(hFile, NULL, 0, &dwRead, TRUE, FALSE, &lpContext); CloseHandle(hFile); if (!bResult) return GetLastError(); return 0; }
Since the FindFirst/NextStreamW functions are only in Windows Server 2003, you’ll still have to do something like that mess on a Windows XP or previous system.
There are still no tools, however, in the base operating system that allow an IT Professional to search for alternate data streams that might be attached to files on his workstation. So, a while back, I created “sdir”, a program that allows you to list alternate data streams on a file or a directory, or recursively through a directory tree. You can find it at http://www.wftpd.com/downloads.htm
Several people have suggested that alternate data streams (or ADS, as they are often referred to) are ideal for infecting a system such that the virus scanner will not find the virus. That’d be true, except for a couple of things – first, that the virus would still need to arrive on the system using a method that would allow virus scanners to look for virus signatures. The virus would have to travel through a download – which doesn’t have a hidden stream – or an email – which doesn’t have a hidden stream – etc, etc. Second, the virus scanners have already added ADS scanning to their repertoire.