Deobfuscating malicious scripts often involves dealing with numbers to be converted into strings, with or without calculations.
Like this PowerShell script:
This script will convert a list of numbers (100, 105, …) into a list of characters (converting each number into its corresponding ASCII value), join them together into a string and execute the command inside this string.
I have to do this kind of analysis so frequently, that a couple of years ago, I made a simple tool to help me: numbers-to-string.py.
This tool takes a text file as input, extracts numbers per line of text and produces a string for each line with at least 3 numbers. Here this tools deobfuscates the above PowerShell script:
When numbers-to-string is used without argument, it converts each number to its ASCII value (if an error occurs, because a number is too large for example, the line is silently skipped).
Often, scripts with obfuscated commands will be a bit more complex than this simple example. Like the following script, where a mathematical operation is performed on each number, before it is converted:
Converting this with numbers-to-string does not yield the desired result:
This can be fixed by providing numbers-to-string with a mathematical expression as argument to be applied for each number. It's clear that in the script, 3 is added to each number ($_ + 3). By providing expression "n + 3" to numbers-to-string, 3 will be added to each number (n) before it is converted to its ASCII value:
With this expression, the obfuscated command is properly decoded, but notice the unprintable character at the end of the decoded string:
This is because of the conversion of number 3 (from $_ + 3). It's not part of the encoded command, but nevertheless, it has been converted by numbers-to-string. One way to avoid this, is to use option --end to instruct numbers-to-string when it should stop looking for numbers, like this:
With option --end Foreach, numbers-to-string will stop looking for numbers when it encounters the string Foreach.