VirusCleaner.cpp
资源名称:antinimda.zip [点击查看]
上传用户:leon2013
上传日期:2007-01-10
资源大小:186k
文件大小:11k
源码类别:
杀毒
开发平台:
Visual C++
- // VirusCleaner.cpp: implementation of the CVirusCleaner class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "VirusCleaner.h"
- /* virus identities */
- #include "../definitions/w32_nimda.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CVirusCleaner::CVirusCleaner(LPCTSTR root)
- : m_paused(false), m_scanned(0), m_skipped(0), m_errors(0), m_infected(0), m_deleted(0), m_cleaned(0), m_directories(0), m_velocity(0), m_bytesscanned(0), m_starttime(CTime::GetCurrentTime()), m_read_block_size(0xFFFF)
- {
- if (root) Root(root);
- /* TODO: User might want to specify the log filename */
- m_logfile.Open("c:\anti-nimba.log", CFile::modeCreate | CFile::modeWrite);
- }
- CVirusCleaner::~CVirusCleaner()
- {
- /* close log file if open */
- if (m_logfile.m_hFile)
- m_logfile.Close();
- }
- void CVirusCleaner::Root(LPCTSTR root)
- {
- ASSERT(root);
- if (root)
- if (root[strlen(root)-1]=='\')
- m_root=CString(root,strlen(root)-1);
- else
- m_root=root;
- }
- bool CVirusCleaner::Start()
- {
- m_starttime=CTime::GetCurrentTime();
- if (m_logfile.m_hFile) {
- CString logentry;
- logentry.Format("Scan of '%s' started on %s:rn", m_root, CTime::GetCurrentTime().Format("%c"));
- m_logfile.Write((LPCTSTR)logentry,logentry.GetLength());
- }
- return CServiceThread::Start();
- }
- double CVirusCleaner::Velocity() const
- {
- /* returns files scaned per second (scan speed) */
- return ( (double)m_scanned / Duration().GetTotalSeconds() ) * 60;
- }
- void CVirusCleaner::run()
- {
- /* TODO: I am adding the virus definitions manually here, a better method could be
- implimented. */
- w32_nimda_a a; m_killers.insert(m_killers.end(), &a);
- w32_nimda_b b; m_killers.insert(m_killers.end(), &b);
- w32_nimda_c c; m_killers.insert(m_killers.end(), &c);
- /* build signatures collection */
- m_killergraph = BuildVirusGraph(m_killers);
- /* call scan to recurse from root directory */
- scandirectory(m_root);
- m_stoptime=CTime::GetCurrentTime();
- if (m_logfile.m_hFile) {
- m_logfile.Close();
- m_logfile.m_hFile=NULL;
- }
- }
- CVirusCleaner::VirusGraph CVirusCleaner::BuildVirusGraph(const VirusKiller::Set& kset)
- {
- VirusGraph graph;
- /* iterate through all killers adding virus killers with specified extensions to virus graph */
- int lbrk,brk;
- CString extensions, ext;
- for(VirusKiller::Set::const_iterator k=kset.begin(), _k=kset.end(); k!=_k; k++) {
- /* get extensions string */
- extensions=(*k)->Extensions();
- lbrk=0;
- while (lbrk<extensions.GetLength()) {
- /* break string into extensions */
- if ((brk=extensions.Find(';',lbrk))==-1) brk=extensions.GetLength();
- /* add virus killer to graph under specified extension */
- ext=extensions.Mid(lbrk,brk-lbrk);
- ext.MakeLower();
- graph[ ext ].insert( graph[ ext ].end(), (*k) );
- /* next extension */
- lbrk=brk+1;
- }
- }
- /* add all virus killers without extensions to all known extensions */
- for(k=kset.begin(), _k=kset.end(); k!=_k; k++) {
- for(VirusGraph::iterator g=graph.begin(), _g=graph.end(); g!=_g; g++) {
- if ((*k)->Extensions().IsEmpty())
- /* add virus killer to virus graph if it is not associated with any particular extension */
- (*g).second.insert( (*g).second.end(), (*k) );
- }
- }
- return graph;
- }
- bool CVirusCleaner::scandirectory(LPCTSTR root)
- {
- WIN32_FIND_DATA find;
- memset(&find,0,sizeof(WIN32_FIND_DATA));
- HANDLE hfind=FindFirstFile(CString(root)+"\*.*",&find);
- if (hfind) {
- /* iterate through all files in the directory */
- do {
- if (find.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) {
- /* for directories recurse into them */
- if ((strcmp(find.cFileName,".")!=0) && (strcmp(find.cFileName,"..")!=0))
- scandirectory(CString(root)+'\'+find.cFileName);
- }
- else {
- /* for files call the virus cleaner */
- scanfile(CString(root)+'\'+find.cFileName);
- }
- /* wait if scan thread is paused */
- while(IsPaused() && !StopPending())
- Sleep(10);
- /* get next file */
- } while (FindNextFile(hfind,&find) && !StopPending());
- /* close the find operation */
- FindClose(hfind);
- }
- /* update scan statistics */
- m_directories++;
- return hfind!=INVALID_HANDLE_VALUE;
- }
- bool CVirusCleaner::scanfile(LPCTSTR file)
- {
- FILE* fp;
- try{
- /* dont scan this executable */
- char fname[1024];
- if (GetModuleFileName(NULL,fname,sizeof(fname)) && (stricmp(file,fname)==0))
- return true;
- /* holds a lost of virus infections found in this file */
- VirusKiller::Set infections;
- /* get the files extension */
- CString extension(file);
- int brk=extension.ReverseFind('.');
- if (brk)
- extension=extension.Mid(brk+1); /* break off extension */
- else
- extension=""; /* assume no extension */
- extension.MakeLower();
- /* get the virus killers associated with this extension */
- VirusKiller::Set& killers = ScanAll()? m_killers : m_killergraph[ extension ];
- int killers_count = killers.size();
- if (killers_count) {
- /* open named file in read-only binary mode */
- if (fp=fopen(file,"rb")) {
- /* build a vector of signature pointers */
- LPBYTE* signatures = new LPBYTE[ killers_count ];
- /* fill the signatures vector */
- int i=0;
- for(VirusKiller::Set::const_iterator k=killers.begin(), _k=killers.end(); k!=_k; k++)
- if ((*k)->AllFiles()) {
- infections.insert( infections.begin(), (*k) );
- signatures[ i++ ] = NULL;
- }
- else
- signatures[ i++ ] = (*k)->Signature();
- /* find the longest signature */
- int max_signature=0, j;
- for(i=0; i<killers_count; i++)
- if (signatures[i] && (j=strlen((LPCTSTR)signatures[i]))>max_signature) max_signature=j;
- /* scan file for virus signature
- Algorithm: Using double buffers (size of m_read_block_size) as a rolling buffer we will
- replace the data with a next loaded buffer as each buffer is no longer required.
- */
- DWORD base=0; /* base offset of first signature character into rolling buffer */
- DWORD offset; /* offset from base of currently comparing character */
- DWORD buffer_size=2 * m_read_block_size; /* size of our rolling buffer */
- DWORD end_base=buffer_size+1; /* will signal when the scanner is at the end of
- the file in the rolling buffer */
- size_t bytes_read; /* number of bytes read with last read operation */
- /* allocate our rolling buffer */
- LPBYTE buffer = (LPBYTE)malloc(buffer_size);
- /* load the initial double buffers */
- bytes_read = fread(buffer, 1, m_read_block_size*2, fp);
- m_bytesscanned+=bytes_read;
- while (base!=end_base) {
- /* search for signature match at this base address */
- for(i=0,offset=0; i<killers_count; i++,offset=0)
- if (signatures[i]) {
- /* continue comparing signature character to file character
- until not equal or encountered null in signature */
- while ( (signatures[i][offset]) && (signatures[i][offset] == *(buffer + (base+offset)%buffer_size)) )
- offset++;
- /* if we have reached the end of signature string we have found a match */
- if (!signatures[i][offset]) {
- int j=0;
- /* find the virus killer associated with this sequence */
- for(VirusKiller::Set::iterator k=killers.begin(), _k=killers.end(); k!=_k; k++, j++)
- if (j==i) {
- /* add virus to list of infections */
- infections.insert( infections.end(), (*k) );
- /* TO DO: we can ignore further occurances of virus sequence */
- signatures[i]=NULL;
- break;
- }
- }
- }
- /* increase base address of character we are scanning in the rolling buffer */
- base++;
- /* load back buffer if scanned */
- if (base>buffer_size) {
- base=0;
- if ((end_base>buffer_size) && (bytes_read=fread(&buffer[m_read_block_size], 1, m_read_block_size, fp))<m_read_block_size) {
- end_base=m_read_block_size+bytes_read;
- /* update scan statistics */
- m_bytesscanned+=bytes_read;
- }
- }
- /* load front buffer if scanned */
- else if (base==m_read_block_size) {
- if ((end_base>buffer_size) && (bytes_read=fread(buffer, 1, m_read_block_size, fp))<m_read_block_size) {
- end_base=bytes_read;
- /* update scan statistics */
- m_bytesscanned+=bytes_read;
- }
- }
- }
- /* free our rolling buffer */
- free(buffer);
- /* free the signature vector */
- delete[] signatures;
- /* close the file */
- fclose(fp);
- /* update scan statistics */
- m_lastfile=file;
- m_scanned++;
- /* check to see if any sequences where found */
- if (infections.size()) {
- /* clean file of infected viruses */
- VirusKiller::SCANRESULT result;
- result=cleanfile(file, infections);
- /* update scan statistics */
- if (result&(VIRUS_CLEANED|VIRUS_DELETED|VIRUS_SKIPPED)) { result|=VIRUS_INFECTED; m_infected++; }
- if (result&VIRUS_CLEANED) m_cleaned++;
- if (result&VIRUS_DELETED) m_deleted++;
- if (result&VIRUS_SKIPPED) m_skipped++;
- /* notify children */
- OnInfected(file, result);
- }
- return true;
- }
- else {
- /* error opening file */
- m_errors++;
- return false;
- }
- }
- else {
- /* no associated virus killers : skip file */
- m_skipped++;
- return true;
- }
- } catch(...) {
- m_errors++;
- return false;
- }
- }
- VirusKiller::SCANRESULT CVirusCleaner::cleanfile(LPCTSTR file, VirusKiller::Set& infections)
- {
- /* call the virus killers clean method */
- VirusKiller::SCANRESULT result;
- for(VirusKiller::Set::iterator k=infections.begin(), _k=infections.end(); k!=_k; k++)
- result = (*k)->Clean(file);
- /* TODO: The result should be checked for each iteration so it's previous value is not
- discarded as it is done now. Not a problem for cases of Nimda virus.
- */
- /* update scan statistics */
- if (result&VIRUS_ERR) m_errors++;
- /* append log entry */
- if (m_logfile.m_hFile) {
- CString action;
- switch (result) {
- case VIRUS_SKIPPED: action="skipped"; break;
- case VIRUS_SCANNED: action="scanned"; break;
- case VIRUS_INFECTED: action="infected"; break;
- case VIRUS_CLEANED: action="cleaned"; break;
- case VIRUS_DELETED: action="deleted"; break;
- default:
- action="error"; break;
- }
- CString logentry;
- logentry.Format("%s: %srn", action, file);
- m_logfile.Write((LPCTSTR)logentry, logentry.GetLength());
- }
- return result;
- }