# dridex/qbot vbs decoder (#constunt) # tested with scripts from: # dridex # https://app.any.run/tasks/c25c082c-7712-4e62-80f1-bdea4d1e6953/ # https://app.any.run/tasks/7d36a639-0b2a-41a2-8053-cfd703f8f115/ # qbot # https://app.any.run/tasks/a7db0dc7-97e3-4dcb-b3f5-1be72c0de814/ # does not decode the EXE, just the other strings in the script # v0.6 added generic identification of function/offset # v0.7 changed decoder function name detection to include qbot, fix extra ) on cint/clng # v0.8 added steps to remove redundant functions/const cls $raw_script = gc 'something_evil.vbs' $entry = "([\w]*)\(array\(" $offset = "function ([\w]*)\(.*\)-([\d]{2})\)" $rx_consts = "const (\w{1,2})=(\d{2,3}):" $pairs = @() # remove null functions $null_func = "iF False ThEn :dim [\w]*:End iF:" ($raw_script | Select-String -Pattern $null_func -AllMatches | % {$_.matches.value} | % {$raw_script = $raw_script -Replace $_, ''}) # get array name and decode offset $arrayname = (($raw_script | Select-String -Pattern $entry | % {$_.matches}).groups[1]).value $offset = [int](($raw_script | Select-String -Pattern $offset | % {$_.matches}).groups[2]).value # extract code table $raw_script | Select-String -Pattern $rx_consts -AllMatches | % {$_.matches} | % {$pairs += ($_.groups[1].value + " " + [char]($_.groups[2].value - $offset))} $pairs = $pairs | sort # remove const $rx_consts2 = "const (\w{1,3})=(\d{2,3}):" ($raw_script | Select-String -Pattern $rx_consts2 -AllMatches | % {$_.matches.value} | % {$raw_script = $raw_script -Replace $_, ''}) # find encoded blocks $arrays = (($raw_script -split "\(array(\([a-z0-9,]*\))\)") -match "^\([a-z][0-9]?(,[a-z][0-9]?)*\)$" ) | sort -Unique -Descending # decode $arrays | % { $to_Replace = $_ $original = $_ $pairs | % { $var1 = ($_[0,1] -replace ' ', '') -join '' $var2 = $_[-1] $to_Replace = $to_Replace -replace "\($var1\)", "($var2)" $to_Replace = $to_Replace -replace ",$var1\)", ",$var2 )" } $pairs | % { $var1 = ($_[0,1] -replace ' ', '') -join '' $var2 = $_[-1] $to_Replace = $to_Replace -replace "\($var1,", "($var2" $to_Replace = $to_Replace -replace "$var1,", "$var2" } $raw_script = $raw_script.Replace($original, $to_Replace) } # tidy up $raw_script = $raw_script -replace "$arrayname\(array\([ ]*([^\)]*) *\)\)", '"$1"' $raw_script = $raw_script -replace 'cint\("([\d)]*)[ ]*"\)', '$1' $raw_script = $raw_script -replace 'clng\("([\d)]*)[ ]*"\)', '$1' # remove more redundant functions $redun_func = 'FuNCtiON [\w]*\(\) : dim [\w]* : [\w]*="[\w]* " : End FuNctiOn :' ($raw_script | Select-String -Pattern $redun_func -AllMatches | % {$_.matches.value} | % {$raw_script = $raw_script.Replace($_, '')}) # split lines (needs work) $raw_script = $raw_script.Replace(':',"`n") $raw_script