Get the latest security news in your inbox.

During a penetration testing engagement, it’s quite common to have antivirus software applications installed in a client’s computer. This makes it quite challenging for the penetration tester to run common tools while giving the clients a perception that their systems are safe, but that’s not always the case. Antivirus software applications do help in protecting systems but there are still cases where these defenses can be bypassed.

Antivirus evasion is a broad topic and this article only presents very basic methods to bypass detection when the program is resting as a file in a non-volatile storage. Evasion techniques for a run-time state are quite different and challenging because of behavior monitoring done by antivirus programs.

In this article, I will be discussing a few techniques that can be used to bypass antivirus software applications like string manipulation and code substitution. Before anything else however, an understanding of programming is required because I’ll assume that the detected software application has its source code available for modification. I’ll probably work out another separate article for evasion of programs that don’t have their source code available.

There will be two basic steps to do. First will be finding the cause of the detection while the next step goes into how the detection can be bypassed. This is because we won’t be able to fix something if we don’t know what the problem is.

Looking for the Origin of the Detection

For the demonstration, I will be using an object-oriented language, specifically C#, with the help of Visual Studio 2012. I grabbed a snippet from here specifically the functions “startup” and “USBSpread” while creating a new project to put both of these. This is what it looks like after creating a console project in C#:

Please note that I have minimized the region of the code in the screenshot above to make it short. I’ll leave the credits where it is due for both those functions. After compiling the project and scanning it in VirusTotal, the result shows two antiviruses detecting it namely ESET and Sophos.

Please forgive me. If any of you are not familiar, VirusTotal actually distributes copies of a scanned file, especially if a few antiviruses detect it. Chances are that if you are reading this right now, the scan results might have changed already when you visit the link. This endangers your tool to become detected very fast and should not be used for scanning when you are developing a penetration testing tool to be used for legal assessments.

Now here comes the fun part. How can we find out what’s causing the detection? Since we have a copy of the source code, what we can do is remove parts of the code line by line and rescan it. To start off, I have commented out the whole “USBSpread” function as seen below:

As you may have guessed, the detection found by ESET now disappeared and Sophos has reappeared. From what we did, we can conclude that having the “startup” function actually triggers detection from ESET while having the “USBSpread” function actually triggers detection from Sophos. Sounds easy to identify the detection right?

Bypassing the Detection

After being able to identify where the detection came from, we can now try to work out how it can be bypassed. Note that the identification process shown above is in general terms. To successfully bypass the antivirus detecting it, we need to continuously do the previous step while working on a fix line by line. There are a few methods like string manipulation and code substitution that usually work but sometimes also trigger more detection so these methods are quite “experimental”.

String Manipulation

This method simply points to how a normal string can be converted into another form while being evaluated with the same meaning. To understand this better, suppose we have a registry path:

Code:

SOFTWARE\Microsoft\Windows\CurrentVersion\Run

In C#, if we declare this, it should look something like:

There are numerous ways on how we can change the form of that string while maintaining the original meaning when the code executes. Here are some very basic ways to do it:

Base64

Using an encoder tool, enter the string “SOFTWARE\Microsoft\Windows\CurrentVersion\Run” and click “encode”. You should get something like this as a result:

Now we copy that string back to the source code with the following evaluator and notice that when the program runs, the string still gets evaluated to the original form:

ASCII Representation

This is a pretty simple solution and it actually works sometimes too! Converting the string to its numeric ASCII form looks like this:

In the image above, I have converted the “\” character into its numeric ASCII form. If we check out the ASCII table, the character “\” is equivalent to 92 in decimal. Doing some other simple calculations basically differentiate the original code from the current one.

Encryption can also take part in this like having your string encrypted and written down to a binary file. The program can then load it by browsing and decrypting the contents during execution or so. There are lots of possible methods for string manipulation and this is basically where your creativity comes into play.

Code Substitution

This method requires more in-depth knowledge of programming because it requires understanding of what a specific line of code or what a specific function does. For example, suppose we have a code that downloads the contents of a web page:

With code substitution, an understanding of what the code does is essential because we will need to find a replacement of the code by commands while achieving the same logic and goal at the end. In this case, the goal of the code above tries to get the client IP address in the network where the program is running. This can also be achieved with the use of this code:

Notice that the output is the same, which means the code logic does the same functionality and goal but the way it is done is different. If ever the first code is detected by a few antiviruses, it can be substituted with the next one or vice-versa. There are other more ways to grab the IP address but I’ll leave that part as a research for the readers.

Going back to the example program, let’s start with Sophos. At this point, the function “startup” is commented out to stop ESET from detecting it while we fix the first one. This antivirus was previously detecting the method “USBSpread” and after some trial and error, the detection was still popping up even after commenting out the whole function contents:

Sophos in this case was basically finding that function name and flagged it as malicious. To proceed, we now do the same steps for the “startup” function and the specific line that started the detection by ESET was:

Since there are parameters in the line and one of the parameters is a string, we will need to separate it to another line so we can confirm what is being detected by ESET. A variable “temp” was assigned to hold the string representation of the registry path for this:

At this point, ESET was still detecting the program even if the registry path doesn’t really make sense, so this might not be the “real” thing being flagged by ESET or there is another line of code in which if combined with the current string, gets detected. Once this happens, we need to carefully go back each step and see what could probably be the issue. While leaving the code uncommented:

Now, there should be a lot of test cases here but to cut the testing short, since some basic string and variable manipulation don’t work, we can try to do some code substitution. Most programmers can understand what the “startup” function does. It simply adds the program to the Windows start up so it can execute once Windows boots. There are numerous ways to add a program in the Windows start up. This could be through copying the executable in “C:\Users\<USER>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup” or maybe by using a scheduled task.

The “startup” function in this case was replaced by this simple code:

This basically does a similar job by logic but different in terms of instructions. The final program looks similar to this:

Once compiled and scanned in VirusTotal, the result gives us a rate of 0/65.

While being able to achieve a fully undetected program which helps in penetration testing engagements, it is essential to understand that running this program will probably catch the attention of antiviruses that monitor its actions during run time. This is why antivirus evasion is challenging to do with automated tools because the scope is very wide.

P.S. The code presented above might have different scan results as time goes on because as mentioned, VirusTotal distributes copies of applications being scanned and other antiviruses might decide to put a flag on them.

About the Author:Nathu NandwaniNathu Nandwani is a Computer Engineer from the Philippines holding various industry certifications like MCP, MCTS, OSCP, and CCNA CyberOps. He is currently part of the red team of Cyber Security Philippines CERT.Blog: nandtech.co
Twitter: @nandwaninathuRead more posts from Nathu Nandwani ›