int ListDataStreams(char *szFilename) { int iRetCode = EXIT_SUCCESS; HANDLE *hFile = NULL; LPVOID lpContext = NULL; byte pbyBuffer[4096]; WIN32_STREAM_ID *psStreamInfo = (WIN32_STREAM_ID *)pbyBuffer; int uiHeaderLength = 20; DWORD dwRead, dwDummy; WHANDLEOK(hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)); while (1) { WNONZERO(BackupRead(hFile, pbyBuffer, uiHeaderLength, &dwRead, FALSE, TRUE, &lpContext)); if (dwRead == 0) break; if (psStreamInfo->dwStreamNameSize > 0) { WNONZERO(BackupRead(hFile, pbyBuffer + uiHeaderLength, psStreamInfo->dwStreamNameSize, &dwRead, FALSE, TRUE, &lpContext)); if (dwRead != psStreamInfo->dwStreamNameSize) break; } DumpStreamInfo(szFilename, psStreamInfo); if (psStreamInfo->Size.QuadPart > 0) { BackupSeek(hFile, psStreamInfo->Size.LowPart, psStreamInfo->Size.HighPart, &dwDummy, &dwDummy, &lpContext); } } cleanup: // release context BackupRead(hFile, pbyBuffer, 0, &dwRead, TRUE, FALSE, &lpContext); CloseHandle(hFile); return iRetCode; }
int next_stream(WIN32_STREAM_ID *dest, struct nt_sid *sid) { DWORD lo, hi, b; if(sid->is_write) return(-1); if(sid->rem.LowPart!=0||sid->rem.HighPart!=0) { if(!BackupSeek(sid->hf, sid->rem.LowPart, sid->rem.HighPart, &lo, &hi, &sid->lpcontext)) return(-1); if(lo!=sid->rem.LowPart||hi!=sid->rem.HighPart) return(-1); sid->rem.LowPart=sid->rem.HighPart=0; } if(!BackupRead(sid->hf, (unsigned char *)dest, W32_SID_HEADER_SIZE, &b, FALSE, TRUE, &sid->lpcontext)) return(-1); if(b!=W32_SID_HEADER_SIZE) return(-1); sid->rem=dest->Size; return(0); }
/* Check if file has NTFS ADS */ int os_check_ads(const char *full_path) { HANDLE file_h; WIN32_STREAM_ID sid; void *context = NULL; char stream_name[MAX_PATH + 1]; char final_name[MAX_PATH + 1]; DWORD dwRead, shs, dw1, dw2; /* Open file */ file_h = CreateFile(full_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL); if (file_h == INVALID_HANDLE_VALUE) { return 0; } /* Zero memory */ ZeroMemory(&sid, sizeof(WIN32_STREAM_ID)); /* Get stream header size -- should be 20 bytes */ shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid + sid.dwStreamNameSize; while (1) { if (BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead, FALSE, FALSE, &context) == 0) { break; } if (dwRead == 0) { break; } stream_name[0] = '\0'; stream_name[MAX_PATH] = '\0'; if (BackupRead(file_h, (LPBYTE)stream_name, sid.dwStreamNameSize, &dwRead, FALSE, FALSE, &context)) { if (dwRead != 0) { DWORD i = 0; int max_path_size = 0; char *tmp_pt; char op_msg[OS_SIZE_1024 + 1]; snprintf(final_name, MAX_PATH, "%s", full_path); max_path_size = strlen(final_name); /* Copy from wide char to char */ while ((i < dwRead) && (max_path_size < MAX_PATH)) { if (stream_name[i] != 0) { final_name[max_path_size] = stream_name[i]; max_path_size++; final_name[max_path_size] = '\0'; } i++; } tmp_pt = strrchr(final_name, ':'); if (tmp_pt) { *tmp_pt = '\0'; } snprintf(op_msg, OS_SIZE_1024, "NTFS Alternate data stream " "found: '%s'. Possible hidden" " content.", final_name); notify_rk(ALERT_ROOTKIT_FOUND, op_msg); } } /* Get next */ if (!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &context)) { break; } } CloseHandle(file_h); return (0); }
int backup1(struct fout *ff, const char *f) { WIN32_STREAM_ID sid; LPVOID lpContext; HANDLE h; DWORD rv; int r, n; lpContext = NULL; set_backup_privs(1); h = CreateFileA(f, FILE_READ_DATA | STANDARD_RIGHTS_READ | ACCESS_SYSTEM_SECURITY, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (h == INVALID_HANDLE_VALUE) { r = GetLastError(); if (r == ERROR_FILE_NOT_FOUND) { set_backup_privs(0); fout_abort(ff); return 1; } set_backup_privs(0); /* try to read it raw */ if (!backup1_ntfs(ff, f)) { return 0; } /* hooray! it read in- get the security info */ if (s_flag) return backupsec2(f); return 1; } if (!backupsec(h, f)) { r = GetLastError(); CloseHandle(h); set_backup_privs(0); SetLastError(r); return 0; } NEXT_STREAM: rv = 0; if (!BackupRead(h,(void*)&sid,20, &rv,FALSE,FALSE,&lpContext)) { goto FAIL; } if (rv < 2) { /* SUCCESS */ (void)BackupRead(h,buffer,sizeof(buffer),&rv,TRUE,FALSE,&lpContext); CloseHandle(h); set_backup_privs(0); SetLastError(ERROR_SUCCESS); return 1; } if (rv != 20) { goto FAIL; } if (sid.dwStreamId != 1 || sid.dwStreamAttributes != 0 || sid.dwStreamNameSize > 0) { /* skip */ BackupSeek(h, sid.dwStreamNameSize, 0, (void*)buffer, (void*)(buffer+8), &lpContext); BackupSeek(h, sid.Size.LowPart, sid.Size.HighPart, (void*)buffer, (void*)(buffer+8), &lpContext); goto NEXT_STREAM; } while (sid.Size.QuadPart > 0) { rv = 0; if (sid.Size.QuadPart < sizeof(buffer)) { n = sid.Size.QuadPart; } else { n = sizeof(buffer); } if (!BackupRead(h,buffer,n,&rv,FALSE,FALSE,&lpContext)) { goto FAIL; } r=rv; if (!r) break; if (!fout(ff, buffer, r)) { goto FAIL; } } goto NEXT_STREAM; FAIL: r = GetLastError(); (void)BackupRead(h,buffer,sizeof(buffer),&rv,TRUE,FALSE,&lpContext); CloseHandle(h); set_backup_privs(0); SetLastError(r); return 0; }
/****************************************************************************** * CKMPrivate_Utils::secureDeleteStreams() * * Parameters: inFilename - [in] name of file with streams to delete * inDeletePasses - [in] number of "cleaning" passes to make * * Returns: Nothing * Throws: Nothing * * Description: Securely delete all streams belonging to the supplied * file by overwriting them with 111s and 000s. * * Note: Does not exist under Unix, which has no alternate stream support *****************************************************************************/ bool FileVEILOperationsImpl::secureDeleteStreams(const tscrypto::tsCryptoString& inFilename, int inDeletePasses) { TSDECLARE_FUNCTIONExt(true); #ifdef WIN32 // if we aren't on an NT platform, bail out now (no streams to delete) //OSVERSIONINFO osvi; //ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); //osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //if (! GetVersionEx ( (OSVERSIONINFO *) &osvi)) //{ // return TSRETURN(("OK"),true); //} //else if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) //{ // return TSRETURN(("OK"),true); //} int index; HANDLE hFile; BOOL bContinue; void * ctx = NULL; WIN32_STREAM_ID sid; DWORD dwRead, lo, hi; // open the file whose streams we want to delete if (INVALID_HANDLE_VALUE == (hFile = CreateFileA(inFilename.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0))) { LogError("Unable to open the specified file. " + inFilename); return TSRETURN_ERROR(("Invalid filename"), true); } // we have to build a list of named files to delete, and then close the // original file. The streams can't be written when the main file is open int streamCnt = 0; tscrypto::tsCryptoStringList streamList = CreateTsAsciiList(); CryptoUtf16 streamName; tscrypto::tsCryptoString tmpStr; // read the first 20 bytes of the stream (all but the last field) while ((bContinue = BackupRead(hFile, (LPBYTE)&sid, sizeof(sid) - sizeof(WCHAR *), &dwRead, FALSE, FALSE, &ctx)) != FALSE) { // if we are done or there was no data read, break out if (!bContinue || !dwRead) break; // if this stream is named Alternate Data, delete it if (sid.dwStreamId == BACKUP_ALTERNATE_DATA && sid.dwStreamNameSize > 0) { // get the name of the stream (Wide-Char format) streamName.clear(); streamName.resize(sid.dwStreamNameSize / sizeof(ts_wchar)); BackupRead(hFile, (byte *)streamName.data(), sid.dwStreamNameSize, &dwRead, FALSE, FALSE, &ctx); if (wcslen(streamName.c_str()) >= 6 && wcscmp(&streamName[wcslen(streamName.c_str()) - 6], L":$DATA") == 0) { streamName.resize(streamName.size() - 6); } tmpStr = inFilename + streamName.toUtf8(); streamList->push_back(tmpStr); } // seek to the end of this stream so we can check the next one BackupSeek(hFile, sid.Size.LowPart, sid.Size.HighPart, &lo, &hi, &ctx); } // free memory allocated by BackupRead and close the file BackupRead(hFile, (LPBYTE)&sid, 0, &dwRead, TRUE, FALSE, &ctx); CloseHandle(hFile); m_taskCount += streamCnt; // now go through the list we built and secureDelete each stream for (index = 0; index < streamCnt; index++) { // ignore exceptions and move on to the next one LOG(DebugInfo1, "CKMPrivate_Utils::secureDeleteStreams() securedelete stream " << streamList->at(index)); if (!secureDeleteFile(streamList->at(index), inDeletePasses)) return TSRETURN(("Returns ~~"), false); m_currentTask++; } #endif /* WIN32 */ return TSRETURN(("OK"), true); }
/* Print out streams of a file */ int os_get_streams(char *full_path) { HANDLE file_h; WIN32_STREAM_ID sid; void *context = NULL; char stream_name[MAX_PATH +1]; char final_name[MAX_PATH +1]; DWORD dwRead, shs, dw1, dw2; /* Opening file */ file_h = CreateFile(full_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL); if (file_h == INVALID_HANDLE_VALUE) { return 0; } /* Zeroing memory */ ZeroMemory(&sid, sizeof(WIN32_STREAM_ID)); /* Getting stream header size -- should be 20 bytes */ shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid+ sid.dwStreamNameSize; while(1) { if(BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead, FALSE, FALSE, &context) == 0) { break; } if(dwRead == 0) { break; } stream_name[0] = '\0'; stream_name[MAX_PATH] = '\0'; if(BackupRead(file_h, (LPBYTE)stream_name, sid.dwStreamNameSize, &dwRead, FALSE, FALSE, &context)) { if(dwRead != 0) { char *tmp_pt; snprintf(final_name, MAX_PATH, "%s%S", full_path, (WCHAR *)stream_name); tmp_pt = strrchr(final_name, ':'); if(tmp_pt) { *tmp_pt = '\0'; } printf("Found NTFS ADS: '%s' \n", final_name); ads_found = 1; } } /* Getting next */ if(!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &context)) { break; } } CloseHandle(file_h); return(0); }