Skip to content

Instantly share code, notes, and snippets.

@mmacfadden
Last active October 1, 2022 19:20
Show Gist options
  • Save mmacfadden/6fb33daee4556f6b992f6c94d37c1d75 to your computer and use it in GitHub Desktop.
Save mmacfadden/6fb33daee4556f6b992f6c94d37c1d75 to your computer and use it in GitHub Desktop.
##############################################################################
## CSC-846 Lab-05
## Michael MacFadden
##
## This is a helper utility I worked up to help manually obfuscate string
## content for powershell.
##############################################################################
##############################################################################
## Encoding Methods
##############################################################################
function simple_encode([string] $value) {
$arr = $value.ToCharArray()
$arr = $arr | ForEach-Object { [char]([int]$_ - 2) }
[array]::Reverse($arr)
return -join($arr)
}
#
# This method encodes a string and generates a unique six character encryption
# key that is needed to decode it.
#
function encode($strings_to_encode) {
# Get the bytes of the ASCII string.
$source_bytes = [System.Text.Encoding]::ASCII.GetBytes($strings_to_encode)
# Reverse the array.
[array]::Reverse($source_bytes)
# Create an array that is twice as long as the string
# we are going to encode. This will allow us to populate
# the string with partial junk data.
$encoded_bytes = [byte[]]::new($source_bytes.Length * 2)
# Create a unique encryption key for this particular string
$random_key = [int[]]::new(6)
foreach($i in (0..($random_key.Length - 1))) {
$random_key[$i] = Get-Random (97..122)
}
# Now we loop over the reverse string bytes.
for($i = 0; $i -lt $source_bytes.Length; $i++) {
$char_byte_val = $source_bytes[$i]
# We get the round robin character
$rnd = $random_key[$i % $random_key.Length]
# calculate the index of where the data will go.
# we multiply by two since we are putting in
# two characters for each original character.
$idx = ($i) * 2
# We actually just put a random character in every other
# slot of the array. This goes in the first slot.
$encoded_bytes[$idx] = Get-Random (33..126)
# Now we put the original charachter in, but we increment
# it by the value of the random key (-97 so that we don't
# go to far out of the printable ASCII range.)
$encoded_bytes[$idx + 1] = $char_byte_val + $rnd - 97
}
# Now encode the bytes as a base 64 string.
$base64 = [Convert]::ToBase64String($encoded_bytes)
# Now we chunk the base64 into 4 character sub strings
# reverse each of those chunks and then join it back
# together. This makes is so you can't even just base
# 64 decode the string.
$split = $base64 -split '(.{4})' | ?{$_}
$reversed_split = $split | ForEach-Object { $a = $_.ToCharArray(); [array]::Reverse($a); return -join $a}
$joined = $reversed_split -join ""
# Convert the ints to chars and join them to make the
# encryption key.
$random_key_str = [char[]]$random_key
$key = $random_key_str -join ""
# return both the encoded string and the encyprtion key.
return @($joined, $key)
}
##############################################################################
## Decoding Methods
##
## All of the decoding code must be copied into the obfuscated script.
##############################################################################
$xyE7rqw = [System.Text.Encoding]::ASCII
$au8Emdr = [Convert]
$lkjsafsdf = 2
# Performs a very simple decoding of a string by reversing it
# and adding a small offset. This is used in the decoding
# method to hide calls to "GetBytes" and "FromBase64String"
# to make it less obvious what is going on.
function uywerwerm($yiuewrh) {
$kjhdsf = $yiuewrh.ToCharArray()
[array]::Reverse($kjhdsf)
# Note the offset was move outside of the method and
# turned into a variable so it was less obvious what
# was going on.
return -join($kjhdsf | ForEach-Object { [char]([int]$_ + $lkjsafsdf) })
}
# this function simply divides the input by 2.
# mad all the variables very simliar and hard to read.
# # then added some junk code.
function djjsfu($1ll1lIlIl11l) {
# This branch will never get taken so this is a bogus
# control flow example.
if ($1ll1lIlIl11l -lt 0) {
$1ll1lIlIl11l = $1ll1lIlIl11l * 2
$1ll1lIlIll1l = $1ll1lIlIl11l + 13
$1ll1lIlIll1l = $1ll1lIlIl11l / 8
$1ll1lIlIll1l = $1ll1lIlIl11l + 12
return $1ll1lIlIl11l / 6
} else {
$1ll1lIlIl11l = $1ll1lIlIl11l * 4
$1ll1lIlIll1l = $1ll1lIlIl11l + 17
$1ll1lIlIll1l = $1ll1lIlIl11l * 4
$1ll1lIlIll1l = $1ll1lIlIl11l / 12
return $1ll1lIlIl11l / 8
}
}
# This number is used in the method below. Just
# moved it out to make it harder to read below.
$ksjdhff = 56
# This number is used when decrypting the strings, but
# was outlined.
$skdjfhskf = 372
# This method decodes strings in the actual code.
# It uses some base64 encoding and getting of ASCII codes
# calls to those methods we obfuscated by hiding their names
# and using reflection, with also slighly obfuscated strings.
function xhhdfuy($ll11ll1l) {
$1ll1ll1ll1 = $ll11ll1l[0]
$1ll1l11l1l = $ll11ll1l[1]
$hsjkdfh = 4
# A lot of in-line-ing here to make this hard to undrstand
# It is basically splitting the input string into 4 character
# chunks. Reverseing each one of those chunks, then re-joining
# those chunks together to get a valid base 64 encoded string.
$ll1lll1l1l = ($1ll1ll1ll1 -split '(.{4})' | ?{$_} | ForEach-Object {$a = $_.ToCharArray(); [array]::Reverse($a); return -join $a}) -join ""
# A obfuscated call to [Convert]::FromBase64String
$jjeirnn = $au8Emdr.GetMethod((uywerwerm("elgprQ24cq_@kmpD")), [type[]]@([string]))
$jjiernr = $jjeirnn.Invoke($null, @(,$ll1lll1l1l))
$iksdfjl = $jjiernr.Length - 1
# Creates a array half the size of our data, using our
# overly complex divide by two method.
$q8ern3 = [byte[]]::new((djjsfu($jjiernr.Length)))
for($hjueh = 0; $hjueh -lt $iksdfjl; $hjueh = $hjueh + 2) {
$ll1ll1l1l = $1ll1l11l1l[(djjsfu($hjueh)) % $1ll1l11l1l.Length]
# Obfuscated method that just divides by 2
$jjienrn = djjsfu($hjueh)
# This is the obfuscated character.
$jskjh8hsd = $jjiernr[$hjueh + 1]
# here we are just subtracting 97 from the decoding character
# but doing it in a really obtuse way.
$hhhisdfkl = $jskjh8hsd - ($ll1ll1l1l - 45 - $ksjdhff + $hsjkdfh)
# putting the decoded character in the result array.
$q8ern3[$jjienrn] = $hhhisdfkl
}
[array]::Reverse($q8ern3)
# An obfuscated call to ASCII.GetString, reusing some of the
# variable names to make it harder to read.
$jjeirnn = $xyE7rqw.getType().GetMethod((uywerwerm("elgprQrcE")), [type[]]@([byte[]]))
$jjeirnn = $jjeirnn.Invoke($xyE7rqw, @(,$q8ern3))
return $jjeirnn
}
##
## This is the actual decode method
##
function hhkjysdf($ll11ll1l) {
$l1ll1ll11ll1 = $ll11ll1l[0]
$l1ll1l111ll1 = $ll11ll1l[1]
$lll11ll1lll1 = 10
$11lll11ll1ll = Get-Location
# Note that on the first iteration of the loop, the counter
# variable is set to 10, and then there is a divide by 0 that is
# tirggered. The actual code we execute is in the catch block.
# so this is an example of using exceptions for control flow
# obfuscation.
try {
for($11ll1lll1ll1 = $lll11ll1lll1; $11ll1lll1ll1 -gt 0; $11ll1lll1ll1--) {
if ($11ll1lll1ll1 -eq 10) {
$11lll11ll1ll = $l1ll1ll11ll1
} else {
$11lll11ll1ll = $l1ll1ll11ll1[1..4]
}
# This is where the divide by zero happens. Can you spot it?
$l1l1l1ll1ll1 = (12 / ($11lll11ll1ll - $lll11ll1lll1)) + $11lll11ll1ll
}
return xhhdfuy($baz, $l1ll1l111ll1)
}
catch {
$l1ll1ll1lll1 = Get-Location
$11ll11l1ll1l = $l1ll1ll11ll1 + $l1ll1ll1lll1.ToString()
$l1l1l1ll1ll1 = $11ll11l1ll1l.substring(0, $l1ll1ll11ll1.Length)
xhhdfuy($l1l1l1ll1ll1, $l1ll1l111ll1)
}
}
function kjhsdff($lkjsdfsdf) {
# This is a decoy URL which is junk code, but certainly will
# grab some one's attention. All the text encoding stuff
# here is also not used at all. Just junk code.
$kjsfsdfsdf = "http://www.sdhfskdjfds.cz/arc/dl.t.gz"
$kjhsdfkjfs = $lkjsdfsdf[0] - $skdjfhskf
$dsfskjh = [System.Text.Encoding]::ASCII.GetBytes($kjsfsdfsdf)
$dsfskjh = $dsfskjh + [byte[]]@(102, 92, 119, 89)
$ksdjhfkjshdf = $uhwekjrb[$kjhsdfkjfs]
$lkisdfsdf = [System.Text.Encoding]::ASCII.GetString($dsfskjh)
$hksjdfhksdf = $lkjsdfsdf[1]
return hhkjysdf($ksdjhfkjshdf, $hksjdfhksdf)
}
##############################################################################
## Data Generation
##
## This code was used to actually generate the strings that were used in
## the obfuscated code.
##############################################################################
##
## Simple Strings to Encode
##
$strings_to_simple_encode = @("GetString", "FromBase64String")
Write-Output "`nSimple Encoded Strings`n"
Write-Output "-----------------------------------------`n"
foreach ($str in $strings_to_simple_encode) {
$encoded_str = simple_encode($str)
Write-Output "$str => `t$encoded_str"
}
Write-Output ""
# I added a bunch of bogus strings in here as well.
$strings_to_encode = @(
"Sed ut perspiciatis unde omnis iste natus error"
"Want a baloons notification?",
"Lorem ipsum dolor sit amet, consectetur adipiscing"
"CSC846 - sample01",
"YesNo",
"Want more baloons?",
"ullamco laboris nisi ut aliquip ex ea commodo c"
"Yes",
"Fine.",
"illum qui dolorem eum fugiat quo voluptas nulla"
"Show",
"LoadWithPartialName",
'System.Windows.Forms',
'System.Drawing',
"on numquam eius modi tempora incidunt"
)
# This variable name is a bit clunky since it is needed to
# be obfuscated in the actual script.
$uhwekjrb = [string[]]::new($strings_to_encode.Length)
$keys = [string[]]::new($strings_to_encode.Length)
for($i = 0; $i -lt $strings_to_encode.Length; $i++) {
$str = $strings_to_encode[$i]
$result = encode($str)
$uhwekjrb[$i] = $result[0]
$keys[$i] = $result[1]
}
Write-Output "`nData Array for Obfuscated Code`n"
Write-Output "-----------------------------------------`n"
Write-Output "`n`$uhwekjrb = @("
$string_constants = ($uhwekjrb | ForEach-Object {"`"$_`""})
Write-Output (" " + ($string_constants -join ",`n "))
Write-Output ");`n"
Write-Output "`nDecoder Mapping for Obfuscated Code`n"
Write-Output "-----------------------------------------`n"
for($i = 0; $i -lt $strings_to_encode.Length; $i++) {
$str = $strings_to_encode[$i]
$key = $keys[$i]
$index = $i + 372
$index_hex = ‘0x{0:x}‘ -f $index
Write-Output "`"$str`""
Write-Output " Function Call:`tkjhsdff($index_hex, `"$key`");"
$decoded = kjhsdff([int]$index_hex, $key)
Write-Output " Decoded String:`t$decoded`n"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment