Private/Threat.Mutation.ps1

function Get-OILongestTokenSpan {
    <#
        Returns the start/length/value of the longest alphanumeric run in the content - a
        heuristic for the distinctive token a literal signature most likely keys on. Returns
        $null when no run of at least MinimumLength is present. Pure and cross-platform.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string]$Content,

        [int]$MinimumLength = 4
    )

    $best = $null
    foreach ($match in [regex]::Matches($Content, '[A-Za-z0-9]+')) {
        if ($match.Length -ge $MinimumLength -and ($null -eq $best -or $match.Length -gt $best.Length)) {
            $best = [pscustomobject]@{ Start = $match.Index; Length = $match.Length; Value = $match.Value }
        }
    }
    return $best
}

function Get-OIMutationVariant {
    <#
        Produces one perturbed variant of the content for a named transform class. These are
        the standard signature-robustness perturbations detection engineers test against: an
        exact-literal signature breaks under them, a robust one does not. String-targeting
        transforms perturb the longest distinctive token (via TokenSpan). Pure and
        cross-platform; returns the content unchanged when a transform has nothing to act on.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string]$Content,

        [Parameter(Mandatory = $true)]
        [ValidateSet('CaseInversion', 'StringConcatenation', 'CommentInsertion', 'WhitespaceInjection')]
        [string]$Transform,

        [AllowNull()]
        $TokenSpan
    )

    if ($Transform -eq 'CaseInversion') {
        $sb = New-Object System.Text.StringBuilder
        foreach ($ch in $Content.ToCharArray()) {
            if ($ch -ge 'a' -and $ch -le 'z') { [void]$sb.Append([char]([int][char]$ch - 32)) }
            elseif ($ch -ge 'A' -and $ch -le 'Z') { [void]$sb.Append([char]([int][char]$ch + 32)) }
            else { [void]$sb.Append($ch) }
        }
        return $sb.ToString()
    }

    if ($null -eq $TokenSpan) { return $Content }

    $mid = [int]$TokenSpan.Start + [int][Math]::Floor([int]$TokenSpan.Length / 2)
    $insert = switch ($Transform) {
        'StringConcatenation' { "'+'" }
        'CommentInsertion' { '<##>' }
        'WhitespaceInjection' { ' ' }
    }
    return $Content.Substring(0, $mid) + $insert + $Content.Substring($mid)
}

function Test-OIMutationSet {
    <#
        Runs the baseline scan and one scan per transform through an injected scanner
        scriptblock ({ param($text) -> status string }), and reports which transforms
        neutralized detection. Pure with respect to the provider (the scanner is injected),
        so it is unit-tested cross-platform with a fake scanner. The public wrapper supplies
        the real in-memory AMSI scanner.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string]$Content,

        [Parameter(Mandatory = $true)]
        [string[]]$Transforms,

        [Parameter(Mandatory = $true)]
        [scriptblock]$Scanner
    )

    $isPositive = { param($s) ($s -eq 'Detected' -or $s -eq 'Blocked') }

    $baselineStatus = & $Scanner $Content
    $baselineDetected = [bool](& $isPositive $baselineStatus)
    $token = Get-OILongestTokenSpan -Content $Content

    $results = New-Object 'System.Collections.Generic.List[object]'
    foreach ($transform in $Transforms) {
        $variant = Get-OIMutationVariant -Content $Content -Transform $transform -TokenSpan $token
        # Case-sensitive: CaseInversion changes only letter case, which -eq would miss.
        $unchanged = ($variant -ceq $Content)
        $status = if ($unchanged) { $baselineStatus } else { & $Scanner $variant }
        $evaded = $baselineDetected -and -not [bool](& $isPositive $status)

        $note = if ($unchanged) { 'Transform had no target in this content (no distinctive token); not exercised.' } else { $null }
        $results.Add([pscustomobject]@{
            Transform     = $transform
            VariantStatus = $status
            Evaded        = $evaded
            Note          = $note
        })
    }

    $evasions = @($results | Where-Object { $_.Evaded })
    return [pscustomobject]@{
        BaselineStatus   = $baselineStatus
        BaselineDetected = $baselineDetected
        TargetToken      = if ($null -ne $token) { $token.Value } else { $null }
        Results          = $results.ToArray()
        EvasionCount     = $evasions.Count
    }
}