www.pudn.com > antinimda.zip > ProcessScanner.cpp
// 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.\r\n",(*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; imax_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 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