UglyEXe — bypass some AVs

Mark Mo
7 min readFeb 28, 2020

--

This is for educational purposes only.

Before I begin, a lot of the credit goes to the authors in these links. I’ve made adaptions to these, created a basic program and added some tests to automate the creating of a new ugly executable that may bypass some AV’s.

https://codereview.stackexchange.com/questions/3226/replace-sequence-of-strings-in-binary-file

https://everydaywithlinux.blogspot.com/2012/11/patch-strings-in-binary-files-with-sed.html?m=1

My inspiration came from pyfuscation (https://github.com/CBHue/PyFuscation). I thought, hey, let me try that with a binary file without the source code!

Here is what I did with mimikatz. On the left, normal mimikatz. On the right, my string replaced version. All I did for this is ensured I could run privilege::debug and sekurlsa::logonpasswords. Nothing else works but the credential dumping functionality still works. I’ve highlighted my NTLM Hash on both screens so you can still see it property dumps an NTLM hash. I could have made more functionality work but I would need to add a lot more automated testing for functionality.

And here is the result from avcheck.net (7 out of 26 detected it). Not amazing but not shabby for just replacing some strings in an executable. I ran a less obfuscated version against virus total and I got 28 out of 72. I haven’t checked this version of the file on VT yet. I’ll probably just keep this version in my pocket. 😊

This is more of a method than a tool. This requires quite a bit of manual processing and known good states to create a functional executable.

In a nutshell this program does the following:

· Performs a SysInternals strings call to extract Unicode and ASCII strings and deduplicate them from a target executable.

· Converts the target exe into a hex representation of the executable.

· Searches for the hex representation of each string in the hex version of the executable.

· If it finds it, it replaces it with a random string of the same size.

· It converts the hex back into a test executable and tries to run it and makes sure it doesn’t crash.

· It is looking for a specific condition to make sure the executable still functions ok.

· For NC.exe I’m just testing if I can run NC -e C:\windows\system32\cmd.exe -nlvp 50000

· To test for success, I’m looking to see if the output contains “listening”

· EVERY EXECUTABLE WILL NEED ITS OWN PASS/FAIL TESTS!!!!

· If the test passes, it records the strings and moves on to the next string but now the exe is modified with the good string. If it fails it notes the string failed and moves onto the next string

· Each successful string replacement is passed on to the next string to check. This builds up a functional executable with as many strings replaced as possible.

This program has a dependency on SysInternals strings64.exe. Strings64.exe needs to be in the same folder as the executable I am targeting. For example, if I put nc.exe in c:\temp I need to put strings64.exe there as well. I have a lot of other things I want to work on so I hard coded a lot of things.

PLEASE NOTE: There will be errors that pop up, I’m ignoring them because I haven’t figured out a way to suppress them programmatically. However, the process still works fine. When the program finishes, I just hold down the escape key for a minute to clear all the error messages. I’ve read the errors can be disabled but by setting a registry values, but I haven’t had time to chase it down. If you know how to fix this, please message me on twitter.

Here is my program running string replacements on nc.exe

And a little later it is still chugging a long

Here is a look at a part of the string dump of nc.exe before and after a string replacement

And here is a snippet of some of the strings that got replaced and their corresponding value

And here it is working just fine.

And here is my shell. Please note from my attacker box, I used a real NC.exe because I don’t have to worry about AV there.

PLEASE NOTE: I’m ONLY REPLACING THE ASCII STRING STRINGS IN NC.EXE IN THE ABOVE EXAMPLE. I ran into some issues with Unicode and I would need to write a more complicated test set to replace the Unicode strings. I just don’t have the free time to do that now.

At this point I usually run some string analysis to see what other strings are remaining. I wrote a quick powershell script to look at the words that remain. It is called WordAnalysisAsciiAndUnicode.ps1. I got some of the code from someone else I don’t remember where I found it.

I look at remining strings that couldn’t get replaced by my program and try to determine if they are likely to trigger an AV alert. For example, after I ran my string replace on mimikatz, I found several strings that didn’t get replaced with my C# program. If you know what I’m doing wrong, please message me on twitter. I’d love to know.

Here is my work around. At this point I copy the exe over to Linux. This step could break things, so I make a copy of the binary and test only a handful of strings at a time. I got help with this script from my friend Anthony (linkedin.com/in/anthonyp7) who is much better at bash then I am. We adapted the script from what I originally found here:

https://everydaywithlinux.blogspot.com/2012/11/patch-strings-in-binary-files-with-sed.html?m=1

Here is the modified script

Here is a handful of strings I replaced when I was working on mimikatz.

Here is a quick walk through of my code. First, I give the path to the executable I’m working with and convert it hex. This is also where I copy strings64.exe.

Next I pull out the ASCII and Unicode string using SysInternals strings64 (https://docs.microsoft.com/en-us/sysinternals/). I’m only looking for strings that are 5 characters or longer.

Next, I loop through the ASCII strings and replace one string at a time and perform a crash test.

I also have a section for Unicode but for my NC test I didn’t have time to write a better test to handle the issues that occurred with the Unicode replacements. It is currently commented out.

Next I’m testing for a crash. In this case I’m launching a modified version of nc.exe (test.exe) and checking to see if I still see a string containing “listening” in the output when I try to start a listener.

I have methods to handle errors and data received. SOMETIMES, the output shows up in the error (not usually). This part is the biggest pain to troubleshoot. Each executable is has a unique test I have to come up with.

I also kill the process after 3 seconds because all NC really does is start a listener for my test. If it hasn’t crashed in 3 seconds and the output contains “listening” then I’m assuming it is functioning correctly and has not crashed.

I left a few hard-coded strings hanging around the program from previous testing with Mimikatz. I wish I had more free time, but I don’t. Well, unless someone wants to pay me to research whatever I want 😊.

Obviously if I have the source to a program changing strings can be done that way too. However, I thought this was interesting. One final note, the bigger the exe, the more strings it contains. It will take a lot longer to run. For example, running the full strings replacement on Mimikatz took 4+ hours. Running the string replacement on nc.exe took about 20 minutes.

Here is the code

https://github.com/fashionproof/UglyEXe

Hopefully you learned something useful here. Feel free to follow me on twitter.

https://twitter.com/_markmo_

--

--

Mark Mo

@fashionproof.bsky.social on bluesky @_markmo_ on twitter