ProcessScanner.cpp
上传用户:leon2013
上传日期:2007-01-10
资源大小:186k
文件大小:10k
源码类别:

杀毒

开发平台:

Visual C++

  1. // ProcessScanner.cpp: implementation of the CProcessScanner class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "memoryscan.h"
  6. #include "ProcessScanner.h"
  7. #include "EnumProcesses.h"
  8. #include "imagehlp.h"
  9. #include "../definitions/w32_nimda.h"
  10. #ifdef _DEBUG
  11. #undef THIS_FILE
  12. static char THIS_FILE[]=__FILE__;
  13. #define new DEBUG_NEW
  14. #endif
  15. /* callback function fills Processes collection with specified process */
  16. BOOL CALLBACK process_enumerator( DWORD dw, WORD w16, LPSTR lpstr, LPARAM lParam )
  17. {
  18. /* insert module into collection */
  19. ASSERT(lParam);
  20. CProcessScanner::Processes& processes = *(CProcessScanner::Processes*)lParam;
  21. processes[dw] = lpstr;
  22. return TRUE;
  23. }
  24. BOOL CALLBACK module_enumerator(PSTR ModuleName, ULONG ModuleBase, ULONG ModuleSize, PVOID UserContext)
  25. {
  26. /* insert module into collection */
  27. ASSERT(UserContext);
  28. CProcessScanner::Modules& modules = *(CProcessScanner::Modules*)UserContext;
  29. modules.insert(modules.end(), CProcessScanner::Module(0,ModuleName,ModuleBase,ModuleSize));
  30. return TRUE;
  31. }
  32. //////////////////////////////////////////////////////////////////////
  33. // Construction/Destruction
  34. //////////////////////////////////////////////////////////////////////
  35. CProcessScanner::CProcessScanner()
  36. : m_processid(0), m_processsize(0), m_processposition(0), m_scanned(0), m_infections(0), m_read_block_size(0xFFFF), m_bytesscanned(0)
  37. {
  38. }
  39. CProcessScanner::~CProcessScanner()
  40. {
  41. }
  42. CProcessScanner::Processes CProcessScanner::GetActiveProcesses()
  43. {
  44. /* call enumeration procedure from MSDN sample and return */
  45. Processes processes;
  46. EnumProcs( &process_enumerator, (DWORD)&processes );
  47. return processes;
  48. }
  49. CProcessScanner::Modules CProcessScanner::GetProcessModules(DWORD processid)
  50. {
  51. Modules modules;
  52. HANDLE hprocess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ, TRUE, processid);
  53. if (hprocess) {
  54. modules=GetProcessModules(hprocess, processid);
  55. CloseHandle(hprocess);
  56. }
  57. return modules;
  58. }
  59. CProcessScanner::Modules CProcessScanner::GetProcessModules(HANDLE hprocess, DWORD processid)
  60. {
  61. Modules modules;
  62. /* enumerate modules into collection */
  63. VERIFY(EnumerateLoadedModules(hprocess,&module_enumerator,(PVOID)&modules));
  64. /* set process members of all modules in collection */
  65. for(Modules::iterator m=modules.begin(), _m=modules.end(); m!=_m; m++)
  66. (*m).processId=processid;
  67. return modules;
  68. }
  69. void CProcessScanner::run()
  70. {
  71. /* TODO: I am adding the virus definitions manually here, a better method could be 
  72. implimented. */
  73. w32_nimda_a a; m_killers.insert(m_killers.end(), &a);
  74. w32_nimda_b b; m_killers.insert(m_killers.end(), &b);
  75. w32_nimda_c c; m_killers.insert(m_killers.end(), &c);
  76. /* get active processes in memory */
  77. processes=GetActiveProcesses();
  78. /* scan each process */
  79. VirusKiller::SCANRESULT result;
  80. for(Processes::const_iterator p=processes.begin(), _p=processes.end(); (p!=_p)  && !StopPending(); p++) 
  81. if ((*p).first!=GetCurrentProcessId()) {
  82. /* scan the process */
  83. result=scanprocess(p->first);
  84. /* update scan statistics */
  85. m_scanned++;
  86. if (result&VIRUS_INFECTED) m_infections++;
  87. }
  88. else
  89. m_scanned++;
  90. }
  91. VirusKiller::SCANRESULT CProcessScanner::scanprocess(DWORD processid)
  92. {
  93. VirusKiller::SCANRESULT result=VIRUS_SCANNED;
  94. /* open process */
  95. HANDLE hprocess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ, TRUE, processid);
  96. if (hprocess) {
  97. /* enumerate the processes modules */
  98. Modules modules=GetProcessModules(hprocess, processid);
  99. /* get the size of memory scan */
  100. DWORD szscan=0;
  101. for(Modules::const_iterator m=modules.begin(), _m=modules.end(); m!=_m; m++)
  102. szscan+=(*m).Length;
  103. /* update statistics */
  104. m_processname = processes[ processid];
  105. m_processid = processid;
  106. m_processsize=szscan;
  107. m_processposition=0;
  108. /* scan all modules */
  109. for(m=modules.begin(), _m=modules.end(); (m!=_m)  && !StopPending(); m++) {
  110. // TRACE("Scanning module '%s', base 0x%x, length %d.rn",(*m).moduleName, (*m).baseAddress, (*m).Length);
  111. result|=scanprocessblock(hprocess, (*m));
  112. /* update scan statistics */
  113. m_processposition+=(*m).Length;
  114. }
  115. /* close the process */
  116. CloseHandle(hprocess);
  117. return result;
  118. }
  119. /* no infections */
  120. return VIRUS_ERR;
  121. }
  122. VirusKiller::SCANRESULT CProcessScanner::scanprocessblock(HANDLE hprocess, const Module& module)
  123. {
  124. /* get module base address and length */
  125. ULONG module_base=module.baseAddress;
  126. ULONG module_length=module.Length;
  127. /* set when a virus is found */
  128. VirusKiller::SCANRESULT result=VIRUS_SCANNED;
  129. /* verify parameters */
  130. ASSERT(hprocess && module_base && module_length);
  131. /* get the virus killers associated with this extension */
  132. VirusKiller::Set killers = m_killers;
  133. /* filter out killers that dont have a signature string */
  134. for(VirusKiller::Set::iterator k=killers.begin(); k!=killers.end(); k++) 
  135. if (!(*k)->Signature()) {
  136. VirusKiller::Set::iterator k2=k;
  137. k++;
  138. killers.erase(k2);
  139. }
  140. int killers_count = killers.size();
  141. if (killers_count) {
  142. /* build a vector of signature pointers */
  143. LPBYTE* signatures = new LPBYTE[ killers_count ];
  144. /* fill the signatures vector */
  145. int i=0;
  146. for(VirusKiller::Set::const_iterator k=killers.begin(), _k=killers.end(); k!=_k; k++)
  147. signatures[ i++ ] = (*k)->Signature();
  148. /* find the longest signature */
  149. int max_signature=0, j;
  150. for(i=0; i<killers_count; i++)
  151. if (signatures[i] && (j=strlen((LPCTSTR)signatures[i]))>max_signature) max_signature=j;
  152. /* scan file for virus signature
  153. Algorithm: Using double buffers (size of m_read_block_size) as a rolling buffer we will 
  154. replace the data with a next loaded buffer as each buffer is no longer required.
  155. */
  156. DWORD base=0; /* base offset of first signature character into rolling buffer */
  157. DWORD offset; /* offset from base of currently comparing character */
  158. DWORD buffer_size=2 * m_read_block_size; /* size of our rolling buffer */
  159. DWORD bytes_read; /* number of bytes read with last read operation */
  160. DWORD prev_bytes_read; /* bytes read with the previous to last read operation */
  161. /* allocate our rolling buffer */
  162. LPBYTE buffer = (LPBYTE)malloc(buffer_size);
  163. /* load the initial double buffers */
  164. if (ReadProcessMemory(hprocess,(LPCVOID)module_base, buffer, (module_length<m_read_block_size? module_length : m_read_block_size), &bytes_read)) {
  165. module_base+=bytes_read;
  166. module_length-=bytes_read;
  167. prev_bytes_read=bytes_read;
  168. }
  169. else
  170. /* process read error */
  171. return VIRUS_ERR;
  172. /* update scan statistics */
  173. m_bytesscanned+=bytes_read;
  174. while(bytes_read > 0) {
  175. /* load the next block (after the current block) */
  176. if (module_length) {
  177. DWORD buffer_load_address=(base+m_read_block_size)%(m_read_block_size*2);
  178. DWORD ibuffer=(base/m_read_block_size+1)%2;
  179. if (!ReadProcessMemory(hprocess,(LPCVOID)module_base, &buffer[ buffer_load_address ], (module_length<m_read_block_size? module_length : m_read_block_size), &bytes_read)) {
  180. /* process memory read error */
  181. return VIRUS_ERR;
  182. }
  183. else
  184. bytes_read=0;
  185. /* search through buffer for a signature match 
  186. */
  187. DWORD to_base = ((base/m_read_block_size)%2)*m_read_block_size + prev_bytes_read;
  188. while ((base < to_base) && !StopPending()) {
  189. /* search for signature match at this base address of the rolling buffer
  190. */
  191. for(i=0,offset=0; i<killers_count; i++,offset=0)
  192. if (signatures[i]) {
  193. /* continue comparing signature character to file character 
  194. until not equal or encountered null in signature */
  195. while ( (signatures[i][offset]) && (signatures[i][offset] == *(buffer + (base+offset)%buffer_size)) )
  196. offset++;
  197. /* if we have reached the end of signature string we have found a match */
  198. if (!signatures[i][offset]) {
  199. int j=0;
  200. /* find the virus killer associated with this sequence */
  201. for(VirusKiller::Set::iterator k=killers.begin(), _k=killers.end(); (k!=_k)&&(j!=i); k++, j++);
  202. /* search should always find associated killer */
  203. ASSERT(j==i);
  204. /* default notification method calls the virus killers clean function */
  205. result|=OnInfectedProcess(hprocess, module, *(*k));
  206. /* set infected flag if killer returned infected */
  207. if (result&(VIRUS_SKIPPED|VIRUS_CLEANED|VIRUS_DELETED|VIRUS_NOTIMPLIMENTED)) 
  208. result|=VIRUS_INFECTED;
  209. /* must return if virus killer terminated process */
  210. if (result&VIRUS_DELETED) return result;
  211. /* we can ignore further occurances of virus sequence */
  212. signatures[i]=NULL;
  213. }
  214. }
  215. /* increase base address of character we are scanning in the rolling buffer */
  216. base++;
  217. }
  218. /* update module base address and length for next process memory read */
  219. module_base+=bytes_read;
  220. module_length-=bytes_read;
  221. prev_bytes_read=bytes_read;
  222. if (base==buffer_size) base=0;
  223. }
  224. /* free our rolling buffer */
  225. free(buffer);
  226. /* free the signature vector */
  227. delete[] signatures;
  228. return result;
  229. }
  230. return VIRUS_SKIPPED;
  231. }
  232. VirusKiller::SCANRESULT CProcessScanner::OnInfectedProcess(HANDLE hprocess, const Module& module, VirusKiller& killer)
  233. {
  234. CString s(CurrentProcessName()), ss;
  235. int brk;
  236. if((brk=s.ReverseFind('\'))!=-1) s=s.Mid(brk+1);
  237. s.MakeLower();
  238. ss.Format("Virus found in memory in process %d '%s',  module %s!", module.processId, s, module.moduleName);
  239. AfxMessageBox(ss);
  240. return killer.Clean(hprocess, module.moduleName, module.baseAddress, module.Length);
  241. }