/*----------------------------------------------------------------------- saidel - Suspicious and Illegal file Deletion Version 0.00 24/03/2009 (C) 2009 David Cutting Licence: GNU GPL v3 or later at user discretion All Rights Reserved http://www.purplepixie.org/dave/ dcutting [some_sort_of_magic_sign] purplepixie [some_kind_of_dot] org ---------------------------------------------------------------------- */ #define SAIDEL_VERSION "0.00" #include #include #include using namespace std; bool Prompt=true; bool Delete=true; bool Recurse=false; bool Debug=false; int MaxDepth=99; // infinite loop protection (symlinks etc) string Path=".\\"; void ShowHelp(void) { cout << "saidel - suspicious and illegal file deletion vers " << SAIDEL_VERSION << endl; cout << "Usage: saidel [options] [/path PATH]" << endl << endl; cout << "Options:" << endl; cout << " /prompt | /noprompt - prompt for each file (default yes)" << endl; cout << " /delete | /nodelete - delete the files or not (default yes)" << endl; cout << " /recurse | /norecurse - recurse down directories or not (default no)" << endl; cout << " /path PATH - set the path to work in (defaults to PWD)" << endl; cout << " NB for the contents of a directory leave a trailing \\, for example:" << endl; cout << " C:\\Windows\\ would check INSIDE the Windows directory but C:\\Windows would" << endl; cout << " just check that folder name itself." << endl << endl; cout << "Examples:" << endl; cout << "saidel /noprompt /delete /recurse /path C:\\" << endl; cout << " Would delete suspicious files recursively on C: without prompting" << endl << endl; cout << "For more info see http://www.purplepixie.org/dave/" << endl; } string ynbool(bool b) { string ret; if (b) ret="Yes"; else ret="No"; return ret; } bool isIllegal(int ascii) { // in it's own function just because... if (ascii<32) return true; // below the space char i.e. control chars else if (ascii>126) return true; // above the ~ i.e. delete or weird-arse stuff else return false; } void PurgeDir(string DirPath, int depth=0) { if (depth>=MaxDepth) return; string SearchPath = DirPath + "*"; cout << "Directory: " << DirPath << endl; int filecount=0; string filename; // reused each time WIN32_FIND_DATA f; HANDLE h = FindFirstFile(SearchPath.c_str(), &f); if(h != INVALID_HANDLE_VALUE) { do { bool invalid=false; // flag to show sai chars filename=f.cFileName; if (Debug) cout << filecount << ": " << filename << endl; if ( (filename==".") || (filename=="..") ) { // skip these } else if (f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (Debug) cout << filename << " is a DIRECTORY" << endl; if (Recurse) { string newDir = DirPath + filename + "\\"; PurgeDir(newDir, depth+1); } } else // file { for(unsigned int a=0; a< filename.length(); a++) { char chr = filename[a]; int ascii = (int) chr; bool illegal = isIllegal(ascii); // check char if (Debug) cout << " " << a << " " << chr << " (" << ascii << ") - invalid: " << ynbool(invalid) << endl; if (illegal) invalid=true; } if (invalid) { bool deletefile; cout << filecount << ": " << filename << " is INVALID" << endl; if (Delete) deletefile=true; else deletefile=false; if (Prompt&&Delete) // only prompt if delete flag is set { cout << "Delete file? (y/n) "; string input; cin >> input; if ( (input == "y") || (input == "Y") ) deletefile=true; else deletefile=false; } string FullFilename = DirPath + filename; if (deletefile) { cout << "Deleting File: " << FullFilename << endl; if (!DeleteFile(FullFilename.c_str())) { DWORD errorcode=GetLastError(); cout << "Error Deleting File " << FullFilename << " - " << errorcode << endl; } else cout << "File Deleted " << FullFilename << endl; } else { if (Debug) cout << "NOT Deleting File: " << FullFilename << endl; } } } filecount++; } while(FindNextFile(h, &f)); } else { cout << "Error opening directory: " << DirPath << endl; } } int main(int ac, char **av) { string argtmp=""; for (int a=1; a