Jouons un peu avec McAfee (et Powershell)

Euh non, on ne va pas jouer avec John McAfee lui-même (range cette arme, John), mais plutôt avec l’antivirus qui l’a rendu célèbre – et qu’il a qualifié de « pire logiciel du monde » soit dit en passant (si ça peut te rassurer John, j’en connais d’autre des bien pires !). Bref, vous vous en doutez, cet article s’adresse principalement à ceux qui, comme moi au boulot, ont McAfee Viruscan pour les protéger contre les vilains virus et autres malwares…

Comme la plupart des antivirus, McAfee Viruscan (on va dire McAfee par la suite, c’est plus simple) utilise une base de signatures virales pour identifier les menaces qui arrivent sur nos PC. Cette base se met à jour régulièrement (en général une fois par jour). Nous allons commencer par tout d’abord identifier quelle version du moteur d’analyse et de cette base de signatures est actuellement installée sur notre machine. Pour cela, lançons Powershell (ISE) et tapons joyeusement les lignes ci-dessous :

$OS=Get-WmiObject -Class Win32_OperatingSystem -ErrorAction silentlycontinue
$OSarchi=$OS.OSarchitecture

if($OSarchi -eq "32 bits")
{
    $engkey="\SOFTWARE\McAfee\AVEngine"
    $prodkey="\SOFTWARE\McAfee\DesktopProtection"
}
elseif($OSarchi -eq "64 bits")
{
    $engkey="\SOFTWARE\Wow6432Node\McAfee\AVEngine"
    $prodkey="\SOFTWARE\Wow6432Node\McAfee\DesktopProtection"
}    
    
if($mcafeeprod = Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE$prodkey -ErrorAction SilentlyContinue)
{
    $prodver=$mcafeeprod.szProductVer
    Write-Host "Product version : $prodver"
}

if($mcafee = Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE$engkey -ErrorAction SilentlyContinue)
{
    $engver=$mcafee.EngineVersionMajor
    $engvermin=$mcafee.EngineVersionMinor
    $datver=$mcafee.AVDatVersion
    $datvermin=$mcafee.AVDatVersionMinor
    $datdate=$mcafee.AVDatDate
    Write-Host "Engine version : $engver.$engvermin"
    Write-Host "AV DAT version : $datver.$datvermin"
    Write-Host "AV DAT date : $datdate"
}

Décryptons ce charabia : au tout début, nous faisons une petite requête WMI afin de savoir si Windows est en 32 ou 64 bits, car en fonction, nous n’allons pas lire les mêmes clés de registre. Une fois que c’est fait, nous définissons le chemin de ces clés (qui sont dans la ruche HKEY_LOCAL_MACHINE) dans les variables $prodkey (chemin vers la version du produit) et $engkey (chemin vers la version du moteur), puis nous lisons les valeurs situées sous ces clés. Ainsi, pour la version de McAfee (Viruscan), c’est la valeur szProductVer qui nous intéresse. Pour la version du moteur, nous concaténons les valeurs EngineVersionMajor et EngineVersionMinor, pour celle de la base de signature, nous concaténons AVDatVersion et AVDatVersionMinor (qui est à ma connaissance toujours égale à zéro, je n’ai encore jamais vu autre chose), et enfin pour la date de la base de signatures,  la valeur AVDatDate.

C’est déjà bien d’avoir ces versions et cette date, mais cela ne nous dit pas si notre antivirus est à jour (à la limite, la date est un bon indicateur, mais qui sait, peut-être qu’une nouvelle signature est déjà disponible…). Pour cela, nous allons récupérer un fichier .INI chez l’éditeur, qui a gardé son ancien nom de domaine nai.com soit dit passant (Network Associates Inc., qui a depuis repris le nom de McAfee. C’est compliqué comme histoire, et à la limite on s’en fout pas mal). Ce fichier .ini ressemble à ceci :

[AVV-ZIP]
DATVersion=8536
FileName=avvdat-8536.zip
FilePath=/current/VSCANDAT1000/DAT/0000/
FileSize=119392660
MD5=0b45ca038a8b97eae64f3ca7f4c6a911

[AVV-MD5]
76412eeeab66c8488a804a243121e6ed avvclean.dat
62ceab424942b3497420f632db1c2aaf avvnames.dat
88863cb8c5ba07db0a1743219e3b5627 avvscan.dat

...etc etc...

Ce qui nous intéresse dans ce fichier, c’est d’abord la section [AVV-ZIP] et la valeur de DATVersion (ici 8536) en particulier. Seulement, même s’il y a des chances que cette valeur soit toujours à la deuxième ligne de ce fichier, rien n’est sûr en informatique, et il vaut mieux parser proprement un fichier à la recherche d’une information que de penser qu’elle se trouvera encore au même endroit demain, ou dans six mois, un an, dix ans, allez savoir. Pour cela, nous allons donc écrire un petit parser de fichier .ini, et comme je suis assez feignant, je ne l’ai pas écrit moi-même (je l’ai trouvé ici et l’ai adapté, car la fonction d’origine nécessite que le fichier .ini soit sur le disque).

function Get-IniContent ($content)
{
    # permet de parser le contenu d'un INI
    $ini = @{}
    switch -regex($content)
    {
        “^\[(.+)\]” # Section
        {
            $section = $matches[1]
            $ini[$section] = @{}
            $CommentCount = 0
        }
        “^(;.*)$” # Commentaire
        {
            $value = $matches[1]
            $CommentCount = $CommentCount + 1
            $name = “Comment” + $CommentCount
            $ini[$section][$name] = $value
        }
        “(.+?)\s*=(.*)” # Valeur
        {
            $name,$value = $matches[1..2]
            $ini[$section][$name] = $value
        }
    }
    return $ini
}

Comme vous le voyez, il s’agit d’une fonction. Celle-ci attend qu’on lui envoie le contenu du fichier .ini en paramètre. Ensuite, elle applique une bonne vieille regex (expression régulière) pour déterminer si la ligne lue est une section, un commentaire ou une valeur. Elle crée enfin un tableau associatif (à deux dimensions) qu’on pourra relire facilement, en précisant la section et la valeur que l’on souhaite récupérer.

Pour avoir le contenu, c’est simple, on télécharge le fichier .ini, on met son contenu dans une variable, et zou on envoie tout ça à la fonction Get-IniContent. Ensuite, on récupère donc la valeur DATVersion de la section [AVV-ZIP] dans notre variable $latestdatver :

$Url = "http://update.nai.com/Products/CommonUpdater/avvdat.ini"
try
{
    $latest=Invoke-WebRequest -Uri $url
    $toto=Get-IniContent($latest)
    $latestdatver = $toto[“AVV-ZIP”][“DATVersion”]
}
catch
{
    Write-Warning "Impossible de vérifier la version du DAT sur le site de McAfee !"
    $latestdatver=0
}

Et si jamais ça foire (parce qu’on n’a pas accès à internet), on gère le problème avec un bon vieux try…catch.

Ainsi, nous savons quelle est la dernière version en ligne de la base antivirale (dans $latestdatver) et celle que nous avons actuellement sur notre machine ($datver). Il suffit donc de les comparer : si $datver est inférieure (-lt, c’est-à-dire « less than ») à $latestdatver, et bien corrigeons cela tout de suite en demandant à McAfee de se mettre à jour !

if($datver -lt $latestdatver)
{
    Write-Warning "La version actuelle ($datver) du DAT est inférieure à la version en ligne ($latestdatver), lancement de la mise à jour..."
    $mcupdate = Start-Process "C:\Program Files (x86)\McAfee\VirusScan Enterprise\mcupdate" -ArgumentList "/update" -wait -NoNewWindow -PassThru
    # on peut attendre avec $mcupdate.HasExited si on n'a que ça à faire (true ou false)
    if($mcupdate.ExitCode -eq 0) # 0 si tout va bien
    {
        Write-Host "La mise à jour est terminée"
    }
    else
    {
        Write-Error "Erreur durant la mise à jour !"
    }
}
else
{
    Write-Host "La version actuelle ($datver) du DAT est égale à la version en ligne ($latestdatver), c'est cool Raoul"
}

Et comment lance-t-on la mise à jour ? Et bien tout simplement en exécutant l’utilitaire mcupdate.exe et en le lui demandant gentiment à l’aide d’arguments bien sentis (/update en l’occurance. Vous pouvez ajouter /quiet si vous ne voulez pas de la fenêtre de progression qui s’affiche). Si le code de retour est 0, ça veut dire que mcupdate.exe s’est bien exécuté, mais pas forcément qu’il a réellement fait la mise à jour (ça a très bien pu foirer). Dans ce cas, il suffit de relire les clés de registre et de voir si $datver est désormais égale (-eq) à $latestdatver. Si ce n’est pas le cas, et bien on peut recommencer, ou faire ce que vous voulez, je vous laisse jouer un peu…

Au passage, si votre ordinateur est gérée de manière centralisée par un serveur ePO (McAfee ePolicy Orchestrator), mcupdate.exe ira télécharger ses signatures sur celui-ci, et pas sur internet. Donc si le serveur ePO n’est pas lui-même à jour, vous n’aurez donc pas la dernière signature disponible…

Pour finir cet article, un petit bout de code pour lister l’état et le type de démarrage de tous les services McAfee :

# Etat des services McAfee
$mcafeeservices=Get-Service | Where displayname -like "McAfee*" | Sort-Object DisplayName
foreach($service in $mcafeeservices)
{
     $srvinfo=Get-Service -name $service.Name
     Write-Host "$($srvinfo.DisplayName) [$($srvinfo.ServiceName)] - Etat : $($srvinfo.Status) -    Démarrage : $($srvinfo.StartType)"
}

Rien de sorcier, on récupère la liste des services dont le nom commence par McAfee, et on les trie dans l’ordre alphabétique. Ensuite, pour chaque service, on récupère ses propriétés DisplayName (nom d’affichage), ServiceName (le nom court), Status (son état, s’il est démarré, en pause ou arrêté, ce qui peut s’avérer fâcheux selon le cas) et StartType (le type de démarrage, à savoir automatique, manuel ou désactivé, ce qui peut s’avérer aussi fâcheux selon le cas). A vous d’ajouter la gestion des avertissements si un service critique est arrêté ou désactivé par exemple.

Voilà, c’étaient mes petites astuces (qui m’ont servi au boulot) concernant McAfee. Sur ce, portez-vous bien et tchüss !

 

Montre ton amour pour Dédé en partageant cet article !

Laisser un commentaire