Anti-Virus

Information about anti-virus and packaged applications.

PowerShell that is packaged as an executable can often trigger anti-virus software after packaged. The use of PowerShell within malicious executables has led to false positives being found in your own packages. This document contains information about anti-virus and PowerShell Pro Tools packaging.

These tests were completed with PowerShell Pro Tools 2021.9.2.

Default Package Detection

The packaging itself will not flag anti-virus for most providers. You will see that if you package an empty PS1 file and upload it to VirusTotal, most AV providers will not flag the executable.

The package settings for this are the default ones provided by the Visual Studio Code extension.

@{
    Root = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package = @{
        Enabled = $true
        Obfuscate = $false
        HideConsoleWindow = $false
        DotNetVersion = 'v4.6.2'
        FileVersion = '1.0.0'
        FileDescription = ''
        ProductName = ''
        ProductVersion = ''
        Copyright = ''
        RequireElevation = $false
        ApplicationIconPath = ''
        PackageType = 'Console'
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}

Custom Script Results

As you can see when we start to include additional PowerShell script, you will begin to see certain AV providers begin to flag the results. This example uses the Clean Windows 10 PowerShell script.

Additionally, we enabled require elevation in the package.psd1 file to ensure that administrator access is allowed to modify the Windows features.

@{
    Root       = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package    = @{
        Enabled             = $true
        Obfuscate           = $false
        HideConsoleWindow   = $false
        DotNetVersion       = 'v4.6.2'
        FileVersion         = '1.0.0'
        FileDescription     = ''
        ProductName         = ''
        ProductVersion      = ''
        Copyright           = ''
        RequireElevation    = $true
        ApplicationIconPath = ''
        PackageType         = 'Console'
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}

This example yields another false positive.

Obfuscation

Obfuscation does not work with PowerShell 7

Obfuscation of the assembly greatly increases the probability of the executable being marked as malicious. We are using the same Windows 10 clean up script but have now enabled obfuscation.

The package.psd1 has been updated to turn on obfuscation.

@{
    Root       = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package    = @{
        Enabled             = $true
        Obfuscate           = $true
        HideConsoleWindow   = $true
        DotNetVersion       = 'v4.6.2'
        FileVersion         = '1.0.0'
        FileDescription     = ''
        ProductName         = ''
        ProductVersion      = ''
        Copyright           = ''
        RequireElevation    = $true
        ApplicationIconPath = ''
        PackageType         = 'Console'
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
        

As you can see, the number of AV vendors to flag the assembly has increased to 10.

Code Signing

While not directly supported within PowerShell Pro Tools, code signing can reduce the number of false positives. Using the same script and package settings as in the obfuscated example, we can use signtool to sign the resulting executable.

signtool sign /f some.pfx /sha1 MYSHA1 /p MYPASSWORD .\text.exe

This results in an executable that is only flagged by 2 vendors.

Modules

Including modules also increases the probability of false positives. In this example, we are packaging the ActiveDirectory module and obfuscating the resulting binary. 12 vendors flag this executable.

Again, signing the binary greatly reduces the number of false positives. Only 3 vendors now flag that same binary.

PowerShell 7

PowerShell 7 executables are packaged differently. Rather than relying on the local PowerShell DLLs, the PowerShell SDK is packaged with the binary. This results in a larger binary but it's completely self-contained.

I've changed the package settings to this. We are using the .NET Core 3.1 SDK and the 7.0.3 PowerShell SDK. This is again packaging the clean up script and the Active Directory module.

@{
    Root       = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package    = @{
        Enabled             = $true
        Obfuscate           = $false
        HideConsoleWindow   = $true
        DotNetVersion       = 'netcoreapp3.1'
        PowerShellVersion   = '7.0.3'
        FileVersion         = '1.0.0'
        FileDescription     = ''
        ProductName         = ''
        ProductVersion      = ''
        Copyright           = ''
        RequireElevation    = $false
        ApplicationIconPath = ''
        PackageType         = 'Console'
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
        

In this example, the package is flagged by 1 AV vendor.

Cmdlet Usage

Certain cmdlets will also cause AV engines to flag. For example, if you use the Set-MpPreference cmdlet within your script, it may flag several vendors. This cmdlet is used for disabling Windows Defender.

Set-MpPreference -DisableRealtimeMonitoring $true

This script was flagged by 8 vendors.

Obfuscating and code signing this same assembly, reduces that number to 2.

Last updated