From 053dd53d746955467733ccc5db42f4825b8c574f Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Mon, 3 Sep 2018 18:33:17 +0200 Subject: [PATCH 01/19] fix: fix antivirus inventory protocol usage --- lib/FusionInventory/Agent/Inventory.pm | 4 ++-- lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/FusionInventory/Agent/Inventory.pm b/lib/FusionInventory/Agent/Inventory.pm index 2019aebf09..f13cc66fb7 100644 --- a/lib/FusionInventory/Agent/Inventory.pm +++ b/lib/FusionInventory/Agent/Inventory.pm @@ -35,8 +35,8 @@ my %fields = ( ACCESSLOG => [ qw/USERID LOGDATE/ ], ANTIVIRUS => [ qw/COMPANY ENABLED GUID NAME UPTODATE VERSION - DATFILECREATION DATFILEVERSION ENGINEVERSION32 - ENGINEVERSION64/ ], + EXPIRATION BASE_CREATION BASE_VERSION + 32ENGINE_VERSION 64ENGINE_VERSION/ ], BATTERIES => [ qw/CAPACITY CHEMISTRY DATE NAME SERIAL MANUFACTURER VOLTAGE/ ], CONTROLLERS => [ qw/CAPTION DRIVER NAME MANUFACTURER PCICLASS VENDORID diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 2928c4f898..19a2361c54 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -130,9 +130,9 @@ sub _getAntivirusUninstall { sub _getMcAfeeInfo { my %properties = ( - DATFILEVERSION => [ 'AVDatVersion', 'AVDatVersionMinor' ], - ENGINEVERSION32 => [ 'EngineVersion32Major', 'EngineVersion32Minor' ], - ENGINEVERSION64 => [ 'EngineVersionMajor', 'EngineVersionMinor' ], + 'BASE_VERSION' => [ 'AVDatVersion', 'AVDatVersionMinor' ], + '32ENGINE_VERSION' => [ 'EngineVersion32Major', 'EngineVersion32Minor' ], + '64ENGINE_VERSION' => [ 'EngineVersionMajor', 'EngineVersionMinor' ], ); my $regvalues = [ 'AVDatDate', map { @{$_} } values(%properties) ]; From 2c41ef138f59bbfb11e5b690c5b5980985726666 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Mon, 3 Sep 2018 18:42:47 +0200 Subject: [PATCH 02/19] fix: update windows defender parsing Set if windows defender is enabled Add antivirus signarure version support --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 19a2361c54..9fffcea7de 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -64,10 +64,16 @@ sub doInventory { my ($defender) = getWMIObjects( moniker => 'winmgmts://./root/microsoft/windows/defender', class => "MSFT_MpComputerStatus", - properties => [ qw/AMProductVersion AntivirusEnabled/ ] + properties => [ qw/AMProductVersion AntivirusEnabled + AntivirusSignatureVersion/ ] ); - $antivirus->{VERSION} = $defender->{AMProductVersion} - if ($defender && $defender->{AntivirusEnabled} && $defender->{AMProductVersion}); + if ($defender) { + $antivirus->{VERSION} = $defender->{AMProductVersion} + if $defender->{AMProductVersion}; + $antivirus->{ENABLED} = $defender->{AntivirusEnabled} =~ /TRUE/i ? 1 : 0; + $antivirus->{BASE_VERSION} = $defender->{AntivirusSignatureVersion} + if $defender->{AntivirusSignatureVersion}; + } $antivirus->{COMPANY} = "Microsoft Corporation"; } From c6ed6a1abb2450d357f4fa56cedba041b9b8adc8 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Mon, 3 Sep 2018 18:56:47 +0200 Subject: [PATCH 03/19] fix: fix productState analysis Change info source URL Better decide on hex value as simpler Closes #501 --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 9fffcea7de..6887762dd9 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -51,11 +51,11 @@ sub doInventory { }; if ($object->{productState}) { - my $bin = sprintf( "%b\n", $object->{productState}); -# http://blogs.msdn.com/b/alejacma/archive/2008/05/12/how-to-get-antivirus-information-with-wmi-vbscript.aspx?PageIndex=2#comments - if ($bin =~ /(\d)\d{5}(\d)\d{6}(\d)\d{5}$/) { - $antivirus->{UPTODATE} = $1 || $2; - $antivirus->{ENABLED} = $3 ? 0 : 1; + my $hex = dec2hex($object->{productState}); + # See http://neophob.com/2010/03/wmi-query-windows-securitycenter2/ + if ($hex =~ /(.{2})(.{2})$/) { + $antivirus->{UPTODATE} = $2 =~ /^00$/ ? 1 : 0; + $antivirus->{ENABLED} = $1 =~ /^1.$/ ? 1 : 0; } } From 854f644e45f03bbfb8863fe13941cd18987b27f1 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 4 Sep 2018 11:28:33 +0200 Subject: [PATCH 04/19] fix: use clean antivirus name pattern Cleanup antivirus name from localized chars to find the installed one Closes #442 --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 6887762dd9..24c4484cc1 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -110,6 +110,13 @@ sub _getAntivirusUninstall { return unless $name; + # Cleanup name from localized chars to keep a clean regex pattern + my ($pattern) = $name =~ /^([a-zA-Z0-9 ._-]+)/ + or return; + # Escape dot in pattern + $pattern =~ s/\./\\./g; + my $match = qr/^$pattern/i; + my ($regUninstall, $AVRegUninstall); if (is64bit()) { @@ -117,7 +124,7 @@ sub _getAntivirusUninstall { path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Windows/CurrentVersion/Uninstall', ); $AVRegUninstall = first { - $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ /$name/i; + $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; } values(%{$regUninstall}); } @@ -126,7 +133,7 @@ sub _getAntivirusUninstall { path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall', ); $AVRegUninstall = first { - $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ /$name/i; + $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; } values(%{$regUninstall}); } From 252358aa81c58b654308067d19569b8faee5e2e5 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 4 Sep 2018 11:50:15 +0200 Subject: [PATCH 05/19] fix: fix condition test --- lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 24c4484cc1..95bf627681 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -178,7 +178,7 @@ sub _getMcAfeeInfo { my $major = $macafeeReg->{'/' . $keys->[0]}; my $minor = $macafeeReg->{'/' . $keys->[1]}; $info->{$property} = sprintf("%04d.%04d", hex2dec($major), hex2dec($minor)) - if defined $major && defined $major; + if defined $major && defined $minor; } # file creation date property From aa17e5f94ad325f225c9bb5546ddea289a0a2d88 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 4 Sep 2018 12:00:31 +0200 Subject: [PATCH 06/19] perf: optimization for remote wmi task Only retrieve useful fields when parsing software uninstall registry keys remotely --- lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 95bf627681..f7f237721b 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -122,6 +122,9 @@ sub _getAntivirusUninstall { if (is64bit()) { $regUninstall = getRegistryKey( path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Windows/CurrentVersion/Uninstall', + wmiopts => { # Only used for remote WMI optimization + values => [ 'DisplayName', 'DisplayVersion', 'Publisher' ] + } ); $AVRegUninstall = first { $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; @@ -131,6 +134,9 @@ sub _getAntivirusUninstall { if (!$AVRegUninstall) { $regUninstall = getRegistryKey( path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall', + wmiopts => { # Only used for remote WMI optimization + values => [ 'DisplayName', 'DisplayVersion', 'Publisher' ] + } ); $AVRegUninstall = first { $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; From 8d452a085e22db7ef10c181b8e8ac83af44fda87 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 4 Sep 2018 12:02:40 +0200 Subject: [PATCH 07/19] refactor: remove dead code --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index f7f237721b..449af923f3 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -154,7 +154,7 @@ sub _getMcAfeeInfo { '64ENGINE_VERSION' => [ 'EngineVersionMajor', 'EngineVersionMinor' ], ); - my $regvalues = [ 'AVDatDate', map { @{$_} } values(%properties) ]; + my $regvalues = [ map { @{$_} } values(%properties) ]; my ($info, $macafeeReg); @@ -187,16 +187,6 @@ sub _getMcAfeeInfo { if defined $major && defined $minor; } - # file creation date property - if ($macafeeReg->{'/AVDatDate'}) { - my $datFileCreation = encodeFromRegistry($macafeeReg->{'/AVDatDate'}); - # from YYYY/MM/DD to DD/MM/YYYY - if ($datFileCreation =~ /(\d\d\d\d)\/(\d\d)\/(\d\d)/) { - $datFileCreation = join( '/', ($3, $2, $1) ); - } - $info->{DATFILECREATION} = $datFileCreation; - } - return $info; } From 3fbcfa0d458e61e5662a198a020d4cf47b7f105e Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 4 Sep 2018 13:00:03 +0200 Subject: [PATCH 08/19] refactor: factorized code in _getSoftwareRegistryKeys --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 91 +++++++++---------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 449af923f3..35720bf4b5 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -117,33 +117,16 @@ sub _getAntivirusUninstall { $pattern =~ s/\./\\./g; my $match = qr/^$pattern/i; - my ($regUninstall, $AVRegUninstall); - - if (is64bit()) { - $regUninstall = getRegistryKey( - path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Windows/CurrentVersion/Uninstall', - wmiopts => { # Only used for remote WMI optimization - values => [ 'DisplayName', 'DisplayVersion', 'Publisher' ] - } - ); - $AVRegUninstall = first { - $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; - } values(%{$regUninstall}); - } - - if (!$AVRegUninstall) { - $regUninstall = getRegistryKey( - path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall', - wmiopts => { # Only used for remote WMI optimization - values => [ 'DisplayName', 'DisplayVersion', 'Publisher' ] - } - ); - $AVRegUninstall = first { - $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; - } values(%{$regUninstall}); - } - - return $AVRegUninstall; + return _getSoftwareRegistryKeys( + 'Microsoft/Windows/CurrentVersion/Uninstall', + [ 'DisplayName', 'DisplayVersion', 'Publisher' ], + sub { + my ($registry) = @_; + return first { + $_->{"/DisplayName"} && $_->{"/DisplayName"} =~ $match; + } values(%{$registry}); + } + ); } sub _getMcAfeeInfo { @@ -156,28 +139,10 @@ sub _getMcAfeeInfo { my $regvalues = [ map { @{$_} } values(%properties) ]; - my ($info, $macafeeReg); - - if (is64bit()) { - $macafeeReg = getRegistryKey( - path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/McAfee/AVEngine', - wmiopts => { # Only used for remote WMI optimization - values => $regvalues - } - ); - } - - if (!$macafeeReg) { - $macafeeReg = getRegistryKey( - path => 'HKEY_LOCAL_MACHINE/SOFTWARE/McAfee/AVEngine', - wmiopts => { # Only used for remote WMI optimization - values => $regvalues - } - ); - } - - return unless $macafeeReg; + my $macafeeReg = _getSoftwareRegistryKeys('McAfee/AVEngine', $regvalues) + or return; + my $info = {}; # major.minor versions properties foreach my $property (keys %properties) { my $keys = $properties{$property}; @@ -190,4 +155,34 @@ sub _getMcAfeeInfo { return $info; } +sub _getSoftwareRegistryKeys { + my ($base, $values, $callback) = @_; + + my $reg; + if (is64bit()) { + $reg = getRegistryKey( + path => 'HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/'.$base, + wmiopts => { # Only used for remote WMI optimization + values => $values + } + ); + if ($reg) { + if ($callback) { + my $filter = &{$callback}($reg); + return $filter if $filter; + } else { + return $reg; + } + } + } + + $reg = getRegistryKey( + path => 'HKEY_LOCAL_MACHINE/SOFTWARE/'.$base, + wmiopts => { # Only used for remote WMI optimization + values => $values + } + ); + return $callback ? &{$callback}($reg) : $reg; +} + 1; From 3695171bde2fa889372949594a6c2631d1ed976e Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 4 Sep 2018 13:02:48 +0200 Subject: [PATCH 09/19] fix: safely handles regex matches Avoid 'ENABLED' first match undefined by new regex --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 35720bf4b5..8c97058805 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -53,9 +53,10 @@ sub doInventory { if ($object->{productState}) { my $hex = dec2hex($object->{productState}); # See http://neophob.com/2010/03/wmi-query-windows-securitycenter2/ - if ($hex =~ /(.{2})(.{2})$/) { - $antivirus->{UPTODATE} = $2 =~ /^00$/ ? 1 : 0; - $antivirus->{ENABLED} = $1 =~ /^1.$/ ? 1 : 0; + my ($enabled, $uptodate) = $hex =~ /(.{2})(.{2})$/; + if (defined($enabled) && defined($uptodate)) { + $antivirus->{ENABLED} = $enabled =~ /^1.$/ ? 1 : 0; + $antivirus->{UPTODATE} = $uptodate =~ /^00$/ ? 1 : 0; } } From a16ea9e47d5a1cbfde302cd10047db41dd6c3565 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 08:35:22 +0200 Subject: [PATCH 10/19] refactor: don't try callback with undef argument --- lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 8c97058805..e4ac1b2255 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -183,7 +183,7 @@ sub _getSoftwareRegistryKeys { values => $values } ); - return $callback ? &{$callback}($reg) : $reg; + return ($callback && $reg) ? &{$callback}($reg) : $reg; } 1; From 2161f7fc372374888ed45a7a8700c9b11baeb1af Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 10:24:12 +0200 Subject: [PATCH 11/19] feature: add kaspersky antivirus support Refacto dedicated antivirus method to directly update the antivirus hash Set Kaspersky base version to last update date in the YYYYMMDD format Set Kaspersky expiration date if possible --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index e4ac1b2255..8d5c6ae372 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -92,10 +92,11 @@ sub doInventory { # avoid duplicates next if $seen->{$antivirus->{NAME}}->{$antivirus->{VERSION}||'_undef_'}++; - # McAfee data + # Check for other product datas for update if ($antivirus->{NAME} =~ /McAfee/i) { - my $info = _getMcAfeeInfo(); - $antivirus->{$_} = $info->{$_} foreach keys %$info; + _setMcAfeeInfos($antivirus); + } elsif ($antivirus->{NAME} =~ /Kaspersky/i) { + _setKasperskyInfos($antivirus); } $inventory->addEntry( @@ -130,7 +131,8 @@ sub _getAntivirusUninstall { ); } -sub _getMcAfeeInfo { +sub _setMcAfeeInfos { + my ($antivirus) = @_; my %properties = ( 'BASE_VERSION' => [ 'AVDatVersion', 'AVDatVersionMinor' ], @@ -143,17 +145,47 @@ sub _getMcAfeeInfo { my $macafeeReg = _getSoftwareRegistryKeys('McAfee/AVEngine', $regvalues) or return; - my $info = {}; # major.minor versions properties foreach my $property (keys %properties) { my $keys = $properties{$property}; my $major = $macafeeReg->{'/' . $keys->[0]}; my $minor = $macafeeReg->{'/' . $keys->[1]}; - $info->{$property} = sprintf("%04d.%04d", hex2dec($major), hex2dec($minor)) + $antivirus->{$property} = sprintf("%04d.%04d", hex2dec($major), hex2dec($minor)) if defined $major && defined $minor; } +} + +sub _setKasperskyInfos { + my ($antivirus) = @_; + + my $regvalues = [ qw(LastSuccessfulUpdate LicKeyType LicDaysTillExpiration) ]; + + my $kasperskyReg = _getSoftwareRegistryKeys('KasperskyLab\protected', $regvalues) + or return; - return $info; + my $found = first { + $_->{"Data/"} && $_->{"Data/"}->{"/LastSuccessfulUpdate"} + } values(%{$kasperskyReg}); + + if ($found) { + my $lastupdate = hex2dec($found->{"Data/"}->{"/LastSuccessfulUpdate"}); + if ($lastupdate && $lastupdate != 0xFFFFFFFF) { + my @date = localtime($lastupdate); + # Format BASE_VERSION as YYYYMMDD + $antivirus->{BASE_VERSION} = sprintf( + "%04d%02d%02d",$date[5]+1900,$date[4]+1,$date[3]); + } + # Set expiration date only if we found a licence key type + my $keytype = hex2dec($found->{"Data/"}->{"/LicKeyType"}); + if ($keytype) { + my $expiration = hex2dec($found->{"Data/"}->{"/LicDaysTillExpiration"}); + if (defined($expiration)) { + my @date = localtime(time+86400*$expiration); + $antivirus->{EXPIRATION} = sprintf( + "%02d/%02d/%04d",$date[3],$date[4]+1,$date[5]+1900); + } + } + } } sub _getSoftwareRegistryKeys { From c03df1780fbaa32775d242ea8b4aef114bf1d10c Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 12:17:04 +0200 Subject: [PATCH 12/19] feature: add ESET antivirus support Set ESET base version --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 8d5c6ae372..1e375e37a3 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -97,6 +97,8 @@ sub doInventory { _setMcAfeeInfos($antivirus); } elsif ($antivirus->{NAME} =~ /Kaspersky/i) { _setKasperskyInfos($antivirus); + } elsif ($antivirus->{NAME} =~ /ESET/i) { + _setESETInfos($antivirus); } $inventory->addEntry( @@ -188,6 +190,24 @@ sub _setKasperskyInfos { } } +sub _setESETInfos { + my ($antivirus) = @_; + + my $esetReg = _getSoftwareRegistryKeys( + 'ESET\ESET Security\CurrentVersion\Info', + [ qw(ProductVersion ScannerVersion) ] + ); + return unless $esetReg; + + unless ($antivirus->{VERSION}) { + $antivirus->{VERSION} = $esetReg->{"/ProductVersion"} + if $esetReg->{"/ProductVersion"}; + } + + $antivirus->{BASE_VERSION} = $esetReg->{"/ScannerVersion"} + if $esetReg->{"/ScannerVersion"}; +} + sub _getSoftwareRegistryKeys { my ($base, $values, $callback) = @_; From d4e3c34fe3abc6fc21ae0fe6f0328d8133c32c91 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 14:28:46 +0200 Subject: [PATCH 13/19] feature: add Avira antivirus support Set Avira base version Set Avira Expiration date --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 1e375e37a3..7c7dc489d1 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -99,6 +99,8 @@ sub doInventory { _setKasperskyInfos($antivirus); } elsif ($antivirus->{NAME} =~ /ESET/i) { _setESETInfos($antivirus); + } elsif ($antivirus->{NAME} =~ /Avira/i) { + _setAviraInfos($antivirus); } $inventory->addEntry( @@ -208,6 +210,38 @@ sub _setESETInfos { if $esetReg->{"/ScannerVersion"}; } +sub _setAviraInfos { + my ($antivirus) = @_; + + my ($aviraInfos) = getWMIObjects( + moniker => 'winmgmts://./root/CIMV2/Applications/Avira_AntiVir', + class => "License_Info", + properties => [ qw/License_Expiration/ ] + ); + if($aviraInfos && $aviraInfos->{License_Expiration}) { + my ($expiration) = $aviraInfos->{License_Expiration} =~ /^(\d+\.\d+\.\d+)/; + if ($expiration) { + $expiration =~ s/\./\//g; + $antivirus->{EXPIRATION} = $expiration; + } + } + + ($aviraInfos) = getWMIObjects( + moniker => 'winmgmts://./root/CIMV2/Applications/Avira_AntiVir', + class => "Product_Info", + properties => [ qw/Product_Version VDF_Version/ ] + ); + return unless $aviraInfos; + + unless ($antivirus->{VERSION}) { + $antivirus->{VERSION} = $aviraInfos->{"Product_Version"} + if $aviraInfos->{"Product_Version"}; + } + + $antivirus->{BASE_VERSION} = $aviraInfos->{"VDF_Version"} + if $aviraInfos->{"VDF_Version"}; +} + sub _getSoftwareRegistryKeys { my ($base, $values, $callback) = @_; From 28dccd8addefff02684ccf2f8ad4237239d6b659 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 16:57:10 +0200 Subject: [PATCH 14/19] feature: update Avira antivirus support Set Avira base version from registry --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 7c7dc489d1..138fe881da 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -226,20 +226,14 @@ sub _setAviraInfos { } } - ($aviraInfos) = getWMIObjects( - moniker => 'winmgmts://./root/CIMV2/Applications/Avira_AntiVir', - class => "Product_Info", - properties => [ qw/Product_Version VDF_Version/ ] + my $aviraReg = _getSoftwareRegistryKeys( + 'Avira/Antivirus', + [ qw(VdfVersion) ] ); - return unless $aviraInfos; - - unless ($antivirus->{VERSION}) { - $antivirus->{VERSION} = $aviraInfos->{"Product_Version"} - if $aviraInfos->{"Product_Version"}; - } + return unless $aviraReg; - $antivirus->{BASE_VERSION} = $aviraInfos->{"VDF_Version"} - if $aviraInfos->{"VDF_Version"}; + $antivirus->{BASE_VERSION} = $aviraReg->{"/VdfVersion"} + if $aviraReg->{"/VdfVersion"}; } sub _getSoftwareRegistryKeys { From 1d1cb59e3ec0c80e3cf8d2e42345935a224f25e6 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 18:03:09 +0200 Subject: [PATCH 15/19] feature: update windows defender support Also try to set base version from registry --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 138fe881da..b526db2380 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -76,6 +76,15 @@ sub doInventory { if $defender->{AntivirusSignatureVersion}; } $antivirus->{COMPANY} = "Microsoft Corporation"; + # Finally try registry for base version + if (!$antivirus->{BASE_VERSION}) { + $defender = _getSoftwareRegistryKeys( + 'Microsoft/Windows Defender/Signature Updates', + [ 'AVSignatureVersion' ] + ); + $antivirus->{BASE_VERSION} = $defender->{'/AVSignatureVersion'} + if $defender && $defender->{'/AVSignatureVersion'}; + } } # Finally try to get version from software installation in registry From e0c6d2b858c9427fb1687d51d43cad6b0cbad21d Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 18:21:33 +0200 Subject: [PATCH 16/19] feature: add microsoft security essentials support Get base version from registry --- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index b526db2380..78de146251 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -110,6 +110,8 @@ sub doInventory { _setESETInfos($antivirus); } elsif ($antivirus->{NAME} =~ /Avira/i) { _setAviraInfos($antivirus); + } elsif ($antivirus->{NAME} =~ /Security Essentials/i) { + _setMSEssentialsInfos($antivirus); } $inventory->addEntry( @@ -245,6 +247,19 @@ sub _setAviraInfos { if $aviraReg->{"/VdfVersion"}; } +sub _setMSEssentialsInfos { + my ($antivirus) = @_; + + my $mseReg = _getSoftwareRegistryKeys( + 'Microsoft\Microsoft Antimalware\Signature Updates', + [ 'AVSignatureVersion' ] + ); + return unless $mseReg; + + $antivirus->{BASE_VERSION} = $mseReg->{"/AVSignatureVersion"} + if $mseReg->{"/AVSignatureVersion"}; +} + sub _getSoftwareRegistryKeys { my ($base, $values, $callback) = @_; From 57329e110e2d70bf4bf8df2c24917300c1a65df3 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Wed, 5 Sep 2018 18:57:15 +0200 Subject: [PATCH 17/19] doc: update changes --- Changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes b/Changes index e6031dc36e..07fa49e240 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,12 @@ Revision history for FusionInventory agent inventory: * Fix physical memory error correction detection via WMI under win32 * Fix #299: Added UWP/APPX/Windows Store software inventory +* win32 antivirus detection enhanced support: + - add support for few antivirus base versions (defender, kaspersky, + EST, avira, MSE, McAfee) + - try to set license expiration date for kaspersky & avira +* Fix #442: kaspersky not fully recognized in russia +* Fix #501: wrong status was reported when windows defender was disabled deploy: * Bump Deploy task version to 2.7 From dc3abbb5835e3bbe34709e01325b00569c3a9386 Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Thu, 6 Sep 2018 15:45:23 +0200 Subject: [PATCH 18/19] fix: AntivirusEnabled from defender is still a boolean --- lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index 78de146251..f49490873b 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -71,7 +71,8 @@ sub doInventory { if ($defender) { $antivirus->{VERSION} = $defender->{AMProductVersion} if $defender->{AMProductVersion}; - $antivirus->{ENABLED} = $defender->{AntivirusEnabled} =~ /TRUE/i ? 1 : 0; + $antivirus->{ENABLED} = $defender->{AntivirusEnabled} + if (defined($defender->{AntivirusEnabled})); $antivirus->{BASE_VERSION} = $defender->{AntivirusSignatureVersion} if $defender->{AntivirusSignatureVersion}; } From c2457de0288f6f77ce4dc19040065c475fcfa44e Mon Sep 17 00:00:00 2001 From: Guillaume Bougard Date: Tue, 11 Sep 2018 19:26:24 +0200 Subject: [PATCH 19/19] feature: add F-Secure support Set F-Secure base version to aquarius base version Set F-Secure Expiration date --- Changes | 4 +- .../Agent/Task/Inventory/Win32/AntiVirus.pm | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 07fa49e240..e7aba016cc 100644 --- a/Changes +++ b/Changes @@ -7,8 +7,8 @@ inventory: * Fix #299: Added UWP/APPX/Windows Store software inventory * win32 antivirus detection enhanced support: - add support for few antivirus base versions (defender, kaspersky, - EST, avira, MSE, McAfee) - - try to set license expiration date for kaspersky & avira + EST, avira, MSE, McAfee, F-Secure) + - try to set license expiration date for F-Secure, kaspersky & avira * Fix #442: kaspersky not fully recognized in russia * Fix #501: wrong status was reported when windows defender was disabled diff --git a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm index f49490873b..6d53e9976a 100644 --- a/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm +++ b/lib/FusionInventory/Agent/Task/Inventory/Win32/AntiVirus.pm @@ -5,6 +5,8 @@ use warnings; use parent 'FusionInventory::Agent::Task::Inventory::Module'; +use UNIVERSAL::require; + use FusionInventory::Agent::Tools; use FusionInventory::Agent::Tools::Win32; @@ -113,6 +115,8 @@ sub doInventory { _setAviraInfos($antivirus); } elsif ($antivirus->{NAME} =~ /Security Essentials/i) { _setMSEssentialsInfos($antivirus); + } elsif ($antivirus->{NAME} =~ /F-Secure/i) { + _setFSecureInfos($antivirus); } $inventory->addEntry( @@ -261,6 +265,58 @@ sub _setMSEssentialsInfos { if $mseReg->{"/AVSignatureVersion"}; } +sub _setFSecureInfos { + my ($antivirus) = @_; + + my $fsecReg = _getSoftwareRegistryKeys( + 'F-Secure\Ultralight\Updates\aquarius', + [ qw(file_set_visible_version) ] + ); + return unless $fsecReg; + + my $found = first { $_->{"/file_set_visible_version"} } values(%{$fsecReg}); + + $antivirus->{BASE_VERSION} = $found->{"/file_set_visible_version"} + if $found->{"/file_set_visible_version"}; + + # Try to find license "expiry_date" from a specific json file + $fsecReg = _getSoftwareRegistryKeys( + 'F-Secure\CCF\DLLHoster\100\Plugins\CosmosService', + [ qw(DataPath) ] + ); + return unless $fsecReg; + + my $path = $fsecReg->{"/DataPath"}; + return unless $path && -d $path; + + # This is the full path for the expected json file + $path .= "\\safe.S-1-5-18.local.cosmos"; + return unless -f $path; + + my $infos = getAllLines(file => $path); + return unless $infos; + + JSON::PP->require(); + my @licenses; + eval { + $infos = JSON::PP::decode_json($infos); + @licenses = @{$infos->{local}->{windows}->{secl}->{subscription}->{license_table}}; + }; + return unless @licenses; + + my $expiry_date; + # In the case more than one license is found, assume we need the one with appid=2 + foreach my $license (@licenses) { + $expiry_date = $license->{expiry_date} + if $license->{expiry_date}; + last if $expiry_date && $license->{appid} && $license->{appid} == 2; + } + return unless $expiry_date; + + my @date = localtime($expiry_date); + $antivirus->{EXPIRATION} = sprintf("%02d/%02d/%04d",$date[3],$date[4]+1,$date[5]+1900); +} + sub _getSoftwareRegistryKeys { my ($base, $values, $callback) = @_;