2108 lines
118 KiB
PowerShell
2108 lines
118 KiB
PowerShell
# This file is part of Invoke-Obfuscation.
|
|
#
|
|
# Copyright 2017 Daniel Bohannon <@danielhbohannon>
|
|
# while at Mandiant <http://www.mandiant.com>
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
Function Invoke-Obfuscation
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Master function that orchestrates the application of all obfuscation functions to provided PowerShell script block or script path contents. Interactive mode enables one to explore all available obfuscation functions and apply them incrementally to input PowerShell script block or script path contents.
|
|
|
|
Invoke-Obfuscation Function: Invoke-Obfuscation
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: Show-AsciiArt, Show-HelpMenu, Show-Menu, Show-OptionsMenu, Show-Tutorial and Out-ScriptContents (all located in Invoke-Obfuscation.ps1)
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Invoke-Obfuscation orchestrates the application of all obfuscation functions to provided PowerShell script block or script path contents to evade detection by simple IOCs and process execution monitoring relying solely on command-line arguments and common parent-child process relationships.
|
|
|
|
.PARAMETER ScriptBlock
|
|
|
|
Specifies a scriptblock containing your payload.
|
|
|
|
.PARAMETER ScriptPath
|
|
|
|
Specifies the path to your payload (can be local file, UNC-path, or remote URI).
|
|
|
|
.PARAMETER Command
|
|
|
|
Specifies the obfuscation commands to run against the input ScriptBlock or ScriptPath parameter.
|
|
|
|
.PARAMETER NoExit
|
|
|
|
(Optional - only works if Command is specified) Outputs the option to not exit after running obfuscation commands defined in Command parameter.
|
|
|
|
.PARAMETER Quiet
|
|
|
|
(Optional - only works if Command is specified) Outputs the option to output only the final obfuscated result via stdout.
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation
|
|
|
|
C:\PS> Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green}
|
|
|
|
C:\PS> Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -Command 'TOKEN\ALL\1,1,TEST,LAUNCHER\STDIN++\2347,CLIP'
|
|
|
|
C:\PS> Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -Command 'TOKEN\ALL\1,1,TEST,LAUNCHER\STDIN++\2347,CLIP' -NoExit
|
|
|
|
C:\PS> Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -Command 'TOKEN\ALL\1,1,TEST,LAUNCHER\STDIN++\2347,CLIP' -Quiet
|
|
|
|
C:\PS> Import-Module .\Invoke-Obfuscation.psd1; Invoke-Obfuscation -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -Command 'TOKEN\ALL\1,1,TEST,LAUNCHER\STDIN++\2347,CLIP' -NoExit -Quiet
|
|
|
|
.NOTES
|
|
|
|
Invoke-Obfuscation orchestrates the application of all obfuscation functions to provided PowerShell script block or script path contents to evade detection by simple IOCs and process execution monitoring relying solely on command-line arguments.
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
|
|
[CmdletBinding(DefaultParameterSetName = 'ScriptBlock')] Param (
|
|
[Parameter(Position = 0, ValueFromPipeline = $True, ParameterSetName = 'ScriptBlock')]
|
|
[ValidateNotNullOrEmpty()]
|
|
[ScriptBlock]
|
|
$ScriptBlock,
|
|
|
|
[Parameter(Position = 0, ParameterSetName = 'ScriptBlock')]
|
|
[ValidateNotNullOrEmpty()]
|
|
[String]
|
|
$ScriptPath,
|
|
|
|
[String]
|
|
$Command,
|
|
|
|
[Switch]
|
|
$NoExit,
|
|
|
|
[Switch]
|
|
$Quiet
|
|
)
|
|
|
|
# Define variables for CLI functionality.
|
|
$Script:CliCommands = @()
|
|
$Script:CompoundCommand = @()
|
|
$Script:QuietWasSpecified = $FALSE
|
|
$CliWasSpecified = $FALSE
|
|
$NoExitWasSpecified = $FALSE
|
|
|
|
# Either convert ScriptBlock to a String or convert script at $Path to a String.
|
|
If($PSBoundParameters['ScriptBlock'])
|
|
{
|
|
$Script:CliCommands += ('set scriptblock ' + [String]$ScriptBlock)
|
|
}
|
|
If($PSBoundParameters['ScriptPath'])
|
|
{
|
|
$Script:CliCommands += ('set scriptpath ' + $ScriptPath)
|
|
}
|
|
|
|
# Append Command to CliCommands if specified by user input.
|
|
If($PSBoundParameters['Command'])
|
|
{
|
|
$Script:CliCommands += $Command.Split(',')
|
|
$CliWasSpecified = $TRUE
|
|
|
|
If($PSBoundParameters['NoExit'])
|
|
{
|
|
$NoExitWasSpecified = $TRUE
|
|
}
|
|
|
|
If($PSBoundParameters['Quiet'])
|
|
{
|
|
# Create empty Write-Host and Start-Sleep proxy functions to cause any Write-Host or Start-Sleep invocations to not do anything until non-interactive -Command values are finished being processed.
|
|
Function Write-Host {}
|
|
Function Start-Sleep {}
|
|
$Script:QuietWasSpecified = $TRUE
|
|
}
|
|
}
|
|
|
|
########################################
|
|
## Script-wide variable instantiation ##
|
|
########################################
|
|
|
|
# Script-level array of Show Options menu, set as SCRIPT-level so it can be set from within any of the functions.
|
|
# Build out menu for Show Options selection from user in Show-OptionsMenu menu.
|
|
$Script:ScriptPath = ''
|
|
$Script:ScriptBlock = ''
|
|
$Script:CliSyntax = @()
|
|
$Script:ExecutionCommands = @()
|
|
$Script:ObfuscatedCommand = ''
|
|
$Script:ObfuscatedCommandHistory = @()
|
|
$Script:ObfuscationLength = ''
|
|
$Script:OptionsMenu = @()
|
|
$Script:OptionsMenu += , @('ScriptPath ' , $Script:ScriptPath , $TRUE)
|
|
$Script:OptionsMenu += , @('ScriptBlock' , $Script:ScriptBlock , $TRUE)
|
|
$Script:OptionsMenu += , @('CommandLineSyntax' , $Script:CliSyntax , $FALSE)
|
|
$Script:OptionsMenu += , @('ExecutionCommands' , $Script:ExecutionCommands, $FALSE)
|
|
$Script:OptionsMenu += , @('ObfuscatedCommand' , $Script:ObfuscatedCommand, $FALSE)
|
|
$Script:OptionsMenu += , @('ObfuscationLength' , $Script:ObfuscatedCommand, $FALSE)
|
|
# Build out $SetInputOptions from above items set as $TRUE (as settable).
|
|
$SettableInputOptions = @()
|
|
ForEach($Option in $Script:OptionsMenu)
|
|
{
|
|
If($Option[2]) {$SettableInputOptions += ([String]$Option[0]).ToLower().Trim()}
|
|
}
|
|
|
|
# Script-level variable for whether LAUNCHER has been applied to current ObfuscatedToken.
|
|
$Script:LauncherApplied = $FALSE
|
|
|
|
# Ensure Invoke-Obfuscation module was properly imported before continuing.
|
|
If(!(Get-Module Invoke-Obfuscation | Where-Object {$_.ModuleType -eq 'Manifest'}))
|
|
{
|
|
$PathTopsd1 = "$ScriptDir\Invoke-Obfuscation.psd1"
|
|
If($PathTopsd1.Contains(' ')) {$PathTopsd1 = '"' + $PathTopsd1 + '"'}
|
|
Write-Host "`n`nERROR: Invoke-Obfuscation module is not loaded. You must run:" -ForegroundColor Red
|
|
Write-Host " Import-Module $PathTopsd1`n`n" -ForegroundColor Yellow
|
|
Exit
|
|
}
|
|
|
|
# Maximum size for cmd.exe and clipboard.
|
|
$CmdMaxLength = 8190
|
|
|
|
# Build interactive menus.
|
|
$LineSpacing = '[*] '
|
|
|
|
# Main Menu.
|
|
$MenuLevel = @()
|
|
$MenuLevel+= , @($LineSpacing, 'TOKEN' , 'Obfuscate PowerShell command <Tokens>')
|
|
$MenuLevel+= , @($LineSpacing, 'STRING' , 'Obfuscate entire command as a <String>')
|
|
$MenuLevel+= , @($LineSpacing, 'ENCODING' , 'Obfuscate entire command via <Encoding>')
|
|
$MenuLevel+= , @($LineSpacing, 'LAUNCHER' , 'Obfuscate command args w/<Launcher> techniques (run once at end)')
|
|
|
|
# Main\Token Menu.
|
|
$MenuLevel_Token = @()
|
|
$MenuLevel_Token += , @($LineSpacing, 'STRING' , 'Obfuscate <String> tokens (suggested to run first)')
|
|
$MenuLevel_Token += , @($LineSpacing, 'COMMAND' , 'Obfuscate <Command> tokens')
|
|
$MenuLevel_Token += , @($LineSpacing, 'ARGUMENT' , 'Obfuscate <Argument> tokens')
|
|
$MenuLevel_Token += , @($LineSpacing, 'MEMBER' , 'Obfuscate <Member> tokens')
|
|
$MenuLevel_Token += , @($LineSpacing, 'VARIABLE' , 'Obfuscate <Variable> tokens')
|
|
$MenuLevel_Token += , @($LineSpacing, 'TYPE ' , 'Obfuscate <Type> tokens')
|
|
$MenuLevel_Token += , @($LineSpacing, 'COMMENT' , 'Remove all <Comment> tokens')
|
|
$MenuLevel_Token += , @($LineSpacing, 'WHITESPACE' , 'Insert random <Whitespace> (suggested to run last)')
|
|
$MenuLevel_Token += , @($LineSpacing, 'ALL ' , 'Select <All> choices from above (random order)')
|
|
|
|
$MenuLevel_Token_String = @()
|
|
$MenuLevel_Token_String += , @($LineSpacing, '1' , "Concatenate --> e.g. <('co'+'ffe'+'e')>" , @('Out-ObfuscatedTokenCommand', 'String', 1))
|
|
$MenuLevel_Token_String += , @($LineSpacing, '2' , "Reorder --> e.g. <('{1}{0}'-f'ffee','co')>" , @('Out-ObfuscatedTokenCommand', 'String', 2))
|
|
|
|
$MenuLevel_Token_Command = @()
|
|
$MenuLevel_Token_Command += , @($LineSpacing, '1' , 'Ticks --> e.g. <Ne`w-O`Bject>' , @('Out-ObfuscatedTokenCommand', 'Command', 1))
|
|
$MenuLevel_Token_Command += , @($LineSpacing, '2' , "Splatting + Concatenate --> e.g. <&('Ne'+'w-Ob'+'ject')>" , @('Out-ObfuscatedTokenCommand', 'Command', 2))
|
|
$MenuLevel_Token_Command += , @($LineSpacing, '3' , "Splatting + Reorder --> e.g. <&('{1}{0}'-f'bject','New-O')>" , @('Out-ObfuscatedTokenCommand', 'Command', 3))
|
|
|
|
$MenuLevel_Token_Argument = @()
|
|
$MenuLevel_Token_Argument += , @($LineSpacing, '1' , 'Random Case --> e.g. <nEt.weBclIenT>' , @('Out-ObfuscatedTokenCommand', 'CommandArgument', 1))
|
|
$MenuLevel_Token_Argument += , @($LineSpacing, '2' , 'Ticks --> e.g. <nE`T.we`Bc`lIe`NT>' , @('Out-ObfuscatedTokenCommand', 'CommandArgument', 2))
|
|
$MenuLevel_Token_Argument += , @($LineSpacing, '3' , "Concatenate --> e.g. <('Ne'+'t.We'+'bClient')>" , @('Out-ObfuscatedTokenCommand', 'CommandArgument', 3))
|
|
$MenuLevel_Token_Argument += , @($LineSpacing, '4' , "Reorder --> e.g. <('{1}{0}'-f'bClient','Net.We')>" , @('Out-ObfuscatedTokenCommand', 'CommandArgument', 4))
|
|
|
|
$MenuLevel_Token_Member = @()
|
|
$MenuLevel_Token_Member += , @($LineSpacing, '1' , 'Random Case --> e.g. <dOwnLoAdsTRing>' , @('Out-ObfuscatedTokenCommand', 'Member', 1))
|
|
$MenuLevel_Token_Member += , @($LineSpacing, '2' , 'Ticks --> e.g. <d`Ow`NLoAd`STRin`g>' , @('Out-ObfuscatedTokenCommand', 'Member', 2))
|
|
$MenuLevel_Token_Member += , @($LineSpacing, '3' , "Concatenate --> e.g. <('dOwnLo'+'AdsT'+'Ring').Invoke()>" , @('Out-ObfuscatedTokenCommand', 'Member', 3))
|
|
$MenuLevel_Token_Member += , @($LineSpacing, '4' , "Reorder --> e.g. <('{1}{0}'-f'dString','Downloa').Invoke()>" , @('Out-ObfuscatedTokenCommand', 'Member', 4))
|
|
|
|
$MenuLevel_Token_Variable = @()
|
|
$MenuLevel_Token_Variable += , @($LineSpacing, '1' , 'Random Case + {} + Ticks --> e.g. <${c`hEm`eX}>' , @('Out-ObfuscatedTokenCommand', 'Variable', 1))
|
|
|
|
$MenuLevel_Token_Type = @()
|
|
$MenuLevel_Token_Type += , @($LineSpacing, '1' , "Type Cast + Concatenate --> e.g. <[Type]('Con'+'sole')>" , @('Out-ObfuscatedTokenCommand', 'Type', 1))
|
|
$MenuLevel_Token_Type += , @($LineSpacing, '2' , "Type Cast + Reordered --> e.g. <[Type]('{1}{0}'-f'sole','Con')>" , @('Out-ObfuscatedTokenCommand', 'Type', 2))
|
|
|
|
$MenuLevel_Token_Whitespace = @()
|
|
$MenuLevel_Token_Whitespace += , @($LineSpacing, '1' , "`tRandom Whitespace --> e.g. <.( 'Ne' +'w-Ob' + 'ject')>" , @('Out-ObfuscatedTokenCommand', 'RandomWhitespace', 1))
|
|
|
|
$MenuLevel_Token_Comment = @()
|
|
$MenuLevel_Token_Comment += , @($LineSpacing, '1' , "Remove Comments --> e.g. self-explanatory" , @('Out-ObfuscatedTokenCommand', 'Comment', 1))
|
|
|
|
$MenuLevel_Token_All = @()
|
|
$MenuLevel_Token_All += , @($LineSpacing, '1' , "`tExecute <ALL> Token obfuscation techniques (random order)" , @('Out-ObfuscatedTokenCommandAll', '', ''))
|
|
|
|
# Main\String Menu.
|
|
$MenuLevel_String = @()
|
|
$MenuLevel_String += , @($LineSpacing, '1' , '<Concatenate> entire command' , @('Out-ObfuscatedStringCommand', '', 1))
|
|
$MenuLevel_String += , @($LineSpacing, '2' , '<Reorder> entire command after concatenating' , @('Out-ObfuscatedStringCommand', '', 2))
|
|
$MenuLevel_String += , @($LineSpacing, '3' , '<Reverse> entire command after concatenating' , @('Out-ObfuscatedStringCommand', '', 3))
|
|
|
|
# Main\Encoding Menu.
|
|
$MenuLevel_Encoding = @()
|
|
$MenuLevel_Encoding += , @($LineSpacing, '1' , "`tEncode entire command as <ASCII>" , @('Out-EncodedAsciiCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '2' , "`tEncode entire command as <Hex>" , @('Out-EncodedHexCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '3' , "`tEncode entire command as <Octal>" , @('Out-EncodedOctalCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '4' , "`tEncode entire command as <Binary>" , @('Out-EncodedBinaryCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '5' , "`tEncrypt entire command as <SecureString> (AES)" , @('Out-SecureStringCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '6' , "`tEncode entire command as <BXOR>" , @('Out-EncodedBXORCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '7' , "`tEncode entire command as <Special Characters>" , @('Out-EncodedSpecialCharOnlyCommand' , '', ''))
|
|
$MenuLevel_Encoding += , @($LineSpacing, '8' , "`tEncode entire command as <Whitespace>" , @('Out-EncodedWhitespaceCommand' , '', ''))
|
|
|
|
# Main\Launcher Menu.
|
|
$MenuLevel_Launcher = @()
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'PS' , "`t<PowerShell>")
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'CMD' , '<Cmd> + PowerShell')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'WMIC' , '<Wmic> + PowerShell')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'RUNDLL' , '<Rundll32> + PowerShell')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'VAR+' , 'Cmd + set <Var> && PowerShell iex <Var>')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'STDIN+' , 'Cmd + <Echo> | PowerShell - (stdin)')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'CLIP+' , 'Cmd + <Echo> | Clip && PowerShell iex <clipboard>')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'VAR++' , 'Cmd + set <Var> && Cmd && PowerShell iex <Var>')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'STDIN++' , 'Cmd + set <Var> && Cmd <Echo> | PowerShell - (stdin)')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'CLIP++' , 'Cmd + <Echo> | Clip && Cmd && PowerShell iex <clipboard>')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'RUNDLL++' , 'Cmd + set Var && <Rundll32> && PowerShell iex Var')
|
|
$MenuLevel_Launcher += , @($LineSpacing, 'MSHTA++' , 'Cmd + set Var && <Mshta> && PowerShell iex Var')
|
|
|
|
$MenuLevel_Launcher_PS = @()
|
|
$MenuLevel_Launcher_PS += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '1'))
|
|
$MenuLevel_Launcher_PS += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '1'))
|
|
|
|
$MenuLevel_Launcher_CMD = @()
|
|
$MenuLevel_Launcher_CMD += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '2'))
|
|
$MenuLevel_Launcher_CMD += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '2'))
|
|
|
|
$MenuLevel_Launcher_WMIC = @()
|
|
$MenuLevel_Launcher_WMIC += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '3'))
|
|
$MenuLevel_Launcher_WMIC += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '3'))
|
|
|
|
$MenuLevel_Launcher_RUNDLL = @()
|
|
$MenuLevel_Launcher_RUNDLL += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '4'))
|
|
$MenuLevel_Launcher_RUNDLL += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '4'))
|
|
|
|
${MenuLevel_Launcher_VAR+} = @()
|
|
${MenuLevel_Launcher_VAR+} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '5'))
|
|
${MenuLevel_Launcher_VAR+} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '5'))
|
|
|
|
${MenuLevel_Launcher_STDIN+} = @()
|
|
${MenuLevel_Launcher_STDIN+} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '6'))
|
|
${MenuLevel_Launcher_STDIN+} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '6'))
|
|
|
|
${MenuLevel_Launcher_CLIP+} = @()
|
|
${MenuLevel_Launcher_CLIP+} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '7'))
|
|
${MenuLevel_Launcher_CLIP+} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '7'))
|
|
|
|
${MenuLevel_Launcher_VAR++} = @()
|
|
${MenuLevel_Launcher_VAR++} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '8'))
|
|
${MenuLevel_Launcher_VAR++} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '8'))
|
|
|
|
${MenuLevel_Launcher_STDIN++} = @()
|
|
${MenuLevel_Launcher_STDIN++} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '0' , "`tNO EXECUTION FLAGS" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '1' , "`t-NoExit" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '2' , "`t-NonInteractive" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '3' , "`t-NoLogo" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '4' , "`t-NoProfile" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '5' , "`t-Command" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '6' , "`t-WindowStyle Hidden" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '7' , "`t-ExecutionPolicy Bypass" , @('Out-PowerShellLauncher', '', '9'))
|
|
${MenuLevel_Launcher_STDIN++} += , @($LineSpacing, '8' , "`t-Wow64 (to path 32-bit powershell.exe)" , @('Out-PowerShellLauncher', '', '9'))
|
|
|
|
${MenuLevel_Launcher_CLIP++} = @()
|
|
${MenuLevel_Launcher_CLIP++} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '10'))
|
|
${MenuLevel_Launcher_CLIP++} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '10'))
|
|
|
|
${MenuLevel_Launcher_RUNDLL++} = @()
|
|
${MenuLevel_Launcher_RUNDLL++} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '11'))
|
|
${MenuLevel_Launcher_RUNDLL++} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '11'))
|
|
|
|
${MenuLevel_Launcher_MSHTA++} = @()
|
|
${MenuLevel_Launcher_MSHTA++} += , @("Enter string of numbers with all desired flags to pass to function. (e.g. 23459)`n", '' , '' , @('', '', ''))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '0' , 'NO EXECUTION FLAGS' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '1' , '-NoExit' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '2' , '-NonInteractive' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '3' , '-NoLogo' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '4' , '-NoProfile' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '5' , '-Command' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '6' , '-WindowStyle Hidden' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '7' , '-ExecutionPolicy Bypass' , @('Out-PowerShellLauncher', '', '12'))
|
|
${MenuLevel_Launcher_MSHTA++} += , @($LineSpacing, '8' , '-Wow64 (to path 32-bit powershell.exe)' , @('Out-PowerShellLauncher', '', '12'))
|
|
|
|
# Input options to display non-interactive menus or perform actions.
|
|
$TutorialInputOptions = @(@('tutorial') , "<Tutorial> of how to use this tool `t " )
|
|
$MenuInputOptionsShowHelp = @(@('help','get-help','?','-?','/?','menu'), "Show this <Help> Menu `t " )
|
|
$MenuInputOptionsShowOptions = @(@('show options','show','options') , "<Show options> for payload to obfuscate `t " )
|
|
$ClearScreenInputOptions = @(@('clear','clear-host','cls') , "<Clear> screen `t " )
|
|
$CopyToClipboardInputOptions = @(@('copy','clip','clipboard') , "<Copy> ObfuscatedCommand to clipboard `t " )
|
|
$OutputToDiskInputOptions = @(@('out') , "Write ObfuscatedCommand <Out> to disk `t " )
|
|
$ExecutionInputOptions = @(@('exec','execute','test','run') , "<Execute> ObfuscatedCommand locally `t " )
|
|
$ResetObfuscationInputOptions = @(@('reset') , "<Reset> ALL obfuscation for ObfuscatedCommand ")
|
|
$UndoObfuscationInputOptions = @(@('undo') , "<Undo> LAST obfuscation for ObfuscatedCommand ")
|
|
$BackCommandInputOptions = @(@('back','cd ..') , "Go <Back> to previous obfuscation menu `t " )
|
|
$ExitCommandInputOptions = @(@('quit','exit') , "<Quit> Invoke-Obfuscation `t " )
|
|
$HomeMenuInputOptions = @(@('home','main') , "Return to <Home> Menu `t " )
|
|
# For Version 1.0 ASCII art is not necessary.
|
|
#$ShowAsciiArtInputOptions = @(@('ascii') , "Display random <ASCII> art for the lulz :)`t")
|
|
|
|
# Add all above input options lists to be displayed in SHOW OPTIONS menu.
|
|
$AllAvailableInputOptionsLists = @()
|
|
$AllAvailableInputOptionsLists += , $TutorialInputOptions
|
|
$AllAvailableInputOptionsLists += , $MenuInputOptionsShowHelp
|
|
$AllAvailableInputOptionsLists += , $MenuInputOptionsShowOptions
|
|
$AllAvailableInputOptionsLists += , $ClearScreenInputOptions
|
|
$AllAvailableInputOptionsLists += , $ExecutionInputOptions
|
|
$AllAvailableInputOptionsLists += , $CopyToClipboardInputOptions
|
|
$AllAvailableInputOptionsLists += , $OutputToDiskInputOptions
|
|
$AllAvailableInputOptionsLists += , $ResetObfuscationInputOptions
|
|
$AllAvailableInputOptionsLists += , $UndoObfuscationInputOptions
|
|
$AllAvailableInputOptionsLists += , $BackCommandInputOptions
|
|
$AllAvailableInputOptionsLists += , $ExitCommandInputOptions
|
|
$AllAvailableInputOptionsLists += , $HomeMenuInputOptions
|
|
# For Version 1.0 ASCII art is not necessary.
|
|
#$AllAvailableInputOptionsLists += , $ShowAsciiArtInputOptions
|
|
|
|
# Input options to change interactive menus.
|
|
$ExitInputOptions = $ExitCommandInputOptions[0]
|
|
$MenuInputOptions = $BackCommandInputOptions[0]
|
|
|
|
# Obligatory ASCII Art.
|
|
Show-AsciiArt
|
|
Start-Sleep -Seconds 2
|
|
|
|
# Show Help Menu once at beginning of script.
|
|
Show-HelpMenu
|
|
|
|
# Main loop for user interaction. Show-Menu function displays current function along with acceptable input options (defined in arrays instantiated above).
|
|
# User input and validation is handled within Show-Menu.
|
|
$UserResponse = ''
|
|
While($ExitInputOptions -NotContains ([String]$UserResponse).ToLower())
|
|
{
|
|
$UserResponse = ([String]$UserResponse).Trim()
|
|
|
|
If($HomeMenuInputOptions[0] -Contains ([String]$UserResponse).ToLower())
|
|
{
|
|
$UserResponse = ''
|
|
}
|
|
|
|
# Display menu if it is defined in a menu variable with $UserResponse in the variable name.
|
|
If(Test-Path ('Variable:' + "MenuLevel$UserResponse"))
|
|
{
|
|
$UserResponse = Show-Menu (Get-Variable "MenuLevel$UserResponse").Value $UserResponse $Script:OptionsMenu
|
|
}
|
|
Else
|
|
{
|
|
Write-Error "The variable MenuLevel$UserResponse does not exist."
|
|
$UserResponse = 'quit'
|
|
}
|
|
|
|
If(($UserResponse -eq 'quit') -AND $CliWasSpecified -AND !$NoExitWasSpecified)
|
|
{
|
|
Write-Output $Script:ObfuscatedCommand.Trim("`n")
|
|
$UserInput = 'quit'
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# Get location of this script no matter what the current directory is for the process executing this script.
|
|
$ScriptDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
|
|
|
|
|
|
Function Show-Menu
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
HELPER FUNCTION :: Displays current menu with obfuscation navigation and application options for Invoke-Obfuscation.
|
|
|
|
Invoke-Obfuscation Function: Show-Menu
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Show-Menu displays current menu with obfuscation navigation and application options for Invoke-Obfuscation.
|
|
|
|
.PARAMETER Menu
|
|
|
|
Specifies the menu options to display, with acceptable input options parsed out of this array.
|
|
|
|
.PARAMETER MenuName
|
|
|
|
Specifies the menu header display and the breadcrumb used in the interactive prompt display.
|
|
|
|
.PARAMETER Script:OptionsMenu
|
|
|
|
Specifies the script-wide variable containing additional acceptable input in addition to each menu's specific acceptable input (e.g. EXIT, QUIT, BACK, HOME, MAIN, etc.).
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Show-Menu
|
|
|
|
.NOTES
|
|
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
|
|
Param(
|
|
[Parameter(ValueFromPipeline = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[Object[]]
|
|
$Menu,
|
|
|
|
[String]
|
|
$MenuName,
|
|
|
|
[Object[]]
|
|
$Script:OptionsMenu
|
|
)
|
|
|
|
# Extract all acceptable values from $Menu.
|
|
$AcceptableInput = @()
|
|
$SelectionContainsCommand = $FALSE
|
|
ForEach($Line in $Menu)
|
|
{
|
|
# If there are 4 items in each $Line in $Menu then the fourth item is a command to exec if selected.
|
|
If($Line.Count -eq 4)
|
|
{
|
|
$SelectionContainsCommand = $TRUE
|
|
}
|
|
$AcceptableInput += ($Line[1]).Trim(' ')
|
|
}
|
|
|
|
$UserInput = $NULL
|
|
|
|
While($AcceptableInput -NotContains $UserInput)
|
|
{
|
|
# Format custom breadcrumb prompt.
|
|
Write-Host "`n"
|
|
$BreadCrumb = $MenuName.Trim('_')
|
|
If($BreadCrumb.Length -gt 1)
|
|
{
|
|
If($BreadCrumb.ToLower() -eq 'show options')
|
|
{
|
|
$BreadCrumb = 'Show Options'
|
|
}
|
|
If($MenuName -ne '')
|
|
{
|
|
# Handle specific case substitutions from what is ALL CAPS in interactive menu and then correct casing we want to appear in the Breadcrumb.
|
|
$BreadCrumbOCD = @()
|
|
$BreadCrumbOCD += , @('ps' ,'PS')
|
|
$BreadCrumbOCD += , @('cmd' ,'Cmd')
|
|
$BreadCrumbOCD += , @('wmic' ,'Wmic')
|
|
$BreadCrumbOCD += , @('rundll' ,'RunDll')
|
|
$BreadCrumbOCD += , @('var+' ,'Var+')
|
|
$BreadCrumbOCD += , @('stdin+' ,'StdIn+')
|
|
$BreadCrumbOCD += , @('clip+' ,'Clip+')
|
|
$BreadCrumbOCD += , @('var++' ,'Var++')
|
|
$BreadCrumbOCD += , @('stdin++' ,'StdIn++')
|
|
$BreadCrumbOCD += , @('clip++' ,'Clip++')
|
|
$BreadCrumbOCD += , @('rundll++','RunDll++')
|
|
$BreadCrumbOCD += , @('mshta++' ,'Mshta++')
|
|
|
|
$BreadCrumbArray = @()
|
|
ForEach($Crumb in $BreadCrumb.Split('_'))
|
|
{
|
|
# Perform casing substitutions for any matches in $BreadCrumbOCD array.
|
|
$StillLookingForSubstitution = $TRUE
|
|
ForEach($Substitution in $BreadCrumbOCD)
|
|
{
|
|
If($Crumb.ToLower() -eq $Substitution[0])
|
|
{
|
|
$BreadCrumbArray += $Substitution[1]
|
|
$StillLookingForSubstitution = $FALSE
|
|
}
|
|
}
|
|
|
|
# If no substitution occurred above then simply upper-case the first character and lower-case all the remaining characters.
|
|
If($StillLookingForSubstitution)
|
|
{
|
|
$BreadCrumbArray += $Crumb.SubString(0,1).ToUpper() + $Crumb.SubString(1).ToLower()
|
|
|
|
# If no substitution was found for the 3rd or later BreadCrumb element (only for Launcher BreadCrumb) then throw a warning so we can add this substitution pair to $BreadCrumbOCD.
|
|
If(($BreadCrumb.Split('_').Count -eq 2) -AND ($BreadCrumb.StartsWith('Launcher_')) -AND ($Crumb -ne 'Launcher'))
|
|
{
|
|
Write-Warning "No substituion pair was found for `$Crumb=$Crumb in `$BreadCrumb=$BreadCrumb. Add this `$Crumb substitution pair to `$BreadCrumbOCD array in Invoke-Obfuscation."
|
|
}
|
|
}
|
|
}
|
|
$BreadCrumb = $BreadCrumbArray -Join '\'
|
|
}
|
|
$BreadCrumb = '\' + $BreadCrumb
|
|
}
|
|
|
|
# Output menu heading.
|
|
$FirstLine = "Choose one of the below "
|
|
If($BreadCrumb -ne '')
|
|
{
|
|
$FirstLine = $FirstLine + $BreadCrumb.Trim('\') + ' '
|
|
}
|
|
Write-Host "$FirstLine" -NoNewLine
|
|
|
|
# Change color and verbiage if selection will execute command.
|
|
If($SelectionContainsCommand)
|
|
{
|
|
Write-Host "options" -NoNewLine -ForegroundColor Green
|
|
Write-Host " to" -NoNewLine
|
|
Write-Host " APPLY" -NoNewLine -ForegroundColor Green
|
|
Write-Host " to current payload" -NoNewLine
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "options" -NoNewLine -ForegroundColor Yellow
|
|
}
|
|
Write-Host ":`n"
|
|
|
|
ForEach($Line in $Menu)
|
|
{
|
|
$LineSpace = $Line[0]
|
|
$LineOption = $Line[1]
|
|
$LineValue = $Line[2]
|
|
Write-Host $LineSpace -NoNewLine
|
|
|
|
# If not empty then include breadcrumb in $LineOption output (is not colored and won't affect user input syntax).
|
|
If(($BreadCrumb -ne '') -AND ($LineSpace.StartsWith('[')))
|
|
{
|
|
Write-Host ($BreadCrumb.ToUpper().Trim('\') + '\') -NoNewLine
|
|
}
|
|
|
|
# Change color if selection will execute command.
|
|
If($SelectionContainsCommand)
|
|
{
|
|
Write-Host $LineOption -NoNewLine -ForegroundColor Green
|
|
}
|
|
Else
|
|
{
|
|
Write-Host $LineOption -NoNewLine -ForegroundColor Yellow
|
|
}
|
|
|
|
# Add additional coloring to string encapsulated by <> if it exists in $LineValue.
|
|
If($LineValue.Contains('<') -AND $LineValue.Contains('>'))
|
|
{
|
|
$FirstPart = $LineValue.SubString(0,$LineValue.IndexOf('<'))
|
|
$MiddlePart = $LineValue.SubString($FirstPart.Length+1)
|
|
$MiddlePart = $MiddlePart.SubString(0,$MiddlePart.IndexOf('>'))
|
|
$LastPart = $LineValue.SubString($FirstPart.Length+$MiddlePart.Length+2)
|
|
Write-Host "`t$FirstPart" -NoNewLine
|
|
Write-Host $MiddlePart -NoNewLine -ForegroundColor Cyan
|
|
|
|
# Handle if more than one term needs to be output in different color.
|
|
If($LastPart.Contains('<') -AND $LastPart.Contains('>'))
|
|
{
|
|
$LineValue = $LastPart
|
|
$FirstPart = $LineValue.SubString(0,$LineValue.IndexOf('<'))
|
|
$MiddlePart = $LineValue.SubString($FirstPart.Length+1)
|
|
$MiddlePart = $MiddlePart.SubString(0,$MiddlePart.IndexOf('>'))
|
|
$LastPart = $LineValue.SubString($FirstPart.Length+$MiddlePart.Length+2)
|
|
Write-Host "$FirstPart" -NoNewLine
|
|
Write-Host $MiddlePart -NoNewLine -ForegroundColor Cyan
|
|
}
|
|
|
|
Write-Host $LastPart
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "`t$LineValue"
|
|
}
|
|
}
|
|
|
|
# Prompt for user input with custom breadcrumb prompt.
|
|
Write-Host ''
|
|
If($UserInput -ne '') {Write-Host ''}
|
|
$UserInput = ''
|
|
|
|
While(($UserInput -eq '') -AND ($Script:CompoundCommand.Count -eq 0))
|
|
{
|
|
# Output custom prompt.
|
|
Write-Host "Invoke-Obfuscation$BreadCrumb> " -NoNewLine -ForegroundColor Magenta
|
|
|
|
# Get interactive user input if CliCommands input variable was not specified by user.
|
|
If(($Script:CliCommands.Count -gt 0) -OR ($Script:CliCommands -ne $NULL))
|
|
{
|
|
If($Script:CliCommands.GetType().Name -eq 'String')
|
|
{
|
|
$NextCliCommand = $Script:CliCommands.Trim()
|
|
$Script:CliCommands = @()
|
|
}
|
|
Else
|
|
{
|
|
$NextCliCommand = ([String]$Script:CliCommands[0]).Trim()
|
|
$Script:CliCommands = For($i=1; $i -lt $Script:CliCommands.Count; $i++) {$Script:CliCommands[$i]}
|
|
}
|
|
|
|
$UserInput = $NextCliCommand
|
|
}
|
|
Else
|
|
{
|
|
# If Command was defined on command line and NoExit switch was not defined then output final ObfuscatedCommand to stdout and then quit. Otherwise continue with interactive Invoke-Obfuscation.
|
|
If($CliWasSpecified -AND ($Script:CliCommands.Count -lt 1) -AND ($Script:CompoundCommand.Count -lt 1) -AND ($Script:QuietWasSpecified -OR !$NoExitWasSpecified))
|
|
{
|
|
If($Script:QuietWasSpecified)
|
|
{
|
|
# Remove Write-Host and Start-Sleep proxy functions so that Write-Host and Start-Sleep cmdlets will be called during the remainder of the interactive Invoke-Obfuscation session.
|
|
Remove-Item -Path Function:Write-Host
|
|
Remove-Item -Path Function:Start-Sleep
|
|
|
|
$Script:QuietWasSpecified = $FALSE
|
|
|
|
# Automatically run 'Show Options' so the user has context of what has successfully been executed.
|
|
$UserInput = 'show options'
|
|
$BreadCrumb = 'Show Options'
|
|
}
|
|
# -NoExit wasn't specified and -Command was, so we will output the result back in the main While loop.
|
|
If(!$NoExitWasSpecified)
|
|
{
|
|
$UserInput = 'quit'
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
$UserInput = (Read-Host).Trim()
|
|
}
|
|
|
|
# Process interactive UserInput using CLI syntax, so comma-delimited and slash-delimited commands can be processed interactively.
|
|
If(($Script:CliCommands.Count -eq 0) -AND !$UserInput.ToLower().StartsWith('set ') -AND $UserInput.Contains(','))
|
|
{
|
|
$Script:CliCommands = $UserInput.Split(',')
|
|
|
|
# Reset $UserInput so current While loop will be traversed once more and process UserInput command as a CliCommand.
|
|
$UserInput = ''
|
|
}
|
|
}
|
|
}
|
|
|
|
# Trim any leading trailing slashes so it doesn't misinterpret it as a compound command unnecessarily.
|
|
$UserInput = $UserInput.Trim('/\')
|
|
|
|
# Cause UserInput of base menu level directories to automatically work.
|
|
# The only exception is STRING if the current MenuName is _token since it can be the base menu STRING or TOKEN/STRING.
|
|
If((($MenuLevel | ForEach-Object {$_[1].Trim()}) -Contains $UserInput.Split('/\')[0]) -AND !(('string' -Contains $UserInput.Split('/\')[0]) -AND ($MenuName -eq '_token')) -AND ($MenuName -ne ''))
|
|
{
|
|
$UserInput = 'home/' + $UserInput.Trim()
|
|
}
|
|
|
|
# If current command contains \ or / and does not start with SET or OUT then we are dealing with a compound command.
|
|
# Setting $Script:CompounCommand in below IF block.
|
|
If(($Script:CompoundCommand.Count -eq 0) -AND !$UserInput.ToLower().StartsWith('set ') -AND !$UserInput.ToLower().StartsWith('out ') -AND ($UserInput.Contains('\') -OR $UserInput.Contains('/')))
|
|
{
|
|
$Script:CompoundCommand = $UserInput.Split('/\')
|
|
}
|
|
|
|
# If current command contains \ or / and does not start with SET then we are dealing with a compound command.
|
|
# Parsing out next command from $Script:CompounCommand in below IF block.
|
|
If($Script:CompoundCommand.Count -gt 0)
|
|
{
|
|
$UserInput = ''
|
|
While(($UserInput -eq '') -AND ($Script:CompoundCommand.Count -gt 0))
|
|
{
|
|
# If last compound command then it will be a string.
|
|
If($Script:CompoundCommand.GetType().Name -eq 'String')
|
|
{
|
|
$NextCompoundCommand = $Script:CompoundCommand.Trim()
|
|
$Script:CompoundCommand = @()
|
|
}
|
|
Else
|
|
{
|
|
# If there are more commands left in compound command then it won't be a string (above IF block).
|
|
# In this else block we get the next command from CompoundCommand array.
|
|
$NextCompoundCommand = ([String]$Script:CompoundCommand[0]).Trim()
|
|
|
|
# Set remaining commands back into CompoundCommand.
|
|
$Temp = $Script:CompoundCommand
|
|
$Script:CompoundCommand = @()
|
|
For($i=1; $i -lt $Temp.Count; $i++)
|
|
{
|
|
$Script:CompoundCommand += $Temp[$i]
|
|
}
|
|
}
|
|
$UserInput = $NextCompoundCommand
|
|
}
|
|
}
|
|
|
|
# Handle new RegEx functionality.
|
|
# Identify if there is any regex in current UserInput by removing all alphanumeric characters (and + or # which are found in launcher names).
|
|
$TempUserInput = $UserInput.ToLower()
|
|
@(97..122) | ForEach-Object {$TempUserInput = $TempUserInput.Replace([String]([Char]$_),'')}
|
|
@(0..9) | ForEach-Object {$TempUserInput = $TempUserInput.Replace($_,'')}
|
|
$TempUserInput = $TempUserInput.Replace(' ','').Replace('+','').Replace('#','').Replace('\','').Replace('/','').Replace('-','').Replace('?','')
|
|
|
|
If(($TempUserInput.Length -gt 0) -AND !($UserInput.Trim().ToLower().StartsWith('set ')) -AND !($UserInput.Trim().ToLower().StartsWith('out ')))
|
|
{
|
|
# Replace any simple wildcard with .* syntax.
|
|
$UserInput = $UserInput.Replace('.*','_____').Replace('*','.*').Replace('_____','.*')
|
|
|
|
# Prepend UserInput with ^ and append with $ if not already there.
|
|
If(!$UserInput.Trim().StartsWith('^') -AND !$UserInput.Trim().StartsWith('.*'))
|
|
{
|
|
$UserInput = '^' + $UserInput
|
|
}
|
|
If(!$UserInput.Trim().EndsWith('$') -AND !$UserInput.Trim().EndsWith('.*'))
|
|
{
|
|
$UserInput = $UserInput + '$'
|
|
}
|
|
|
|
# See if there are any filtered matches in the current menu.
|
|
Try
|
|
{
|
|
$MenuFiltered = ($Menu | Where-Object {($_[1].Trim() -Match $UserInput) -AND ($_[1].Trim().Length -gt 0)} | ForEach-Object {$_[1].Trim()})
|
|
}
|
|
Catch
|
|
{
|
|
# Output error message if Regular Expression causes error in above filtering step.
|
|
# E.g. Using *+ instead of *[+]
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host ' The current Regular Expression caused the following error:'
|
|
write-host " $_" -ForegroundColor Red
|
|
}
|
|
|
|
# If there are filtered matches in the current menu then randomly choose one for the UserInput value.
|
|
If($MenuFiltered -ne $NULL)
|
|
{
|
|
# Randomly select UserInput from filtered options.
|
|
$UserInput = (Get-Random -Input $MenuFiltered).Trim()
|
|
|
|
# Output randomly chosen option (and filtered options selected from) if more than one option were returned from regex.
|
|
If($MenuFiltered.Count -gt 1)
|
|
{
|
|
# Change color and verbiage if acceptable options will execute an obfuscation function.
|
|
If($SelectionContainsCommand)
|
|
{
|
|
$ColorToOutput = 'Green'
|
|
}
|
|
Else
|
|
{
|
|
$ColorToOutput = 'Yellow'
|
|
}
|
|
|
|
Write-Host "`n`nRandomly selected " -NoNewline
|
|
Write-Host $UserInput -NoNewline -ForegroundColor $ColorToOutput
|
|
write-host " from the following filtered options: " -NoNewline
|
|
|
|
For($i=0; $i -lt $MenuFiltered.Count-1; $i++)
|
|
{
|
|
Write-Host $MenuFiltered[$i].Trim() -NoNewLine -ForegroundColor $ColorToOutput
|
|
Write-Host ', ' -NoNewLine
|
|
}
|
|
Write-Host $MenuFiltered[$MenuFiltered.Count-1].Trim() -NoNewLine -ForegroundColor $ColorToOutput
|
|
}
|
|
}
|
|
}
|
|
|
|
# If $UserInput is all numbers and is in a menu in $MenusWithMultiSelectNumbers
|
|
$OverrideAcceptableInput = $FALSE
|
|
$MenusWithMultiSelectNumbers = @('\Launcher')
|
|
If(($UserInput.Trim(' 0123456789').Length -eq 0) -AND $BreadCrumb.Contains('\') -AND ($MenusWithMultiSelectNumbers -Contains $BreadCrumb.SubString(0,$BreadCrumb.LastIndexOf('\'))))
|
|
{
|
|
$OverrideAcceptableInput = $TRUE
|
|
}
|
|
|
|
If($ExitInputOptions -Contains $UserInput.ToLower())
|
|
{
|
|
Return $ExitInputOptions[0]
|
|
}
|
|
ElseIf($MenuInputOptions -Contains $UserInput.ToLower())
|
|
{
|
|
# Commands like 'back' that will return user to previous interactive menu.
|
|
If($BreadCrumb.Contains('\')) {$UserInput = $BreadCrumb.SubString(0,$BreadCrumb.LastIndexOf('\')).Replace('\','_')}
|
|
Else {$UserInput = ''}
|
|
|
|
Return $UserInput.ToLower()
|
|
}
|
|
ElseIf($HomeMenuInputOptions[0] -Contains $UserInput.ToLower())
|
|
{
|
|
Return $UserInput.ToLower()
|
|
}
|
|
ElseIf($UserInput.ToLower().StartsWith('set '))
|
|
{
|
|
# Extract $UserInputOptionName and $UserInputOptionValue from $UserInput SET command.
|
|
$UserInputOptionName = $NULL
|
|
$UserInputOptionValue = $NULL
|
|
$HasError = $FALSE
|
|
|
|
$UserInputMinusSet = $UserInput.SubString(4).Trim()
|
|
If($UserInputMinusSet.IndexOf(' ') -eq -1)
|
|
{
|
|
$HasError = $TRUE
|
|
$UserInputOptionName = $UserInputMinusSet.Trim()
|
|
}
|
|
Else
|
|
{
|
|
$UserInputOptionName = $UserInputMinusSet.SubString(0,$UserInputMinusSet.IndexOf(' ')).Trim().ToLower()
|
|
$UserInputOptionValue = $UserInputMinusSet.SubString($UserInputMinusSet.IndexOf(' ')).Trim()
|
|
}
|
|
|
|
# Validate that $UserInputOptionName is defined in $SettableInputOptions.
|
|
If($SettableInputOptions -Contains $UserInputOptionName)
|
|
{
|
|
# Perform separate validation for $UserInputOptionValue before setting value. Set to 'emptyvalue' if no value was entered.
|
|
If($UserInputOptionValue.Length -eq 0) {$UserInputOptionName = 'emptyvalue'}
|
|
Switch($UserInputOptionName.ToLower())
|
|
{
|
|
'scriptpath' {
|
|
If($UserInputOptionValue -AND ((Test-Path $UserInputOptionValue) -OR ($UserInputOptionValue -Match '(http|https)://')))
|
|
{
|
|
# Reset ScriptBlock in case it contained a value.
|
|
$Script:ScriptBlock = ''
|
|
|
|
# Check if user-input ScriptPath is a URL or a directory.
|
|
If($UserInputOptionValue -Match '(http|https)://')
|
|
{
|
|
# ScriptPath is a URL.
|
|
|
|
# Download content.
|
|
$Script:ScriptBlock = (New-Object Net.WebClient).DownloadString($UserInputOptionValue)
|
|
|
|
# Set script-wide variables for future reference.
|
|
$Script:ScriptPath = $UserInputOptionValue
|
|
$Script:ObfuscatedCommand = $Script:ScriptBlock
|
|
$Script:ObfuscatedCommandHistory = @()
|
|
$Script:ObfuscatedCommandHistory += $Script:ScriptBlock
|
|
$Script:CliSyntax = @()
|
|
$Script:ExecutionCommands = @()
|
|
$Script:LauncherApplied = $FALSE
|
|
|
|
Write-Host "`n`nSuccessfully set ScriptPath (as URL):" -ForegroundColor Cyan
|
|
Write-Host $Script:ScriptPath -ForegroundColor Magenta
|
|
}
|
|
ElseIf ((Get-Item $UserInputOptionValue) -is [System.IO.DirectoryInfo])
|
|
{
|
|
# ScriptPath does not exist.
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host ' Path is a directory instead of a file (' -NoNewLine
|
|
Write-Host "$UserInputOptionValue" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host ").`n" -NoNewLine
|
|
}
|
|
Else
|
|
{
|
|
# Read contents from user-input ScriptPath value.
|
|
Get-ChildItem $UserInputOptionValue -ErrorAction Stop | Out-Null
|
|
$Script:ScriptBlock = [IO.File]::ReadAllText((Resolve-Path $UserInputOptionValue))
|
|
|
|
# Set script-wide variables for future reference.
|
|
$Script:ScriptPath = $UserInputOptionValue
|
|
$Script:ObfuscatedCommand = $Script:ScriptBlock
|
|
$Script:ObfuscatedCommandHistory = @()
|
|
$Script:ObfuscatedCommandHistory += $Script:ScriptBlock
|
|
$Script:CliSyntax = @()
|
|
$Script:ExecutionCommands = @()
|
|
$Script:LauncherApplied = $FALSE
|
|
|
|
Write-Host "`n`nSuccessfully set ScriptPath:" -ForegroundColor Cyan
|
|
Write-Host $Script:ScriptPath -ForegroundColor Magenta
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
# ScriptPath not found (failed Test-Path).
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host ' Path not found (' -NoNewLine
|
|
Write-Host "$UserInputOptionValue" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host ").`n" -NoNewLine
|
|
}
|
|
}
|
|
'scriptblock' {
|
|
# Remove evenly paired {} '' or "" if user includes it around their scriptblock input.
|
|
ForEach($Char in @(@('{','}'),@('"','"'),@("'","'")))
|
|
{
|
|
While($UserInputOptionValue.StartsWith($Char[0]) -AND $UserInputOptionValue.EndsWith($Char[1]))
|
|
{
|
|
$UserInputOptionValue = $UserInputOptionValue.SubString(1,$UserInputOptionValue.Length-2).Trim()
|
|
}
|
|
}
|
|
|
|
# Check if input is PowerShell encoded command syntax so we can decode for scriptblock.
|
|
If($UserInputOptionValue -Match 'powershell(.exe | )\s*-(e |ec |en |enc |enco |encod |encode)\s*["'']*[a-z=]')
|
|
{
|
|
# Extract encoded command.
|
|
$EncodedCommand = $UserInputOptionValue.SubString($UserInputOptionValue.ToLower().IndexOf(' -e')+3)
|
|
$EncodedCommand = $EncodedCommand.SubString($EncodedCommand.IndexOf(' ')).Trim(" '`"")
|
|
|
|
# Decode Unicode-encoded $EncodedCommand
|
|
$UserInputOptionValue = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($EncodedCommand))
|
|
}
|
|
|
|
# Set script-wide variables for future reference.
|
|
$Script:ScriptPath = 'N/A'
|
|
$Script:ScriptBlock = $UserInputOptionValue
|
|
$Script:ObfuscatedCommand = $UserInputOptionValue
|
|
$Script:ObfuscatedCommandHistory = @()
|
|
$Script:ObfuscatedCommandHistory += $UserInputOptionValue
|
|
$Script:CliSyntax = @()
|
|
$Script:ExecutionCommands = @()
|
|
$Script:LauncherApplied = $FALSE
|
|
|
|
Write-Host "`n`nSuccessfully set ScriptBlock:" -ForegroundColor Cyan
|
|
Write-Host $Script:ScriptBlock -ForegroundColor Magenta
|
|
}
|
|
'emptyvalue' {
|
|
# No OPTIONVALUE was entered after OPTIONNAME.
|
|
$HasError = $TRUE
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host ' No value was entered after' -NoNewLine
|
|
Write-Host ' SCRIPTBLOCK/SCRIPTPATH' -NoNewLine -ForegroundColor Cyan
|
|
Write-Host '.' -NoNewLine
|
|
}
|
|
default {Write-Error "An invalid OPTIONNAME ($UserInputOptionName) was passed to switch block."; Exit}
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
$HasError = $TRUE
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host ' OPTIONNAME' -NoNewLine
|
|
Write-Host " $UserInputOptionName" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " is not a settable option." -NoNewLine
|
|
}
|
|
|
|
If($HasError)
|
|
{
|
|
Write-Host "`n Correct syntax is" -NoNewLine
|
|
Write-Host ' SET OPTIONNAME VALUE' -NoNewLine -ForegroundColor Green
|
|
Write-Host '.' -NoNewLine
|
|
|
|
Write-Host "`n Enter" -NoNewLine
|
|
Write-Host ' SHOW OPTIONS' -NoNewLine -ForegroundColor Yellow
|
|
Write-Host ' for more details.'
|
|
}
|
|
}
|
|
ElseIf(($AcceptableInput -Contains $UserInput) -OR ($OverrideAcceptableInput))
|
|
{
|
|
# User input matches $AcceptableInput extracted from the current $Menu, so decide if:
|
|
# 1) an obfuscation function needs to be called and remain in current interactive prompt, or
|
|
# 2) return value to enter into a new interactive prompt.
|
|
|
|
# Format breadcrumb trail to successfully retrieve the next interactive prompt.
|
|
$UserInput = $BreadCrumb.Trim('\').Replace('\','_') + '_' + $UserInput
|
|
If($BreadCrumb.StartsWith('\')) {$UserInput = '_' + $UserInput}
|
|
|
|
# If the current selection contains a command to execute then continue. Otherwise return to go to another menu.
|
|
If($SelectionContainsCommand)
|
|
{
|
|
# Make sure user has entered command or path to script.
|
|
If($Script:ObfuscatedCommand -ne $NULL)
|
|
{
|
|
# Iterate through lines in $Menu to extract command for the current selection in $UserInput.
|
|
ForEach($Line in $Menu)
|
|
{
|
|
If($Line[1].Trim(' ') -eq $UserInput.SubString($UserInput.LastIndexOf('_')+1)) {$CommandToExec = $Line[3]; Continue}
|
|
}
|
|
|
|
If(!$OverrideAcceptableInput)
|
|
{
|
|
# Extract arguments from $CommandToExec.
|
|
$Function = $CommandToExec[0]
|
|
$Token = $CommandToExec[1]
|
|
$ObfLevel = $CommandToExec[2]
|
|
}
|
|
Else
|
|
{
|
|
# Overload above arguments if $OverrideAcceptableInput is $TRUE, and extract $Function from $BreadCrumb
|
|
Switch($BreadCrumb.ToLower())
|
|
{
|
|
'\launcher\ps' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 1}
|
|
'\launcher\cmd' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 2}
|
|
'\launcher\wmic' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 3}
|
|
'\launcher\rundll' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 4}
|
|
'\launcher\var+' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 5}
|
|
'\launcher\stdin+' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 6}
|
|
'\launcher\clip+' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 7}
|
|
'\launcher\var++' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 8}
|
|
'\launcher\stdin++' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 9}
|
|
'\launcher\clip++' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 10}
|
|
'\launcher\rundll++' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 11}
|
|
'\launcher\mshta++' {$Function = 'Out-PowerShellLauncher'; $ObfLevel = 12}
|
|
default {Write-Error "An invalid value ($($BreadCrumb.ToLower())) was passed to switch block for setting `$Function when `$OverrideAcceptableInput -eq `$TRUE."; Exit}
|
|
}
|
|
# Extract $ObfLevel from first element in array (in case 0th element is used for informational purposes), and extract $Token from $BreadCrumb.
|
|
$ObfLevel = $Menu[1][3][2]
|
|
$Token = $UserInput.SubString($UserInput.LastIndexOf('_')+1)
|
|
}
|
|
|
|
# Convert ObfuscatedCommand (string) to ScriptBlock for next obfuscation function.
|
|
If(!($Script:LauncherApplied))
|
|
{
|
|
$ObfCommandScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock($Script:ObfuscatedCommand)
|
|
}
|
|
|
|
# Validate that user has set SCRIPTPATH or SCRIPTBLOCK (by seeing if $Script:ObfuscatedCommand is empty).
|
|
If($Script:ObfuscatedCommand -eq '')
|
|
{
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " Cannot execute obfuscation commands without setting ScriptPath or ScriptBlock values in SHOW OPTIONS menu. Set these by executing" -NoNewLine
|
|
Write-Host ' SET SCRIPTBLOCK script_block_or_command' -NoNewLine -ForegroundColor Green
|
|
Write-Host ' or' -NoNewLine
|
|
Write-Host ' SET SCRIPTPATH path_to_script_or_URL' -NoNewLine -ForegroundColor Green
|
|
Write-Host '.'
|
|
Continue
|
|
}
|
|
|
|
# Save current ObfuscatedCommand to see if obfuscation was successful (i.e. no warnings prevented obfuscation from occurring).
|
|
$ObfuscatedCommandBefore = $Script:ObfuscatedCommand
|
|
$CmdToPrint = $NULL
|
|
|
|
If($Script:LauncherApplied)
|
|
{
|
|
If($Function -eq 'Out-PowerShellLauncher')
|
|
{
|
|
$ErrorMessage = ' You have already applied a launcher to ObfuscatedCommand.'
|
|
}
|
|
Else
|
|
{
|
|
$ErrorMessage = ' You cannot obfuscate after applying a Launcher to ObfuscatedCommand.'
|
|
}
|
|
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host $ErrorMessage -NoNewLine
|
|
Write-Host "`n Enter" -NoNewLine
|
|
Write-Host ' UNDO' -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to remove the launcher from ObfuscatedCommand.`n" -NoNewLine
|
|
}
|
|
Else
|
|
{
|
|
# Switch block to route to the correct function.
|
|
Switch($Function)
|
|
{
|
|
'Out-ObfuscatedTokenCommand' {
|
|
$Script:ObfuscatedCommand = Out-ObfuscatedTokenCommand -ScriptBlock $ObfCommandScriptBlock $Token $ObfLevel
|
|
$CmdToPrint = @("Out-ObfuscatedTokenCommand -ScriptBlock "," '$Token' $ObfLevel")
|
|
}
|
|
'Out-ObfuscatedTokenCommandAll' {
|
|
$Script:ObfuscatedCommand = Out-ObfuscatedTokenCommand -ScriptBlock $ObfCommandScriptBlock
|
|
$CmdToPrint = @("Out-ObfuscatedTokenCommand -ScriptBlock ","")
|
|
}
|
|
'Out-ObfuscatedStringCommand' {
|
|
$Script:ObfuscatedCommand = Out-ObfuscatedStringCommand -ScriptBlock $ObfCommandScriptBlock $ObfLevel
|
|
$CmdToPrint = @("Out-ObfuscatedStringCommand -ScriptBlock "," $ObfLevel")
|
|
}
|
|
'Out-EncodedAsciiCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedAsciiCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedAsciiCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-EncodedHexCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedHexCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedHexCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-EncodedOctalCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedOctalCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedOctalCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-EncodedBinaryCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedBinaryCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedBinaryCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-SecureStringCommand' {
|
|
$Script:ObfuscatedCommand = Out-SecureStringCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-SecureStringCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-EncodedBXORCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedBXORCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedBXORCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-EncodedSpecialCharOnlyCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedSpecialCharOnlyCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedSpecialCharOnlyCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-EncodedWhitespaceCommand' {
|
|
$Script:ObfuscatedCommand = Out-EncodedWhitespaceCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
|
|
$CmdToPrint = @("Out-EncodedWhitespaceCommand -ScriptBlock "," -PassThru")
|
|
}
|
|
'Out-PowerShellLauncher' {
|
|
# Extract numbers from string so we can output proper flag syntax in ExecutionCommands history.
|
|
$SwitchesAsStringArray = [char[]]$Token | Sort-Object -Unique | Where-Object {$_ -ne ' '}
|
|
|
|
If($SwitchesAsStringArray -Contains '0')
|
|
{
|
|
$CmdToPrint = @("Out-PowerShellLauncher -ScriptBlock "," $ObfLevel")
|
|
}
|
|
Else
|
|
{
|
|
$HasWindowStyle = $FALSE
|
|
$SwitchesToPrint = @()
|
|
ForEach($Value in $SwitchesAsStringArray)
|
|
{
|
|
Switch($Value)
|
|
{
|
|
1 {$SwitchesToPrint += '-NoExit'}
|
|
2 {$SwitchesToPrint += '-NonInteractive'}
|
|
3 {$SwitchesToPrint += '-NoLogo'}
|
|
4 {$SwitchesToPrint += '-NoProfile'}
|
|
5 {$SwitchesToPrint += '-Command'}
|
|
6 {If(!$HasWindowStyle) {$SwitchesToPrint += '-WindowStyle Hidden'; $HasWindowStyle = $TRUE}}
|
|
7 {$SwitchesToPrint += '-ExecutionPolicy Bypass'}
|
|
8 {$SwitchesToPrint += '-Wow64'}
|
|
default {Write-Error "An invalid `$SwitchesAsString value ($Value) was passed to switch block."; Exit;}
|
|
}
|
|
}
|
|
$SwitchesToPrint = $SwitchesToPrint -Join ' '
|
|
$CmdToPrint = @("Out-PowerShellLauncher -ScriptBlock "," $SwitchesToPrint $ObfLevel")
|
|
}
|
|
|
|
$Script:ObfuscatedCommand = Out-PowerShellLauncher -ScriptBlock $ObfCommandScriptBlock -SwitchesAsString $Token $ObfLevel
|
|
|
|
# Only set LauncherApplied to true if before/after are different (i.e. no warnings prevented launcher from being applied).
|
|
If($ObfuscatedCommandBefore -ne $Script:ObfuscatedCommand)
|
|
{
|
|
$Script:LauncherApplied = $TRUE
|
|
}
|
|
}
|
|
default {Write-Error "An invalid `$Function value ($Function) was passed to switch block."; Exit;}
|
|
}
|
|
|
|
If(($Script:ObfuscatedCommand -ceq $ObfuscatedCommandBefore) -AND ($MenuName.StartsWith('_Token_')))
|
|
{
|
|
Write-Host "`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " There were not any" -NoNewLine
|
|
If($BreadCrumb.SubString($BreadCrumb.LastIndexOf('\')+1).ToLower() -ne 'all') {Write-Host " $($BreadCrumb.SubString($BreadCrumb.LastIndexOf('\')+1))" -NoNewLine -ForegroundColor Yellow}
|
|
Write-Host " tokens to further obfuscate, so nothing changed."
|
|
}
|
|
Else
|
|
{
|
|
# Add to $Script:ObfuscatedCommandHistory if a change took place for the current ObfuscatedCommand.
|
|
$Script:ObfuscatedCommandHistory += , $Script:ObfuscatedCommand
|
|
|
|
# Convert UserInput to CLI syntax to store in CliSyntax variable if obfuscation occurred.
|
|
$CliSyntaxCurrentCommand = $UserInput.Trim('_ ').Replace('_','\')
|
|
|
|
# Add CLI command syntax to $Script:CliSyntax to maintain a history of commands to arrive at current obfuscated command for CLI syntax.
|
|
$Script:CliSyntax += $CliSyntaxCurrentCommand
|
|
|
|
# Add execution syntax to $Script:ExecutionCommands to maintain a history of commands to arrive at current obfuscated command.
|
|
$Script:ExecutionCommands += ($CmdToPrint[0] + '$ScriptBlock' + $CmdToPrint[1])
|
|
|
|
# Output syntax of CLI syntax and full command we executed in above Switch block.
|
|
Write-Host "`nExecuted:`t"
|
|
Write-Host " CLI: " -NoNewline
|
|
Write-Host $CliSyntaxCurrentCommand -ForegroundColor Cyan
|
|
Write-Host " FULL: " -NoNewline
|
|
Write-Host $CmdToPrint[0] -NoNewLine -ForegroundColor Cyan
|
|
Write-Host '$ScriptBlock' -NoNewLine -ForegroundColor Magenta
|
|
Write-Host $CmdToPrint[1] -ForegroundColor Cyan
|
|
|
|
# Output obfuscation result.
|
|
Write-Host "`nResult:`t"
|
|
Out-ScriptContents $Script:ObfuscatedCommand -PrintWarning
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
Return $UserInput
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
If ($MenuInputOptionsShowHelp[0] -Contains $UserInput) {Show-HelpMenu}
|
|
ElseIf($MenuInputOptionsShowOptions[0] -Contains $UserInput) {Show-OptionsMenu}
|
|
ElseIf($TutorialInputOptions[0] -Contains $UserInput) {Show-Tutorial}
|
|
ElseIf($ClearScreenInputOptions[0] -Contains $UserInput) {Clear-Host}
|
|
# For Version 1.0 ASCII art is not necessary.
|
|
#ElseIf($ShowAsciiArtInputOptions[0] -Contains $UserInput) {Show-AsciiArt -Random}
|
|
ElseIf($ResetObfuscationInputOptions[0] -Contains $UserInput)
|
|
{
|
|
If(($Script:ObfuscatedCommand -ne $NULL) -AND ($Script:ObfuscatedCommand.Length -eq 0))
|
|
{
|
|
Write-Host "`n`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " ObfuscatedCommand has not been set. There is nothing to reset."
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -ceq $Script:ScriptBlock)
|
|
{
|
|
Write-Host "`n`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " No obfuscation has been applied to ObfuscatedCommand. There is nothing to reset."
|
|
}
|
|
Else
|
|
{
|
|
$Script:LauncherApplied = $FALSE
|
|
$Script:ObfuscatedCommand = $Script:ScriptBlock
|
|
$Script:ObfuscatedCommandHistory = @($Script:ScriptBlock)
|
|
$Script:CliSyntax = @()
|
|
$Script:ExecutionCommands = @()
|
|
|
|
Write-Host "`n`nSuccessfully reset ObfuscatedCommand." -ForegroundColor Cyan
|
|
}
|
|
}
|
|
ElseIf($UndoObfuscationInputOptions[0] -Contains $UserInput)
|
|
{
|
|
If(($Script:ObfuscatedCommand -ne $NULL) -AND ($Script:ObfuscatedCommand.Length -eq 0))
|
|
{
|
|
Write-Host "`n`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " ObfuscatedCommand has not been set. There is nothing to undo."
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -ceq $Script:ScriptBlock)
|
|
{
|
|
Write-Host "`n`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " No obfuscation has been applied to ObfuscatedCommand. There is nothing to undo."
|
|
}
|
|
Else
|
|
{
|
|
# Set ObfuscatedCommand to the last state in ObfuscatedCommandHistory.
|
|
$Script:ObfuscatedCommand = $Script:ObfuscatedCommandHistory[$Script:ObfuscatedCommandHistory.Count-2]
|
|
|
|
# Remove the last state from ObfuscatedCommandHistory.
|
|
$Temp = $Script:ObfuscatedCommandHistory
|
|
$Script:ObfuscatedCommandHistory = @()
|
|
For($i=0; $i -lt $Temp.Count-1; $i++)
|
|
{
|
|
$Script:ObfuscatedCommandHistory += $Temp[$i]
|
|
}
|
|
|
|
# Remove last command from CliSyntax. Trim all trailing OUT or CLIP commands until an obfuscation command is removed.
|
|
$CliSyntaxCount = $Script:CliSyntax.Count
|
|
While(($Script:CliSyntax[$CliSyntaxCount-1] -Match '^(clip|out )') -AND ($CliSyntaxCount -gt 0))
|
|
{
|
|
$CliSyntaxCount--
|
|
}
|
|
$Temp = $Script:CliSyntax
|
|
$Script:CliSyntax = @()
|
|
For($i=0; $i -lt $CliSyntaxCount-1; $i++)
|
|
{
|
|
$Script:CliSyntax += $Temp[$i]
|
|
}
|
|
|
|
# Remove last command from ExecutionCommands.
|
|
$Temp = $Script:ExecutionCommands
|
|
$Script:ExecutionCommands = @()
|
|
For($i=0; $i -lt $Temp.Count-1; $i++)
|
|
{
|
|
$Script:ExecutionCommands += $Temp[$i]
|
|
}
|
|
|
|
# If this is removing a launcher then we must change the launcher state so we can continue obfuscating.
|
|
If($Script:LauncherApplied)
|
|
{
|
|
$Script:LauncherApplied = $FALSE
|
|
Write-Host "`n`nSuccessfully removed launcher from ObfuscatedCommand." -ForegroundColor Cyan
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "`n`nSuccessfully removed last obfuscation from ObfuscatedCommand." -ForegroundColor Cyan
|
|
}
|
|
}
|
|
}
|
|
ElseIf(($OutputToDiskInputOptions[0] -Contains $UserInput) -OR ($OutputToDiskInputOptions[0] -Contains $UserInput.Trim().Split(' ')[0]))
|
|
{
|
|
If(($Script:ObfuscatedCommand -ne '') -AND ($Script:ObfuscatedCommand -ceq $Script:ScriptBlock))
|
|
{
|
|
Write-Host "`n`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " You haven't applied any obfuscation.`n Just enter" -NoNewLine
|
|
Write-Host " SHOW OPTIONS" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " and look at ObfuscatedCommand."
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -ne '')
|
|
{
|
|
# Get file path information from compound user input (e.g. OUT C:\FILENAME.TXT).
|
|
If($UserInput.Trim().Split(' ').Count -gt 1)
|
|
{
|
|
# Get file path information from user input.
|
|
$UserInputOutputFilePath = $UserInput.Trim().SubString(4).Trim()
|
|
Write-Host ''
|
|
}
|
|
Else
|
|
{
|
|
# Get file path information from user interactively.
|
|
$UserInputOutputFilePath = Read-Host "`n`nEnter path for output file (or leave blank for default)"
|
|
}
|
|
# Decipher if user input a full file path, just a file name or nothing (default).
|
|
If($UserInputOutputFilePath.Trim() -eq '')
|
|
{
|
|
# User did not input anything so use default filename and current directory of this script.
|
|
$OutputFilePath = "$ScriptDir\Obfuscated_Command.txt"
|
|
}
|
|
ElseIf(!($UserInputOutputFilePath.Contains('\')) -AND !($UserInputOutputFilePath.Contains('/')))
|
|
{
|
|
# User input is not a file path so treat it as a filename and use current directory of this script.
|
|
$OutputFilePath = "$ScriptDir\$($UserInputOutputFilePath.Trim())"
|
|
}
|
|
Else
|
|
{
|
|
# User input is a full file path.
|
|
$OutputFilePath = $UserInputOutputFilePath
|
|
}
|
|
|
|
# Write ObfuscatedCommand out to disk.
|
|
Write-Output $Script:ObfuscatedCommand > $OutputFilePath
|
|
|
|
If($Script:LauncherApplied -AND (Test-Path $OutputFilePath))
|
|
{
|
|
$Script:CliSyntax += "out $OutputFilePath"
|
|
Write-Host "`nSuccessfully output ObfuscatedCommand to" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " $OutputFilePath" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host ".`nA Launcher has been applied so this script cannot be run as a standalone .ps1 file." -ForegroundColor Cyan
|
|
If($Env:windir) { C:\Windows\Notepad.exe $OutputFilePath }
|
|
}
|
|
ElseIf(!$Script:LauncherApplied -AND (Test-Path $OutputFilePath))
|
|
{
|
|
$Script:CliSyntax += "out $OutputFilePath"
|
|
Write-Host "`nSuccessfully output ObfuscatedCommand to" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " $OutputFilePath" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host "." -ForegroundColor Cyan
|
|
If($Env:windir) { C:\Windows\Notepad.exe $OutputFilePath }
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "`nERROR: Unable to write ObfuscatedCommand out to" -NoNewLine -ForegroundColor Red
|
|
Write-Host " $OutputFilePath" -NoNewLine -ForegroundColor Yellow
|
|
}
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -eq '')
|
|
{
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " There isn't anything to write out to disk.`n Just enter" -NoNewLine
|
|
Write-Host " SHOW OPTIONS" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " and look at ObfuscatedCommand."
|
|
}
|
|
}
|
|
ElseIf($CopyToClipboardInputOptions[0] -Contains $UserInput)
|
|
{
|
|
If(($Script:ObfuscatedCommand -ne '') -AND ($Script:ObfuscatedCommand -ceq $Script:ScriptBlock))
|
|
{
|
|
Write-Host "`n`nWARNING:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " You haven't applied any obfuscation.`n Just enter" -NoNewLine
|
|
Write-Host " SHOW OPTIONS" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " and look at ObfuscatedCommand."
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -ne '')
|
|
{
|
|
# Copy ObfuscatedCommand to clipboard.
|
|
# Try-Catch block introduced since PowerShell v2.0 without -STA defined will not be able to perform clipboard functionality.
|
|
Try
|
|
{
|
|
$Null = [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
|
|
[Windows.Forms.Clipboard]::SetText($Script:ObfuscatedCommand)
|
|
|
|
If($Script:LauncherApplied)
|
|
{
|
|
Write-Host "`n`nSuccessfully copied ObfuscatedCommand to clipboard." -ForegroundColor Cyan
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "`n`nSuccessfully copied ObfuscatedCommand to clipboard.`nNo Launcher has been applied, so command can only be pasted into powershell.exe." -ForegroundColor Cyan
|
|
}
|
|
}
|
|
Catch
|
|
{
|
|
$ErrorMessage = "Clipboard functionality will not work in PowerShell version $($PsVersionTable.PsVersion.Major) unless you add -STA (Single-Threaded Apartment) execution flag to powershell.exe."
|
|
|
|
If((Get-Command Write-Host).CommandType -ne 'Cmdlet')
|
|
{
|
|
# Retrieving Write-Host and Start-Sleep Cmdlets to get around the current proxy functions of Write-Host and Start-Sleep that are overloaded if -Quiet flag was used.
|
|
. ((Get-Command Write-Host) | Where-Object {$_.CommandType -eq 'Cmdlet'}) "`n`nWARNING: " -NoNewLine -ForegroundColor Red
|
|
. ((Get-Command Write-Host) | Where-Object {$_.CommandType -eq 'Cmdlet'}) $ErrorMessage -NoNewLine
|
|
|
|
. ((Get-Command Start-Sleep) | Where-Object {$_.CommandType -eq 'Cmdlet'}) 2
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "`n`nWARNING: " -NoNewLine -ForegroundColor Red
|
|
Write-Host $ErrorMessage
|
|
|
|
If($Script:CliSyntax -gt 0) {Start-Sleep 2}
|
|
}
|
|
}
|
|
|
|
$Script:CliSyntax += 'clip'
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -eq '')
|
|
{
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " There isn't anything to copy to your clipboard.`n Just enter" -NoNewLine
|
|
Write-Host " SHOW OPTIONS" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " and look at ObfuscatedCommand." -NoNewLine
|
|
}
|
|
|
|
}
|
|
ElseIf($ExecutionInputOptions[0] -Contains $UserInput)
|
|
{
|
|
If($Script:LauncherApplied)
|
|
{
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " Cannot execute because you have applied a Launcher.`n Enter" -NoNewLine
|
|
Write-Host " COPY" -NoNewLine -ForeGroundColor Yellow
|
|
Write-Host "/" -NoNewLine
|
|
Write-Host "CLIP" -NoNewLine -ForeGroundColor Yellow
|
|
Write-Host " and paste into cmd.exe.`n Or enter" -NoNewLine
|
|
Write-Host " UNDO" -NoNewLine -ForeGroundColor Yellow
|
|
Write-Host " to remove the Launcher from ObfuscatedCommand."
|
|
}
|
|
ElseIf($Script:ObfuscatedCommand -ne '')
|
|
{
|
|
If($Script:ObfuscatedCommand -ceq $Script:ScriptBlock) {Write-Host "`n`nInvoking (though you haven't obfuscated anything yet):"}
|
|
Else {Write-Host "`n`nInvoking:"}
|
|
|
|
Out-ScriptContents $Script:ObfuscatedCommand
|
|
Write-Host ''
|
|
$null = Invoke-Expression $Script:ObfuscatedCommand
|
|
}
|
|
Else {
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " Cannot execute because you have not set ScriptPath or ScriptBlock.`n Enter" -NoNewline
|
|
Write-Host " SHOW OPTIONS" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to set ScriptPath or ScriptBlock."
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "`n`nERROR:" -NoNewLine -ForegroundColor Red
|
|
Write-Host " You entered an invalid option. Enter" -NoNewLine
|
|
Write-Host " HELP" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " for more information."
|
|
|
|
# If the failed input was part of $Script:CompoundCommand then cancel out the rest of the compound command so it is not further processed.
|
|
If($Script:CompoundCommand.Count -gt 0)
|
|
{
|
|
$Script:CompoundCommand = @()
|
|
}
|
|
|
|
# Output all available/acceptable options for current menu if invalid input was entered.
|
|
If($AcceptableInput.Count -gt 1)
|
|
{
|
|
$Message = 'Valid options for current menu include:'
|
|
}
|
|
Else
|
|
{
|
|
$Message = 'Valid option for current menu includes:'
|
|
}
|
|
Write-Host " $Message " -NoNewLine
|
|
|
|
$Counter=0
|
|
ForEach($AcceptableOption in $AcceptableInput)
|
|
{
|
|
$Counter++
|
|
|
|
# Change color and verbiage if acceptable options will execute an obfuscation function.
|
|
If($SelectionContainsCommand)
|
|
{
|
|
$ColorToOutput = 'Green'
|
|
}
|
|
Else
|
|
{
|
|
$ColorToOutput = 'Yellow'
|
|
}
|
|
|
|
Write-Host $AcceptableOption -NoNewLine -ForegroundColor $ColorToOutput
|
|
If(($Counter -lt $AcceptableInput.Length) -AND ($AcceptableOption.Length -gt 0))
|
|
{
|
|
Write-Host ', ' -NoNewLine
|
|
}
|
|
}
|
|
Write-Host ''
|
|
}
|
|
}
|
|
}
|
|
|
|
Return $UserInput.ToLower()
|
|
}
|
|
|
|
|
|
Function Show-OptionsMenu
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
HELPER FUNCTION :: Displays options menu for Invoke-Obfuscation.
|
|
|
|
Invoke-Obfuscation Function: Show-OptionsMenu
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Show-OptionsMenu displays options menu for Invoke-Obfuscation.
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Show-OptionsMenu
|
|
|
|
.NOTES
|
|
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
|
|
# Set potentially-updated script-level values in $Script:OptionsMenu before displaying.
|
|
$Counter = 0
|
|
ForEach($Line in $Script:OptionsMenu)
|
|
{
|
|
If($Line[0].ToLower().Trim() -eq 'scriptpath') {$Script:OptionsMenu[$Counter][1] = $Script:ScriptPath}
|
|
If($Line[0].ToLower().Trim() -eq 'scriptblock') {$Script:OptionsMenu[$Counter][1] = $Script:ScriptBlock}
|
|
If($Line[0].ToLower().Trim() -eq 'commandlinesyntax') {$Script:OptionsMenu[$Counter][1] = $Script:CliSyntax}
|
|
If($Line[0].ToLower().Trim() -eq 'executioncommands') {$Script:OptionsMenu[$Counter][1] = $Script:ExecutionCommands}
|
|
If($Line[0].ToLower().Trim() -eq 'obfuscatedcommand')
|
|
{
|
|
# Only add obfuscatedcommand if it is different than scriptblock (to avoid showing obfuscatedcommand before it has been obfuscated).
|
|
If($Script:ObfuscatedCommand -cne $Script:ScriptBlock) {$Script:OptionsMenu[$Counter][1] = $Script:ObfuscatedCommand}
|
|
Else {$Script:OptionsMenu[$Counter][1] = ''}
|
|
}
|
|
If($Line[0].ToLower().Trim() -eq 'obfuscationlength')
|
|
{
|
|
# Only set/display ObfuscationLength if there is an obfuscated command.
|
|
If(($Script:ObfuscatedCommand.Length -gt 0) -AND ($Script:ObfuscatedCommand -cne $Script:ScriptBlock)) {$Script:OptionsMenu[$Counter][1] = $Script:ObfuscatedCommand.Length}
|
|
Else {$Script:OptionsMenu[$Counter][1] = ''}
|
|
}
|
|
|
|
$Counter++
|
|
}
|
|
|
|
# Output menu.
|
|
Write-Host "`n`nSHOW OPTIONS" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " ::" -NoNewLine
|
|
Write-Host " Yellow" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " options can be set by entering" -NoNewLine
|
|
Write-Host " SET OPTIONNAME VALUE" -NoNewLine -ForegroundColor Green
|
|
Write-Host ".`n"
|
|
ForEach($Option in $Script:OptionsMenu)
|
|
{
|
|
$OptionTitle = $Option[0]
|
|
$OptionValue = $Option[1]
|
|
$CanSetValue = $Option[2]
|
|
|
|
Write-Host $LineSpacing -NoNewLine
|
|
|
|
# For options that can be set by user, output as Yellow.
|
|
If($CanSetValue) {Write-Host $OptionTitle -NoNewLine -ForegroundColor Yellow}
|
|
Else {Write-Host $OptionTitle -NoNewLine}
|
|
Write-Host ": " -NoNewLine
|
|
|
|
# Handle coloring and multi-value output for ExecutionCommands and ObfuscationLength.
|
|
If($OptionTitle -eq 'ObfuscationLength')
|
|
{
|
|
Write-Host $OptionValue -ForegroundColor Cyan
|
|
}
|
|
ElseIf($OptionTitle -eq 'ScriptBlock')
|
|
{
|
|
Out-ScriptContents $OptionValue
|
|
}
|
|
ElseIf($OptionTitle -eq 'CommandLineSyntax')
|
|
{
|
|
# CLISyntax output.
|
|
$SetSyntax = ''
|
|
If(($Script:ScriptPath.Length -gt 0) -AND ($Script:ScriptPath -ne 'N/A'))
|
|
{
|
|
$SetSyntax = " -ScriptPath '$Script:ScriptPath'"
|
|
}
|
|
ElseIf(($Script:ScriptBlock.Length -gt 0) -AND ($Script:ScriptPath -eq 'N/A'))
|
|
{
|
|
$SetSyntax = " -ScriptBlock {$Script:ScriptBlock}"
|
|
}
|
|
|
|
$CommandSyntax = ''
|
|
If($OptionValue.Count -gt 0)
|
|
{
|
|
$CommandSyntax = " -Command '" + ($OptionValue -Join ',') + "' -Quiet"
|
|
}
|
|
|
|
If(($SetSyntax -ne '') -OR ($CommandSyntax -ne ''))
|
|
{
|
|
$CliSyntaxToOutput = "Invoke-Obfuscation" + $SetSyntax + $CommandSyntax
|
|
Write-Host $CliSyntaxToOutput -ForegroundColor Cyan
|
|
}
|
|
Else
|
|
{
|
|
Write-Host ''
|
|
}
|
|
}
|
|
ElseIf($OptionTitle -eq 'ExecutionCommands')
|
|
{
|
|
# ExecutionCommands output.
|
|
If($OptionValue.Count -gt 0) {Write-Host ''}
|
|
$Counter = 0
|
|
ForEach($ExecutionCommand in $OptionValue)
|
|
{
|
|
$Counter++
|
|
If($ExecutionCommand.Length -eq 0) {Write-Host ''; Continue}
|
|
|
|
$ExecutionCommand = $ExecutionCommand.Replace('$ScriptBlock','~').Split('~')
|
|
Write-Host " $($ExecutionCommand[0])" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host '$ScriptBlock' -NoNewLine -ForegroundColor Magenta
|
|
|
|
# Handle output formatting when SHOW OPTIONS is run.
|
|
If(($OptionValue.Count -gt 0) -AND ($Counter -lt $OptionValue.Count))
|
|
{
|
|
Write-Host $ExecutionCommand[1] -ForegroundColor Cyan
|
|
}
|
|
Else
|
|
{
|
|
Write-Host $ExecutionCommand[1] -NoNewLine -ForegroundColor Cyan
|
|
}
|
|
|
|
}
|
|
Write-Host ''
|
|
}
|
|
ElseIf($OptionTitle -eq 'ObfuscatedCommand')
|
|
{
|
|
Out-ScriptContents $OptionValue
|
|
}
|
|
Else
|
|
{
|
|
Write-Host $OptionValue -ForegroundColor Magenta
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Function Show-HelpMenu
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
HELPER FUNCTION :: Displays help menu for Invoke-Obfuscation.
|
|
|
|
Invoke-Obfuscation Function: Show-HelpMenu
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Show-HelpMenu displays help menu for Invoke-Obfuscation.
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Show-HelpMenu
|
|
|
|
.NOTES
|
|
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
|
|
# Show Help Menu.
|
|
Write-Host "`n`nHELP MENU" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " :: Available" -NoNewLine
|
|
Write-Host " options" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " shown below:`n"
|
|
ForEach($InputOptionsList in $AllAvailableInputOptionsLists)
|
|
{
|
|
$InputOptionsCommands = $InputOptionsList[0]
|
|
$InputOptionsDescription = $InputOptionsList[1]
|
|
|
|
# Add additional coloring to string encapsulated by <> if it exists in $InputOptionsDescription.
|
|
If($InputOptionsDescription.Contains('<') -AND $InputOptionsDescription.Contains('>'))
|
|
{
|
|
$FirstPart = $InputOptionsDescription.SubString(0,$InputOptionsDescription.IndexOf('<'))
|
|
$MiddlePart = $InputOptionsDescription.SubString($FirstPart.Length+1)
|
|
$MiddlePart = $MiddlePart.SubString(0,$MiddlePart.IndexOf('>'))
|
|
$LastPart = $InputOptionsDescription.SubString($FirstPart.Length+$MiddlePart.Length+2)
|
|
Write-Host "$LineSpacing $FirstPart" -NoNewLine
|
|
Write-Host $MiddlePart -NoNewLine -ForegroundColor Cyan
|
|
Write-Host $LastPart -NoNewLine
|
|
}
|
|
Else
|
|
{
|
|
Write-Host "$LineSpacing $InputOptionsDescription" -NoNewLine
|
|
}
|
|
|
|
$Counter = 0
|
|
ForEach($Command in $InputOptionsCommands)
|
|
{
|
|
$Counter++
|
|
Write-Host $Command.ToUpper() -NoNewLine -ForegroundColor Yellow
|
|
If($Counter -lt $InputOptionsCommands.Count) {Write-Host ',' -NoNewLine}
|
|
}
|
|
Write-Host ''
|
|
}
|
|
}
|
|
|
|
|
|
Function Show-Tutorial
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
HELPER FUNCTION :: Displays tutorial information for Invoke-Obfuscation.
|
|
|
|
Invoke-Obfuscation Function: Show-Tutorial
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Show-Tutorial displays tutorial information for Invoke-Obfuscation.
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Show-Tutorial
|
|
|
|
.NOTES
|
|
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
|
|
Write-Host "`n`nTUTORIAL" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " :: Here is a quick tutorial showing you how to get your obfuscation on:"
|
|
|
|
Write-Host "`n1) " -NoNewLine -ForegroundColor Cyan
|
|
Write-Host "Load a scriptblock (SET SCRIPTBLOCK) or a script path/URL (SET SCRIPTPATH)."
|
|
Write-Host " SET SCRIPTBLOCK Write-Host 'This is my test command' -ForegroundColor Green" -ForegroundColor Green
|
|
|
|
Write-Host "`n2) " -NoNewLine -ForegroundColor Cyan
|
|
Write-Host "Navigate through the obfuscation menus where the options are in" -NoNewLine
|
|
Write-Host " YELLOW" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host "."
|
|
Write-Host " GREEN" -NoNewLine -ForegroundColor Green
|
|
Write-Host " options apply obfuscation."
|
|
Write-Host " Enter" -NoNewLine
|
|
Write-Host " BACK" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host "/" -NoNewLine
|
|
Write-Host "CD .." -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to go to previous menu and" -NoNewLine
|
|
Write-Host " HOME" -NoNewline -ForegroundColor Yellow
|
|
Write-Host "/" -NoNewline
|
|
Write-Host "MAIN" -NoNewline -ForegroundColor Yellow
|
|
Write-Host " to go to home menu.`n E.g. Enter" -NoNewLine
|
|
Write-Host " ENCODING" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " & then" -NoNewLine
|
|
Write-Host " 5" -NoNewLine -ForegroundColor Green
|
|
Write-Host " to apply SecureString obfuscation."
|
|
|
|
Write-Host "`n3) " -NoNewLine -ForegroundColor Cyan
|
|
Write-Host "Enter" -NoNewLine
|
|
Write-Host " TEST" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host "/" -NoNewLine
|
|
Write-Host "EXEC" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to test the obfuscated command locally.`n Enter" -NoNewLine
|
|
Write-Host " SHOW" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to see the currently obfuscated command."
|
|
|
|
Write-Host "`n4) " -NoNewLine -ForegroundColor Cyan
|
|
Write-Host "Enter" -NoNewLine
|
|
Write-Host " COPY" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host "/" -NoNewLine
|
|
Write-Host "CLIP" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to copy obfuscated command out to your clipboard."
|
|
Write-Host " Enter" -NoNewLine
|
|
Write-Host " OUT" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to write obfuscated command out to disk."
|
|
|
|
Write-Host "`n5) " -NoNewLine -ForegroundColor Cyan
|
|
Write-Host "Enter" -NoNewLine
|
|
Write-Host " RESET" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to remove all obfuscation and start over.`n Enter" -NoNewLine
|
|
Write-Host " UNDO" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " to undo last obfuscation.`n Enter" -NoNewLine
|
|
Write-Host " HELP" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host "/" -NoNewLine
|
|
Write-Host "?" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " for help menu."
|
|
|
|
Write-Host "`nAnd finally the obligatory `"Don't use this for evil, please`"" -NoNewLine -ForegroundColor Cyan
|
|
Write-Host " :)" -ForegroundColor Green
|
|
}
|
|
|
|
|
|
Function Out-ScriptContents
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
HELPER FUNCTION :: Displays current obfuscated command for Invoke-Obfuscation.
|
|
|
|
Invoke-Obfuscation Function: Out-ScriptContents
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Out-ScriptContents displays current obfuscated command for Invoke-Obfuscation.
|
|
|
|
.PARAMETER ScriptContents
|
|
|
|
Specifies the string containing your payload.
|
|
|
|
.PARAMETER PrintWarning
|
|
|
|
Switch to output redacted form of ScriptContents if they exceed 8,190 characters.
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Out-ScriptContents
|
|
|
|
.NOTES
|
|
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
|
|
Param(
|
|
[Parameter(ValueFromPipeline = $true)]
|
|
[String]
|
|
$ScriptContents,
|
|
|
|
[Switch]
|
|
$PrintWarning
|
|
)
|
|
|
|
If($ScriptContents.Length -gt $CmdMaxLength)
|
|
{
|
|
# Output ScriptContents, handling if the size of ScriptContents exceeds $CmdMaxLength characters.
|
|
$RedactedPrintLength = $CmdMaxLength/5
|
|
|
|
# Handle printing redaction message in middle of screen. #OCD
|
|
$CmdLineWidth = (Get-Host).UI.RawUI.BufferSize.Width
|
|
$RedactionMessage = "<REDACTED: ObfuscatedLength = $($ScriptContents.Length)>"
|
|
$CenteredRedactionMessageStartIndex = (($CmdLineWidth-$RedactionMessage.Length)/2) - "[*] ObfuscatedCommand: ".Length
|
|
$CurrentRedactionMessageStartIndex = ($RedactedPrintLength % $CmdLineWidth)
|
|
|
|
If($CurrentRedactionMessageStartIndex -gt $CenteredRedactionMessageStartIndex)
|
|
{
|
|
$RedactedPrintLength = $RedactedPrintLength-($CurrentRedactionMessageStartIndex-$CenteredRedactionMessageStartIndex)
|
|
}
|
|
Else
|
|
{
|
|
$RedactedPrintLength = $RedactedPrintLength+($CenteredRedactionMessageStartIndex-$CurrentRedactionMessageStartIndex)
|
|
}
|
|
|
|
Write-Host $ScriptContents.SubString(0,$RedactedPrintLength) -NoNewLine -ForegroundColor Magenta
|
|
Write-Host $RedactionMessage -NoNewLine -ForegroundColor Yellow
|
|
Write-Host $ScriptContents.SubString($ScriptContents.Length-$RedactedPrintLength) -ForegroundColor Magenta
|
|
}
|
|
Else
|
|
{
|
|
Write-Host $ScriptContents -ForegroundColor Magenta
|
|
}
|
|
|
|
# Make sure final command doesn't exceed cmd.exe's character limit.
|
|
If($ScriptContents.Length -gt $CmdMaxLength)
|
|
{
|
|
If($PSBoundParameters['PrintWarning'])
|
|
{
|
|
Write-Host "`nWARNING: This command exceeds the cmd.exe maximum length of $CmdMaxLength." -ForegroundColor Red
|
|
Write-Host " Its length is" -NoNewLine -ForegroundColor Red
|
|
Write-Host " $($ScriptContents.Length)" -NoNewLine -ForegroundColor Yellow
|
|
Write-Host " characters." -ForegroundColor Red
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Function Show-AsciiArt
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
HELPER FUNCTION :: Displays random ASCII art for Invoke-Obfuscation.
|
|
|
|
Invoke-Obfuscation Function: Show-AsciiArt
|
|
Author: Daniel Bohannon (@danielhbohannon)
|
|
License: Apache License, Version 2.0
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Show-AsciiArt displays random ASCII art for Invoke-Obfuscation, and also displays ASCII art during script startup.
|
|
|
|
.EXAMPLE
|
|
|
|
C:\PS> Show-AsciiArt
|
|
|
|
.NOTES
|
|
|
|
Credit for ASCII art font generation: http://patorjk.com/software/taag/
|
|
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
|
|
|
|
.LINK
|
|
|
|
http://www.danielbohannon.com
|
|
#>
|
|
[CmdletBinding()] Param (
|
|
[Parameter(Position = 0)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[Switch]
|
|
$Random
|
|
)
|
|
|
|
# Create multiple ASCII art title banners.
|
|
$Spacing = "`t"
|
|
$InvokeObfuscationAscii = @()
|
|
$InvokeObfuscationAscii += $Spacing + ' ____ __ '
|
|
$InvokeObfuscationAscii += $Spacing + ' / _/___ _ ______ / /_____ '
|
|
$InvokeObfuscationAscii += $Spacing + ' / // __ \ | / / __ \/ //_/ _ \______ '
|
|
$InvokeObfuscationAscii += $Spacing + ' _/ // / / / |/ / /_/ / ,< / __/_____/ '
|
|
$InvokeObfuscationAscii += $Spacing + '/______ /__|_________/_/|_|\___/ __ _ '
|
|
$InvokeObfuscationAscii += $Spacing + ' / __ \/ /_ / __/_ ________________ _/ /_(_)___ ____ '
|
|
$InvokeObfuscationAscii += $Spacing + ' / / / / __ \/ /_/ / / / ___/ ___/ __ `/ __/ / __ \/ __ \'
|
|
$InvokeObfuscationAscii += $Spacing + '/ /_/ / /_/ / __/ /_/ (__ ) /__/ /_/ / /_/ / /_/ / / / /'
|
|
$InvokeObfuscationAscii += $Spacing + '\____/_.___/_/ \__,_/____/\___/\__,_/\__/_/\____/_/ /_/ '
|
|
|
|
# Ascii art to run only during script startup.
|
|
If(!$PSBoundParameters['Random'])
|
|
{
|
|
$ArrowAscii = @()
|
|
$ArrowAscii += ' | '
|
|
$ArrowAscii += ' | '
|
|
$ArrowAscii += ' \ / '
|
|
$ArrowAscii += ' V '
|
|
|
|
# Show actual obfuscation example (generated with this tool) in reverse.
|
|
Write-Host "`nIEX( ( '36{78Q55@32t61_91{99@104X97{114Q91-32t93}32t93}32t34@110m111@105}115X115-101m114_112@120@69-45{101@107X111m118m110-73Q124Q32X41Q57@51-93Q114_97_104t67t91{44V39Q112_81t109@39}101{99@97}108{112}101}82_45m32_32X52{51Q93m114@97-104{67t91t44t39V98t103V48t39-101}99}97V108}112t101_82_45{32@41X39{41_112t81_109_39m43{39-110t101@112{81t39X43@39t109_43t112_81Q109t101X39Q43m39}114Q71_112{81m109m39@43X39V32Q40}32m39_43_39{114-111m108t111t67{100m110{117Q39_43m39-111-114Q103_101t114@39m43-39{111t70-45}32m41}98{103V48V110Q98t103{48@39{43{39-43{32t98m103_48{111@105t98@103V48-39@43{39_32-32V43V32}32t98t103@48X116m97V99t98X103t48_39V43m39@43-39X43Q39_98@103@48}115V117V102Q98V79m45@98m39Q43{39X103_39X43Q39V48}43-39}43t39}98-103{48V101_107Q39t43X39_111X118X110V39X43}39t98_103{48@43}32_98{103}48{73{98-39@43t39m103_39}43{39{48Q32t39X43X39-32{40V32t41{39Q43V39m98X103{39_43V39{48-116{115Q79{39_43_39}98}103m48{39Q43t39X32X43{32_98@103-39@43m39X48_72-39_43t39V45m39t43Q39_101Q98}103_48-32_39Q43V39V32t39V43}39m43Q32V98X39Q43_39@103_48V39@43Q39@116X73t82V119m98-39{43_39}103Q48X40_46_32m39}40_40{34t59m91@65V114V114@97_121}93Q58Q58V82Q101Q118Q101{114}115_101m40_36_78m55@32t41t32-59{32}73{69V88m32{40t36V78t55}45Q74m111@105-110m32X39V39-32}41'.SpLiT( '{_Q-@t}mXV' ) |ForEach-Object { ([Int]`$_ -AS [Char]) } ) -Join'' )" -ForegroundColor Cyan
|
|
Start-Sleep -Milliseconds 650
|
|
ForEach($Line in $ArrowAscii) {Write-Host $Line -NoNewline; Write-Host $Line -NoNewline; Write-Host $Line -NoNewline; Write-Host $Line}
|
|
Start-Sleep -Milliseconds 100
|
|
|
|
Write-Host "`$N7 =[char[ ] ] `"noisserpxE-ekovnI| )93]rahC[,'pQm'ecalpeR- 43]rahC[,'bg0'ecalpeR- )')pQm'+'nepQ'+'m+pQme'+'rGpQm'+' ( '+'roloCdnu'+'orger'+'oF- )bg0nbg0'+'+ bg0oibg0'+' + bg0tacbg0'+'+'+'bg0sufbO-b'+'g'+'0+'+'bg0ek'+'ovn'+'bg0+ bg0Ib'+'g'+'0 '+' ( )'+'bg'+'0tsO'+'bg0'+' + bg'+'0H'+'-'+'ebg0 '+' '+'+ b'+'g0'+'tIRwb'+'g0(. '((`";[Array]::Reverse(`$N7 ) ; IEX (`$N7-Join '' )" -ForegroundColor Magenta
|
|
Start-Sleep -Milliseconds 650
|
|
ForEach($Line in $ArrowAscii) {Write-Host $Line -NoNewline; Write-Host $Line -NoNewline; Write-Host $Line}
|
|
Start-Sleep -Milliseconds 100
|
|
|
|
Write-Host ".(`"wRIt`" + `"e-H`" + `"Ost`") ( `"I`" +`"nvoke`"+`"-Obfus`"+`"cat`" + `"io`" +`"n`") -ForegroundColor ( 'Gre'+'en')" -ForegroundColor Yellow
|
|
Start-Sleep -Milliseconds 650
|
|
ForEach($Line in $ArrowAscii) {Write-Host $Line -NoNewline; Write-Host $Line}
|
|
Start-Sleep -Milliseconds 100
|
|
|
|
Write-Host "Write-Host `"Invoke-Obfuscation`" -ForegroundColor Green" -ForegroundColor White
|
|
Start-Sleep -Milliseconds 650
|
|
ForEach($Line in $ArrowAscii) {Write-Host $Line}
|
|
Start-Sleep -Milliseconds 100
|
|
|
|
# Write out below string in interactive format.
|
|
Start-Sleep -Milliseconds 100
|
|
ForEach($Char in [Char[]]'Invoke-Obfuscation')
|
|
{
|
|
Start-Sleep -Milliseconds (Get-Random -Input @(25..200))
|
|
Write-Host $Char -NoNewline -ForegroundColor Green
|
|
}
|
|
|
|
Start-Sleep -Milliseconds 900
|
|
Write-Host ""
|
|
Start-Sleep -Milliseconds 300
|
|
Write-Host
|
|
|
|
# Display primary ASCII art title banner.
|
|
$RandomColor = (Get-Random -Input @('Green','Cyan','Yellow'))
|
|
ForEach($Line in $InvokeObfuscationAscii)
|
|
{
|
|
Write-Host $Line -ForegroundColor $RandomColor
|
|
}
|
|
}
|
|
Else
|
|
{
|
|
# ASCII option in Invoke-Obfuscation interactive console.
|
|
|
|
}
|
|
|
|
# Output tool banner after all ASCII art.
|
|
Write-Host ""
|
|
Write-Host "`tTool :: Invoke-Obfuscation" -ForegroundColor Magenta
|
|
Write-Host "`tAuthor :: Daniel Bohannon (DBO)" -ForegroundColor Magenta
|
|
Write-Host "`tTwitter :: @danielhbohannon" -ForegroundColor Magenta
|
|
Write-Host "`tBlog :: http://danielbohannon.com" -ForegroundColor Magenta
|
|
Write-Host "`tGithub :: https://github.com/danielbohannon/Invoke-Obfuscation" -ForegroundColor Magenta
|
|
Write-Host "`tVersion :: 1.8" -ForegroundColor Magenta
|
|
Write-Host "`tLicense :: Apache License, Version 2.0" -ForegroundColor Magenta
|
|
Write-Host "`tNotes :: If(!`$Caffeinated) {Exit}" -ForegroundColor Magenta
|
|
}
|