ProcessScanner.cpp
资源名称:antinimda.zip [点击查看]
上传用户:leon2013
上传日期:2007-01-10
资源大小:186k
文件大小:10k
源码类别:
杀毒
开发平台:
Visual C++
- // ProcessScanner.cpp: implementation of the CProcessScanner class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "memoryscan.h"
- #include "ProcessScanner.h"
- #include "EnumProcesses.h"
- #include "imagehlp.h"
- #include "../definitions/w32_nimda.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- /* callback function fills Processes collection with specified process */
- BOOL CALLBACK process_enumerator( DWORD dw, WORD w16, LPSTR lpstr, LPARAM lParam )
- {
- /* insert module into collection */
- ASSERT(lParam);
- CProcessScanner::Processes& processes = *(CProcessScanner::Processes*)lParam;
- processes[dw] = lpstr;
- return TRUE;
- }
- BOOL CALLBACK module_enumerator(PSTR ModuleName, ULONG ModuleBase, ULONG ModuleSize, PVOID UserContext)
- {
- /* insert module into collection */
- ASSERT(UserContext);
- CProcessScanner::Modules& modules = *(CProcessScanner::Modules*)UserContext;
- modules.insert(modules.end(), CProcessScanner::Module(0,ModuleName,ModuleBase,ModuleSize));
- return TRUE;
- }
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CProcessScanner::CProcessScanner()
- : m_processid(0), m_processsize(0), m_processposition(0), m_scanned(0), m_infections(0), m_read_block_size(0xFFFF), m_bytesscanned(0)
- {
- }
- CProcessScanner::~CProcessScanner()
- {
- }
- CProcessScanner::Processes CProcessScanner::GetActiveProcesses()
- {
- /* call enumeration procedure from MSDN sample and return */
- Processes processes;
- EnumProcs( &process_enumerator, (DWORD)&processes );
- return processes;
- }
- CProcessScanner::Modules CProcessScanner::GetProcessModules(DWORD processid)
- {
- Modules modules;
- HANDLE hprocess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ, TRUE, processid);
- if (hprocess) {
- modules=GetProcessModules(hprocess, processid);
- CloseHandle(hprocess);
- }
- return modules;
- }
- CProcessScanner::Modules CProcessScanner::GetProcessModules(HANDLE hprocess, DWORD processid)
- {
- Modules modules;
- /* enumerate modules into collection */
- VERIFY(EnumerateLoadedModules(hprocess,&module_enumerator,(PVOID)&modules));
- /* set process members of all modules in collection */
- for(Modules::iterator m=modules.begin(), _m=modules.end(); m!=_m; m++)
- (*m).processId=processid;
- return modules;
- }
- void CProcessScanner::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);
- /* get active processes in memory */
- processes=GetActiveProcesses();
- /* scan each process */
- VirusKiller::SCANRESULT result;
- for(Processes::const_iterator p=processes.begin(), _p=processes.end(); (p!=_p) && !StopPending(); p++)
- if ((*p).first!=GetCurrentProcessId()) {
- /* scan the process */
- result=scanprocess(p->first);
- /* update scan statistics */
- m_scanned++;
- if (result&VIRUS_INFECTED) m_infections++;
- }
- else
- m_scanned++;
- }
- VirusKiller::SCANRESULT CProcessScanner::scanprocess(DWORD processid)
- {
- VirusKiller::SCANRESULT result=VIRUS_SCANNED;
- /* open process */
- HANDLE hprocess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ, TRUE, processid);
- if (hprocess) {
- /* enumerate the processes modules */
- Modules modules=GetProcessModules(hprocess, processid);
- /* get the size of memory scan */
- DWORD szscan=0;
- for(Modules::const_iterator m=modules.begin(), _m=modules.end(); m!=_m; m++)
- szscan+=(*m).Length;
- /* update statistics */
- m_processname = processes[ processid];
- m_processid = processid;
- m_processsize=szscan;
- m_processposition=0;
- /* scan all modules */
- for(m=modules.begin(), _m=modules.end(); (m!=_m) && !StopPending(); m++) {
- // TRACE("Scanning module '%s', base 0x%x, length %d.rn",(*m).moduleName, (*m).baseAddress, (*m).Length);
- result|=scanprocessblock(hprocess, (*m));
- /* update scan statistics */
- m_processposition+=(*m).Length;
- }
- /* close the process */
- CloseHandle(hprocess);
- return result;
- }
- /* no infections */
- return VIRUS_ERR;
- }
- VirusKiller::SCANRESULT CProcessScanner::scanprocessblock(HANDLE hprocess, const Module& module)
- {
- /* get module base address and length */
- ULONG module_base=module.baseAddress;
- ULONG module_length=module.Length;
- /* set when a virus is found */
- VirusKiller::SCANRESULT result=VIRUS_SCANNED;
- /* verify parameters */
- ASSERT(hprocess && module_base && module_length);
- /* get the virus killers associated with this extension */
- VirusKiller::Set killers = m_killers;
- /* filter out killers that dont have a signature string */
- for(VirusKiller::Set::iterator k=killers.begin(); k!=killers.end(); k++)
- if (!(*k)->Signature()) {
- VirusKiller::Set::iterator k2=k;
- k++;
- killers.erase(k2);
- }
- int killers_count = killers.size();
- if (killers_count) {
- /* 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++)
- 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 bytes_read; /* number of bytes read with last read operation */
- DWORD prev_bytes_read; /* bytes read with the previous to last read operation */
- /* allocate our rolling buffer */
- LPBYTE buffer = (LPBYTE)malloc(buffer_size);
- /* load the initial double buffers */
- if (ReadProcessMemory(hprocess,(LPCVOID)module_base, buffer, (module_length<m_read_block_size? module_length : m_read_block_size), &bytes_read)) {
- module_base+=bytes_read;
- module_length-=bytes_read;
- prev_bytes_read=bytes_read;
- }
- else
- /* process read error */
- return VIRUS_ERR;
- /* update scan statistics */
- m_bytesscanned+=bytes_read;
- while(bytes_read > 0) {
- /* load the next block (after the current block) */
- if (module_length) {
- DWORD buffer_load_address=(base+m_read_block_size)%(m_read_block_size*2);
- DWORD ibuffer=(base/m_read_block_size+1)%2;
- if (!ReadProcessMemory(hprocess,(LPCVOID)module_base, &buffer[ buffer_load_address ], (module_length<m_read_block_size? module_length : m_read_block_size), &bytes_read)) {
- /* process memory read error */
- return VIRUS_ERR;
- }
- }
- else
- bytes_read=0;
- /* search through buffer for a signature match
- */
- DWORD to_base = ((base/m_read_block_size)%2)*m_read_block_size + prev_bytes_read;
- while ((base < to_base) && !StopPending()) {
- /* search for signature match at this base address of the rolling buffer
- */
- 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)&&(j!=i); k++, j++);
- /* search should always find associated killer */
- ASSERT(j==i);
- /* default notification method calls the virus killers clean function */
- result|=OnInfectedProcess(hprocess, module, *(*k));
- /* set infected flag if killer returned infected */
- if (result&(VIRUS_SKIPPED|VIRUS_CLEANED|VIRUS_DELETED|VIRUS_NOTIMPLIMENTED))
- result|=VIRUS_INFECTED;
- /* must return if virus killer terminated process */
- if (result&VIRUS_DELETED) return result;
- /* we can ignore further occurances of virus sequence */
- signatures[i]=NULL;
- }
- }
- /* increase base address of character we are scanning in the rolling buffer */
- base++;
- }
- /* update module base address and length for next process memory read */
- module_base+=bytes_read;
- module_length-=bytes_read;
- prev_bytes_read=bytes_read;
- if (base==buffer_size) base=0;
- }
- /* free our rolling buffer */
- free(buffer);
- /* free the signature vector */
- delete[] signatures;
- return result;
- }
- return VIRUS_SKIPPED;
- }
- VirusKiller::SCANRESULT CProcessScanner::OnInfectedProcess(HANDLE hprocess, const Module& module, VirusKiller& killer)
- {
- CString s(CurrentProcessName()), ss;
- int brk;
- if((brk=s.ReverseFind('\'))!=-1) s=s.Mid(brk+1);
- s.MakeLower();
- ss.Format("Virus found in memory in process %d '%s', module %s!", module.processId, s, module.moduleName);
- AfxMessageBox(ss);
- return killer.Clean(hprocess, module.moduleName, module.baseAddress, module.Length);
- }