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