AntivirusBypass/Find-AVSignature.ps1

function Find-AVSignature
{
<#
.SYNOPSIS

Locate tiny AV signatures.

PowerSploit Function: Find-AVSignature
Authors: Chris Campbell (@obscuresec) & Matt Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None

.DESCRIPTION

Locates single Byte AV signatures utilizing the same method as DSplit from "class101" on heapoverflow.com.

.PARAMETER Startbyte

Specifies the first byte to begin splitting on.

.PARAMETER Endbyte

Specifies the last byte to split on.

.PARAMETER Interval

Specifies the interval size to split with.

.PARAMETER Path

Specifies the path to the binary you want tested.

.PARAMETER OutPath

Optionally specifies the directory to write the binaries to.

.PARAMETER BufferLen

Specifies the length of the file read buffer . Defaults to 64KB.

.PARAMETER Force

Forces the script to continue without confirmation.

.EXAMPLE

PS C:\> Find-AVSignature -Startbyte 0 -Endbyte max -Interval 10000 -Path c:\test\exempt\nc.exe
PS C:\> Find-AVSignature -StartByte 10000 -EndByte 20000 -Interval 1000 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run2 -Verbose
PS C:\> Find-AVSignature -StartByte 16000 -EndByte 17000 -Interval 100 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run3 -Verbose
PS C:\> Find-AVSignature -StartByte 16800 -EndByte 16900 -Interval 10 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run4 -Verbose
PS C:\> Find-AVSignature -StartByte 16890 -EndByte 16900 -Interval 1 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run5 -Verbose

.NOTES

Several of the versions of "DSplit.exe" available on the internet contain malware.

.LINK

http://obscuresecurity.blogspot.com/2012/12/finding-simple-av-signatures-with.html
https://github.com/mattifestation/PowerSploit
http://www.exploit-monday.com/
http://heapoverflow.com/f0rums/project.php?issueid=34&filter=changes&page=2
#>


    [CmdletBinding()] Param(
        [Parameter(Mandatory = $True)]
        [ValidateRange(0,4294967295)]
        [UInt32]
        $StartByte,

        [Parameter(Mandatory = $True)]
        [String]
        $EndByte,

        [Parameter(Mandatory = $True)]
        [ValidateRange(0,4294967295)]
        [UInt32]
        $Interval,

        [String]
        [ValidateScript({Test-Path $_ })]
        $Path = ($pwd.path),

        [String]
        $OutPath = ($pwd),
        
        
        [ValidateRange(1,2097152)]
        [UInt32]
        $BufferLen = 65536,
        
        [Switch] $Force
        
    )

    #test variables
    if (!(Test-Path $Path)) {Throw "File path not found"}
    $Response = $True
    if (!(Test-Path $OutPath)) {
        if ($Force -or ($Response = $psCmdlet.ShouldContinue("The `"$OutPath`" does not exist! Do you want to create the directory?",""))){new-item ($OutPath)-type directory}
    }
    if (!$Response) {Throw "Output path not found"}
    if (!(Get-ChildItem $Path).Exists) {Throw "File not found"}
    [Int32] $FileSize = (Get-ChildItem $Path).Length
    if ($StartByte -gt ($FileSize - 1) -or $StartByte -lt 0) {Throw "StartByte range must be between 0 and $Filesize"}
    [Int32] $MaximumByte = (($FileSize) - 1)
    if ($EndByte -ceq "max") {$EndByte = $MaximumByte}
    
    #Recast $Endbyte into an Integer so that it can be compared properly.
    [Int32]$EndByte = $EndByte 
    
    #If $Endbyte is greater than the file Length, use $MaximumByte.
    if ($EndByte -gt $FileSize) {$EndByte = $MaximumByte}
    
    #If $Endbyte is less than the $StartByte, use 1 Interval past $StartByte.
    if ($EndByte -lt $StartByte) {$EndByte = $StartByte + $Interval}

    Write-Verbose "StartByte: $StartByte"
    Write-Verbose "EndByte: $EndByte"
    
    #find the filename for the output name
    [String] $FileName = (Split-Path $Path -leaf).Split('.')[0]

    #Calculate the number of binaries
    [Int32] $ResultNumber = [Math]::Floor(($EndByte - $StartByte) / $Interval)
    if (((($EndByte - $StartByte) % $Interval)) -gt 0) {$ResultNumber = ($ResultNumber + 1)}
    
    #Prompt user to verify parameters to avoid writing binaries to the wrong directory
    $Response = $True
    if ( $Force -or ( $Response = $psCmdlet.ShouldContinue("This script will result in $ResultNumber binaries being written to `"$OutPath`"!",
             "Do you want to continue?"))){}
    if (!$Response) {Return}
    
    Write-Verbose "This script will now write $ResultNumber binaries to `"$OutPath`"." 
    [Int32] $Number = [Math]::Floor($Endbyte/$Interval)
    
        #Create a Read Buffer and Stream.
        #Note: The Filestream class takes advantage of internal .NET Buffering. We set the default internal buffer to 64KB per http://research.microsoft.com/pubs/64538/tr-2004-136.doc.
        [Byte[]] $ReadBuffer=New-Object byte[] $BufferLen
        [System.IO.FileStream] $ReadStream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read, $BufferLen)
        
        #write out the calculated number of binaries
        [Int32] $i = 0
        for ($i -eq 0; $i -lt $ResultNumber + 1 ; $i++)
        {
            # If this is the Final Binary, use $EndBytes, Otherwise calculate based on the Interval
            if ($i -eq $ResultNumber) {[Int32]$SplitByte = $EndByte}
            else {[Int32] $SplitByte = (($StartByte) + (($Interval) * ($i)))}
            
            Write-Verbose "Byte 0 -> $($SplitByte)"
            
            #Reset ReadStream to beginning of file
            $ReadStream.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null
            
            #Build a new FileStream for Writing
            [String] $outfile = Join-Path $OutPath "$($FileName)_$($SplitByte).bin"
            [System.IO.FileStream] $WriteStream = New-Object System.IO.FileStream($outfile, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None, $BufferLen)
            
            [Int32] $BytesLeft = $SplitByte
            Write-Verbose "$($WriteStream.name)"
            
            #Write Buffer Length to the Writing Stream until the bytes left is smaller than the buffer
            while ($BytesLeft -gt $BufferLen){
                [Int32]$count = $ReadStream.Read($ReadBuffer, 0, $BufferLen)
                $WriteStream.Write($ReadBuffer, 0, $count)
                $BytesLeft = $BytesLeft - $count
            }
            
            #Write the remaining bytes to the file
            do {
                [Int32]$count = $ReadStream.Read($ReadBuffer, 0, $BytesLeft)
                $WriteStream.Write($ReadBuffer, 0, $count)
                $BytesLeft = $BytesLeft - $count            
            }
            until ($BytesLeft -eq 0)
            $WriteStream.Close()
            $WriteStream.Dispose()
        }
        Write-Verbose "Files written to disk. Flushing memory."
        $ReadStream.Dispose()
        
        #During testing using large binaries, memory usage was excessive so lets fix that
        [System.GC]::Collect()
        Write-Verbose "Completed!"
}