Windows 10 Windows 10 Powershell based virus detector

Discussion in 'Programming and Scripting' started by Neemobeer, Mar 11, 2016.

  1. Neemobeer

    Neemobeer Windows Forum Team
    Staff Member

    Joined:
    Jul 4, 2015
    Messages:
    2,412
    Likes Received:
    366
    Here's a neat script I put together today. If added as a scheduled task it will loop and monitor running processes. The only thing needed is to sign up for an account on virustotal.com to get an API key then replace the F's with your api key
    Function Get-ProcessReport([string]$FilePath, [string]$Hash)
    {
    Get-VirusTotalReport -Hash $hash -Apikey FFFFFFFFFFFFFFFFFFF
    }

    The script scans through all running processes, detects and ignores any trusted signed binaries. It then generates a hash of any unsigned process and pulls a report from virustotal.com and if there are more than 4 indicators it saves the hash in a blacklist file. Any process that passes virustotal has it's hash saved in the whitelist file.

    When a process is blacklisted or fails the virus total check the script will kill the process.

    Enjoy.

    Code:
    # Process_Bouncer.ps1
    $main_conf_dir="$env:ProgramData\Malwark\Process_Bouncer"
    $log_file="$main_conf_dir\action.log"
    $white_file="$main_conf_dir\whitelist"
    $black_file="$main_conf_dir\blacklist"
    
    Function New-Configuration
    {
        If (-Not (Test-Path $main_conf_dir))
        {
            New-Item -Path $main_conf_dir -ItemType Directory
        }
        If (-Not (Test-Path $log_file))
        {
            New-Item -Path $log_file -ItemType File
        }
        If (-Not (Test-Path $white_file))
        {
            New-Item -Path $white_file -ItemType File
        }
        If (-Not (Test-Path $black_file))
        {
            New-Item -Path $black_file -ItemType File
        }
    }
    
    Function Create-NotificationBallon([string]$Message, [string]$Title)
    {
        [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    
        $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
    
        $objNotifyIcon.Icon = "C:\Windows\ProgressError.ico"
        $objNotifyIcon.BalloonTipIcon = "Error"
        $objNotifyIcon.BalloonTipText = "$Message"
        $objNotifyIcon.BalloonTipTitle = "$Title"
        $objNotifyIcon.Visible = $True
        $objNotifyIcon.ShowBalloonTip(5000)
    }
    
    
    Function Search-BWList([string]$Hash, [string]$SearchList)
    {
        $list = Get-Content $SearchList
    
        ForEach ($entry In $list)
        {
            If ( $Hash -eq $entry) { return $true }
        }
        return $false
    }
    
    Function Get-UnsignedProcesses()
    {
        # Get current list of unique running processes based on execution path
        $procs = gwmi -Query 'select ExecutablePath,ProcessID from win32_process'
       
        $unsigned = New-Object System.Collections.ArrayList
    
        ForEach($proc In $procs)
        {
            $proc_exe_path = $proc.ExecutablePath
            If ($proc_exe_path -eq $null) { continue }
            If ($proc_exe_path -eq "") { continue }
            # Create a list of unsigned binaries for scanning
            $auth_code = Get-AuthenticodeSignature $proc_exe_path
            If ($auth_code.Status -ne "Valid")
            {
                $hash = (Get-FileHash -Path $proc_exe_path -Algorithm SHA1).Hash
                If ( -Not (Search-BWList -SearchList $white_file -Hash $hash))
                {
                    New-LogAction -Message "A new unsigned process was detected: $proc_exe_path"
                    $proc_obj = New-Object -TypeName psobject
                    $proc_obj | Add-Member -MemberType NoteProperty -Name ExecutablePath -Value $proc.ExecutablePath
                    $proc_obj | Add-Member -MemberType NoteProperty -Name ProcessID -Value $proc.ProcessID
                    $proc_obj | Add-Member -MemberType NoteProperty -Name Hash -Value $hash
                    $unsigned.Add($proc_obj) > null
                }           
            }
        }
        return $unsigned
    }
    
    Function Get-ProcessReport([string]$FilePath, [string]$Hash)
    {
        Get-VirusTotalReport -Hash $hash -Apikey FFFFFFFFFFFFFFFFFFF
    }
    
    Function New-LogAction([string]$Message)
    {
        # Add in code to check log size and rotate log files (keep 5 log files)
        $main_log_size = $(Get-ChildItem -Path $log_file | Measure-Object -Property Length -Sum).Sum
    
        If (($main_log_size / 1MB) -gt 1)
        {
            $log_count = @(Get-ChildItem -Path $main_conf_dir -Filter "*action*").Count
            $log_count--
    
            If ($log_count -ge 4)
            {
                Remove-Item -Path "$log_file.$($log_count)"
                $log_count--
            }
            While($log_count -ge 0)
            {
                If ($log_count -eq 0)
                {
                    Rename-Item -Path "$log_file" -NewName "$log_file.$($log_count+1)"
                }
                else
                {
                    Rename-Item -Path "$log_file.$log_count" -NewName "$log_file.$($log_count+1)"
                }
                $log_count--
            }
            New-Item -Path $log_file -ItemType File
        }
    
        # Add an action event to the log
        Add-Content -Path $log_file -Value "$((Get-Date).ToString())    -----    $Message"
    }
    
    Function Get-VirusTotalReport
    {
        param([string]$Hash, [string]$ApiKey)
       
        $body = @{ resource = $hash; apikey = $ApiKey }
        $Report = Invoke-RestMethod -Method 'POST' -Uri 'https://www.virustotal.com/vtapi/v2/file/report' -Body $body
    
        return $Report
    }
    
    Function Main
    {
        New-Configuration
    
        $suspect_procs = Get-UnsignedProcesses
        ForEach ($proc In $suspect_procs)
        {
            $proc_exe_path = $proc.ExecutablePath
            If ($proc_exe_path -eq $null) { continue }
            If ($proc_exe_path -eq "") { continue }
            $hash = $proc.Hash
    
            If ($(Search-BWList -SearchList $black_file -Hash $hash) -eq $true)
            {
                "Black Listed $proc_exe_path"
                New-LogAction -Message "[BLACKLIST DETECTION]  $proc_exe_path HASH: $hash was found in the blacklist."
    
                #"Kill the process"
                "Stopping $proc_exe_path"
                Stop-Process -Id $proc.ProcessId 2> $kill_error
                If ($?)
                {
                    Create-NotificationBallon -Message "Blacklisted process detected and killed. Process: $proc_exe_path" -Title "Process Killed"
                    New-LogAction -Message "[PROCESS KILL](Success)  $proc_exe_path HASH: $hash"
                } else
                {
                    New-LogAction -Message "[PROCESS KILL](Failed)  $proc_exe_path HASH: $hash  ERROR: $kill_error"
                }
               
                continue
            } ElseIf ( $(Search-BWList -SearchList $white_file -Hash $hash) -eq $true )
            {
                "White Listed $proc_exe_path"
                New-LogAction -Message "[WHITELIST DETECTION]  $proc_exe_path HASH: $hash was found in the whitelist."
                continue
            }
    
            $report = Get-ProcessReport -FilePath $proc_exe_path -Hash $hash
    
            If ($report.positives -eq $null)
            {
                New-LogAction -Message "[PROBLEM]  Process: $proc_exe_path HASH: $hash.  Problem getting Virus Total Report"
                continue
            }
            If ($report.positives -gt 2)
            {
                Add-Content -Path $black_file -Value $hash
                New-LogAction -Message "[BLACKLIST ADD]  Process: $proc_exe_path HASH: $hash was blacklisted.  Hit Count: $($report.positives)/$($report.total)"
    
                #"Kill the process"
                "Stopping $proc_exe_path"
                Stop-Process -Id $proc.ProcessId 2> $kill_error
                If ($?)
                {
                    Create-NotificationBallon -Message "Blacklisted process detected and killed. Process: $proc_exe_path" -Title "Process Killed"
                    New-LogAction -Message "[PROCESS KILL](Success)  $proc_exe_path HASH: $hash"
                } else
                {
                    New-LogAction -Message "[PROCESS KILL](Failed)  $proc_exe_path HASH: $hash  ERROR: $kill_error"
                }
            }
            else
            {
                Add-Content -Path $white_file -Value $hash
                New-LogAction -Message "[WHITELIST ADD]  Process: $proc_exe_path HASH: $hash was whitelisted.  Hit Count: $($report.positives)/$($report.total)"
            }
        }
    }
    
    
    While($true)
    {
        Main
        Sleep -Seconds 1
    }
     
  2. Josephur

    Josephur Windows Forum Admin
    Staff Member Premium Supporter

    Joined:
    Aug 3, 2010
    Messages:
    1,019
    Likes Received:
    125
  3. AceInfinity

    AceInfinity Senior Member
    Microsoft MVP

    Joined:
    Aug 12, 2011
    Messages:
    159
    Likes Received:
    11
    This is more of a file integrity check. Most viruses now don't run in their own executable, they are mapped into the memory of running processes, and this won't detect that. This is okay as a file scanner however.
     
  4. Neemobeer

    Neemobeer Windows Forum Team
    Staff Member

    Joined:
    Jul 4, 2015
    Messages:
    2,412
    Likes Received:
    366
    It checks the locally stored exe against virus total. It doesn't dump the process memory and check that to look for code injection.
     
  5. AceInfinity

    AceInfinity Senior Member
    Microsoft MVP

    Joined:
    Aug 12, 2011
    Messages:
    159
    Likes Received:
    11
    I know, that's what I'm saying, so it's not a *full* virus detector, but more of a file scanner.
     

Share This Page

Loading...