Public/Invoke-OffsetMutationTest.ps1
|
function Invoke-OffsetMutationTest { <# .SYNOPSIS Tests how robust a signature is by perturbing a detected sample in memory and re-scanning. .DESCRIPTION For authorized detection-engineering and red-team engagements. Given a sample that AMSI currently detects, this applies a set of standard signature-robustness perturbations (case inversion, string-literal concatenation, comment insertion, whitespace injection) and re-scans each variant with AMSI to report which transform CLASSES neutralize detection. That tells you whether the signature is a brittle exact-literal match or is robust to common obfuscation - the core detection-engineering question, and the same insight an authorized operator needs to assess a control. Everything happens IN MEMORY: variants are scanned via AMSI's in-process interface and are never written to disk, so no evasive artifacts are produced and Defender real-time protection is not involved. AMSI only (Defender file scanning would require disk writes). The command refuses to run without -AuthorizedEngagement. .PARAMETER FilePath The sample to test. Must currently be detected by AMSI for the results to be meaningful. Read as text (UTF-8, BOM-aware); the transforms are script/text-oriented, so this command targets script-style samples rather than arbitrary binaries. .PARAMETER AuthorizedEngagement Required acknowledgement that you are authorized to test this sample. The command will not run without it. .PARAMETER Transform Which robustness transform classes to test (default: all four). .EXAMPLE Invoke-OffsetMutationTest -FilePath .\flagged.ps1 -AuthorizedEngagement .EXAMPLE Invoke-OffsetMutationTest .\flagged.ps1 -AuthorizedEngagement -Transform CaseInversion, StringConcatenation #> [CmdletBinding()] [OutputType('OffsetInspect.MutationTestResult')] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string]$FilePath, [Parameter(Mandatory = $true)] [switch]$AuthorizedEngagement, [ValidateSet('CaseInversion', 'StringConcatenation', 'CommentInsertion', 'WhitespaceInjection')] [string[]]$Transform = @('CaseInversion', 'StringConcatenation', 'CommentInsertion', 'WhitespaceInjection') ) if (-not $AuthorizedEngagement) { throw 'Invoke-OffsetMutationTest generates detection-evasion variants and is for authorized engagements only. Re-run with -AuthorizedEngagement to confirm you are authorized to test this sample.' } Write-Warning 'Signature-robustness testing: evasion variants are generated and scanned IN MEMORY (nothing is written to disk). Use only against samples you are authorized to test.' if (-not (Test-OIIsWindows)) { throw 'Invoke-OffsetMutationTest requires Windows (it uses the in-memory AMSI interface).' } $resolved = (Resolve-Path -LiteralPath $FilePath -ErrorAction Stop).Path if ((Get-Item -LiteralPath $resolved).PSIsContainer) { throw "Path is a directory, not a file: $resolved" } $content = [System.IO.File]::ReadAllText($resolved) Initialize-OIAmsiInterop $session = New-Object 'OffsetInspect.Interop.AmsiSession' -ArgumentList 'OffsetInspect.MutationTest' try { $scanner = { param($text) $response = $session.ScanString($text, 'OffsetInspect.MutationTest') (ConvertFrom-OIAmsiResponse -Response $response).Status } $set = Test-OIMutationSet -Content $content -Transforms $Transform -Scanner $scanner } finally { $session.Dispose() } $summary = if (-not $set.BaselineDetected) { "Baseline is $($set.BaselineStatus) under AMSI - nothing to test (the sample is not currently detected)." } elseif ($set.EvasionCount -eq 0) { "Signature is robust to the $($Transform.Count) tested transform class(es); none neutralized detection." } else { $names = @($set.Results | Where-Object { $_.Evaded } | ForEach-Object { $_.Transform }) -join ', ' "Signature is brittle: neutralized by $($set.EvasionCount) of $($Transform.Count) transform class(es) - $names." } return [pscustomobject]@{ PSTypeName = 'OffsetInspect.MutationTestResult' File = $resolved Engine = 'AMSI' BaselineStatus = $set.BaselineStatus BaselineDetected = $set.BaselineDetected TargetToken = $set.TargetToken TransformsTested = $Transform Results = $set.Results EvasionCount = $set.EvasionCount RobustnessSummary = $summary } } |