#175598 - 2007-04-23 09:56 PM
RFC - Antivirus Detection UDF
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
I'm looking for comments/feedback on the following UDF which detects the presence and configuration of several common Anti-Virus products.
It uses a common signature file to perform the tests, allowing a single
UDF to be extensible, supporting other products, and enhancements to
current products, without changing the UDF.
The script below contains some test code, the GetAVI UDF, and a
slightly modified version of fnWMIService. The modification to this
public UDF is simply to accept a pre-authenticated WMI object pointer.
To test, simply save the script and the AVSig.INI file (next post) to
a folder, and run KIX32 AVTEST.KIX. You can specify a remote computer
by adding $COMPUTER="computer" to the command line.
The signature file currently detects products from Symantec, McAfee,
Trend, Panda, and Microsoft. These signatures (other than McAfee) are
not validated, as I don't have access to computers with these products.
I'd like to hear about any issues, and the accuracy of the detections.
I would gladly update the signatures if anyone can provide me with
samples of the product registry settings, and file locations.
I have included a README in the second post for anyone that wishes to
experiment with the signature files.
;; KixGenerated: 2007/04/23 - 15:37:04
Break On
; script to test the WMIGetAVI UDF
; no strict coding standards defined at this stage
Dim $ , $A , $I , $J
$ =SetOption ('WrapAtEOL' , 'On' )
CLS
'This script tests the AntiVirus detection capabilities of the WMIGetAVI UDF.
It simply calls the UDF and displays the number of records and the data that
was returned. The number of records value validates that the AVSig.INI
file was properly read.
The data returned is
0: boolean product detected
1: boolean service running
2: value AV product name, from signature file
3: value name of section in AVSig.INI
Additional values will be returned only if the product is detected, and will
be in the format "Data Name","Data Value", with one value/data pair per
additional array elements. The total number of sub-array elements will vary
depending on the objects defined in the AVSig.INI file.
A computer name can be specified by invoking this script as
KIX32 AVTest.kix $COMPUTER="remotehost"
Press a key to continue:'
Get $
? ?
$A = WMIGetAVI($COMPUTER )
@SERROR ?
UBound ($A ) + 1 ' Records' ?
For $I = 0 to UBound ($A )
' 0: ' If $A [$I ][0 ] 'Installed' Else 'Not Installed' EndIf ?
' 1: ' If $A [$I ][1 ] 'Running' Else 'Not Running' EndIf ?
' 2: ' $A [$I ][2 ] ?
' 3: ' $A [$I ][3 ] ?
For $J = 4 to UBound ($A [$I ])
Right (' ' + $J , 2 ) ': ' $A [$I ][$J ] ?
Next
?
Next
Exit 0
;;
;;======================================================================
;;
;;FUNCTION WMIGetAVI()
;;
;;ACTION Get AVI product info / status / detail
;;
;;AUTHOR Glenn Barnas
;;
;;VERSION 0.0 / 2007/04/20
;;
;;SYNTAX WMIGetAVI([Computer] [, WMIauth])
;;
;;PARAMETERS Computer - OPTIONAL, name of computer to check, default is local computer
;;
;; WMIAuth - OPTIONAL, preauthenticated WMI object pointer
;;
;;REMARKS Checks for the presence of different AV products, returning an array of
;; product IDs, and status values representing the presence and running status
;; of each.
;;
;; Part of the WMI suite because it makes WMI calls and accepts the WMIAuth pointer.
;;
;;RETURNS array of arrays defining AV info - Each element represents one of the AV products
;; defined in the AVSig.ini file, while each sub-array contains the following information:
;; 0: INSTALLED Boolean The product is installed
;; 1: ACTIVE Boolean This product is actively running
;; 2: NAME String Descriptive name of the product
;; 3: PROD_ID String Short name of the product (INI section name)
;; 4: DATA_PAIR String "Description","Value" pair
;; Represents one descriptive setting and it's value. There
;; can be many such elements returned - it is up to the user
;; to determine how many elements are returned and process them.
;;
;; Only elements 0-3 are consistent, elements 4 and up will depend on the AV product
;;
;;DEPENDENCIES AVSig.ini - AntiVirus signature database
;; WMIService -
;;
;;TESTED WITH W2K, WXP, W2K3
;;
;;EXAMPLES
;
Function WMIGetAVI(OPTIONAL $_Computer , OPTIONAL $_pAuth )
Dim $_ , $_T1 , $_T2 , $_I , $_J , $_K ; temp & index vars
Dim $_WComputer ; computer name formatted for WMI queries
Dim $_SigFile ; path/name of signature file
Dim $_aProd , $_Prod ; array of product IDs enumerated from signature file
Dim $_aAVIData [0 ] ; array of AVI data detected
Dim $_aProdData [3 ] ; array of product-specific AVI data
Dim $_Action ; Flag to permit further action
Dim $_aTasks , $_Task ; array of tasks & enumerator var
Dim $_Services ; var holding service name
; Insure computer name is either null or \\host\ format
If $_Computer
$_Computer = '\\' + Join (Split ($_Computer , '\' , 3 ), '' ) + '\'
$_WComputer = Join (Split ($_Computer , '\' , 3 ), '' )
Else
$_WComputer = @WKSTA
EndIf
; Locate the (preferred) Antivirus signature file
$_SigFile = ''
If Exist (@SCRIPTDIR + '\AVSig.ini' )
$_SigFile = @SCRIPTDIR + '\AVSig.ini' ; default AVSig file location
EndIf
; ###
; our environment defines the config file path in the S_CONFIG environment var
; this will not affect general use, and can be removed if desired
If Exist ('%S_CONFIG%\AVSig.ini' )
$_SigFile = '%S_CONFIG%\AVSig.ini' ; preferred AVSig file location, if present
EndIF
; ###
If Not $_SigFile
Exit 2 ; AVSig file not found - exit with status 2
EndIf
; Define the array of Product IDs.
; enumerate the AVI products in the signature file
$_T1 = ReadProfileString ($_SigFile , '' , '' )
$_aProd = Split (Left ($_T1 ,len ($_T1 )-1 ), Chr (10 ))
ReDim $_aAVIData [UBound ($_aProd )]
For $_I = 0 to UBound ($_aProd )
$_Prod = $_aProd [$_I ] ; working product name
ReDim $_aProdData [3 ] ; clear the array
$_aProdData [1 ] = 0 ; default service state
$_aProdData [3 ] = $_Prod ; insert product ID
; enumerate and process the individual signature tasks
$_T1 = ReadProfileString ($_SigFile , $_Prod , '' )
$_aTasks = Split (Left ($_T1 ,len ($_T1 )-1 ), Chr (10 ))
$_Action = 1 ; Allow data collection, assuming product is installed
$_J = 3
For Each $_Task in $_aTasks
Select
; Detect task - determine if the signature is present, quit scanning this product if it is not
Case $_Task = 'Detect'
$_aProdData [0 ] = GetAVI_Detail($_Computer , ReadProfileString ($_SigFile , $_Prod , $_Task ))
If Not $_aProdData [0 ]
$_Action = 0
EndIf
; determine if the service is running
Case $_Task = 'Service' And $_Action
$_Services = Split (ReadProfileString ($_SigFile , $_Prod , $_Task ), '|' )
For $_K = 0 to UBound ($_Services )
$_ = WMIService($_Services [$_K ], 'Name' , $_WComputer , $_pAuth )
If $_ ; see if the service name is valid
$_ = WMIService($_Services [$_K ], 'Started' , $_WComputer , $_pAuth )
If $_ And Not @ERROR
$_aProdData [1 ] = Abs ($_ )
$_K = 999
EndIf ; found data
EndIf ; svc exists
Next
; Return the fixed descriptive name
Case $_Task = 'Name'
$_aProdData [2 ] = ReadProfileString ($_SigFile , $_Prod , $_Task )
; Iformational record - ignore
Case $_Task = 'Info' And $_Action
; This optional record contains information describing the author and date of the AV signature
; process the AVI product-specific definitions
Case $_Action
$_ = ReadProfileString ($_SigFile , $_Prod , $_Task )
; is there a recursive lookup? Only one level of recursion is supported!
; this permits the definition of a INSTALL PATH lookup, and reference
; &INSTALL PATH&\file.ext for FILEDate or FILEVersion lookups
If InStr ($_ , '&' )
$_T1 = Split ($_ , '&' )[1 ] ; get the embedded lookup id
$_T2 = GetAVI_Detail($_Computer , ReadProfileString ($_SigFile , $_Prod , $_T1 ))
$_ = Join (Split ($_ , '&' + $_T1 + '&' ), $_T2 )
EndIf
$_J = $_J + 1
ReDim Preserve $_aProdData [$_J ]
$_aProdData [$_J ] = $_Task + ';' + GetAVI_Detail($_Computer , $_ )
EndSelect
Next
$_aAVIData [$_I ] = $_aProdData
Next
$WMIGetAVI = $_aAVIData ; return array of arrays
Exit 0
EndFunction
Function GetAVI_Detail($_Computer , $_Tasks )
Dim $_ , $_I , $_J , $_K ; temp & index vars
Dim $_Paths ; Paths to query
Dim $_Vals ; values to read
Dim $_Bool , $_BoolVal ; Bool result flag, True response value
Dim $_Result ; result string
; array of METHOD, PATH(s), KEY, RESULT_TYPE
$_Tasks = Split ($_Tasks + ';' , ';' )
$_Bool = InStr ($_Tasks [3 ], 'bool' ) ; Is this a BOOL or VALUE query?
$_BoolVal = IIf ($_Bool <> 0 , $_Tasks [3 ], '' ) ; Does the BOOL have an alternate TRUE response?
$_BoolVal = Split ($_BoolVal , ':' )[1 ]
$_Result = IIf ($_Bool , 0 , '' ) ; set defaults for return to Bool False or empty string
Select
Case $_Tasks [0 ] = 'REG' ; perform registry read
; could have multiple keys to check
$_Paths = Split ($_Tasks [1 ], '|' )
For $_I = 0 to UBound ($_Paths )
; Verify that the key exists
If KeyExist ($_Computer + $_Paths [$_I ])
$_Vals = Split ($_Tasks [2 ], '|' )
For $_K = 0 to UBound ($_Vals )
$_ = ReadValue ($_Computer + $_Paths [$_I ], $_Vals [$_K ])
If $_
$_J = 999 ; got data, stop searching
EndIf
Next
EndIf ; Key Exists
If $_
$_I = 999 ; don't check other paths once a value is obtained
If $_Bool
$_Result = IIf ($_BoolVal <> '' , $_BoolVal , 1 ) ; Return Bool True or Message String
Else
$_Result = $_ ; return the actual value
EndIf ; Bool/Value
EndIF ; $_ has data
Next ; $_I (Paths)
Case Left ($_Tasks [0 ], 4 ) = 'File' ; perform file checks
; could have multiple filepaths to check
$_Paths = Split ($_Tasks [1 ], '|' )
For $_I = 0 to UBound ($_Paths )
; if referencing a remote system, change the ":" to "$" in the path to use admin share
If $_Computer
$_Paths [$_I ] = Join (Split ($_Paths [$_I ], ':' ), '$' )
EndIf
; Verify that the file exists
If Exist ($_Computer + $_Paths [$_I ]) ; file exists
If Right ($_Tasks [0 ], 1 ) = 'X' ; file exist check - return boolean
$_Result = IIf ($_BoolVal <> '' , $_BoolVal , 1 )
$_I = 999 ; stop processing additional filepaths
EndIf
If Right ($_Tasks [0 ], 1 ) = 'V' ; file version check - return version string
$_ = ''
If $_Tasks [2 ] $_ = $_Tasks [2 ] EndIf
$_Result = GetFileVersion ($_Computer + $_Paths [$_I ], $_ )
$_I = 999 ; stop processing additional filepaths
EndIf
If Right ($_Tasks [0 ], 1 ) = 'D' ; file date check - return timestamp
$_Result = GetFileTime ($_Computer + $_Paths [$_I ])
$_I = 999 ; stop processing additional filepaths
EndIf
EndIf ; FielPath Exists
Next ; $_I (Paths)
EndSelect
$GetAVI_Detail = $_Result
Exit 0
EndFunction
;Function: fnWMIService()
;
;Author: Christopher Shilt
; (christopher.shilt@relizon.com)
;
;Version: 1.1
;
;Version History:
; 2005-07-12 : NoVarsInStrings compliant
; 2007-04-02 : GAB - permit use of pre-authenticated object pointer
;
;Action: Uses WMI to execute methods on services.
;
;Syntax: WMIService(SERVICE NAME, METHOD, Optional COMPUTER, Optional ObjPtr)
;
;Parameters:
; SERVICE NAME : Required. Target service name to execute methods against.
;
; METHOD : Required. See remarks for details.
;
; COMPUTER : Optional. Local or Remote WMI enabled target computer.
;
;Remarks:
; See WMI SDK on Win32_Service class for complete documentation:
; http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_service.asp
;
;Returns:
; Queries on properties will return a value as indicated above. Method functions will return a return code
; from the Win32_Service Method Return Value Table.
;
; Note: An error code will only be set if the WMI object is unable to be created. Use the Return Code on
; methods to determine method success/failure.
;
;Dependencies:
; KiX 4.02 (or higher)
; WMI Enabled target computer.
;
; see associated .TXT file for detailed docs and examples
;
Function WMIService($sService , $sMethod , Optional $sComputer , OPTIONAL $pAuth )
Dim $objWMI , $objSrvc , $nul
If Not $sComputer $sComputer = @WKSTA EndIf
; Use pre-authenticated object pointer if provided, otherwise create a new object
If $pAuth
$objWMI = $pAuth
Else
$objWMI = GetObject ("winmgmts:{impersonationLevel=impersonate}!\\" + $sComputer + "\root\cimv2" )
If @ERROR
$WMIService = ''
Exit VAL ("&" + Right (DecToHex (@ERROR ), 4 ))
EndIf
EndIf
$objSrvc = $objWMI .ExecQuery('Select * from Win32_Service WHERE Name = "' + $sService + '"' )
For Each $objSrvc in $objSrvc
$nul = Execute (Chr (36 ) + "WMIService = " + Chr (36 ) + "objSrvc." + $sMethod )
Next
EndFunction
_________________________
Actually I
am a Rocket Scientist!
Top
Moderator: Glenn Barnas , NTDOC , Arend_ , Jochen , Radimus , Allen , ShaneEP , Ruud van Velsen , Mart
1 registered
(Allen )
and 1198 anonymous users online.