Home Grown Red Team: Let’s Make Some Malware In C: Part 2

assume-breach
10 min readDec 16, 2022

--

As promised during part 1 of this series, we have reached part 2! If you haven’t read my first post, you can find it here. In the first part of this series, we wrote some malware, encrypted our payload with AES and XOR encrypted some WinAPI functions to bypass Windows Defender and some other AVs.

That was a fun project, but let’s take it a step further and create a script that will replicate the process and obfuscate the functions within our malware template so we get a new, unsignatured EXE every time.

Sounds cool right? Let’s get started.

Creating The Script File

If you followed along with the first post, you should have a directory with all of the relevant files. If not, you can git clone it from here.

https://github.com/assume-breach/Malware_Project.git

Let’s create a bash script file.

And we can add some ASCII art to make it look pretty.

https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=Red%20Phoenix&text=Your%20text%20here%20

We’ll create a banner in our malware generator.

And now we need some prompts so the script can find what we need to input and output. These include our shellcode location and what we want our malware to be named.

At this point, the script will read these two variables.

Before we move on, let’s copy our shellcode.c file and make it malware.c. This way if we need to revert something, we have our shellcode.c file as reference and a backup.

cp shellcode.c malware.c

Encryption Templates

Next, we need to prep templates for our encryption scripts. We should have AES.py and XOR.py in our github repo. Since AES.py already creates a random key, we only need to worry about XOR.py.

Let’s open the script up and replace the current key with a new key variable: XORKEY.

That should take care of our encryption templates. The workflow for this is to create a randomized XOR key every time so our bash script will replace XORKEY with a random value. Let’s create a new folder to house the replaced variable XOR.py script.

mkdir Resources

We also need to make some changes to our AES.py script so that it takes our shellcode file location as an argument.

We’ll change the payload variable to accept the location as an argument. We will also remove the “char” from the printed text in main.

Now we can move our AES script into the Resources directory.

mv AES.py Resources/

Now, let’s go back to our malware_creator script. We’ll add a new line to copy our xor.py script into the Resources directory.

And since we’re going to be working out of the Resources directory to replace values, we need to add a line to copy our malware.c file.

So now, we can run our script and input dummy values.

When we go to the Resources directory, we should see a copy of xor.py and malware.c and our AES.py script.

Perfect!

Now we can add commands to encrypt our payload and insert it into the copy of our malware.c file. Let’s add some printed text to show that we are starting our encryption process. This will be helpful for debugging.

Now we need to copy 2 variables. The first is going to be our encrypted payload. We can copy this into a TXT file.

This line reads our shellcode file based on our prompt in the beginning and then places the AES key and the AES encrypted payload into a TXT file.

As a test, let’s create some real shellcode to run the script against.

And now our shell.txt file is created. Let’s open it to make sure our key and payload are inside.

Looks good!

Let’s go back to our malware_creator script and add some printed text to show that our encryption has completed.

Cool, now we need to get the “key” string and the “payload” string from shell.txt into our malware.c file. So how do we do that?

We can use the cut command. Since we need our key and our payload variables, we can copy our shell.txt file and cut away the unneeded text in each file.

Now we need to choose variables in our malware.c file to stand in for the AES key and the AES payload. Let’s open our malware.c file and look at the AES key and the AES payload fields.

In the main function, I have left these values blank with “Fill In Yourself”. Let’s remove that and add AESKEY and AESPAYLOAD in their place.

We can save this and go back to our malware_creator.sh script. With some basic bash voodoo we can extract the AES key and enter it into our malware.c file to replace the “AESKEY” text.

We declare aeskey as the text inside shell2.txt then cut everything after and including the “P” in Payload. We then declare aeskeys as the text inside our newly created shell3.txt file (this is just the AES key). We then declare aeskeysnow as the text and cut out the AESKEY= text to leave us with our key.

After running the script, we see that the AESKEY text in our malware.c file has been replaced with our encrypted key.

Pretty cool! Now we can just replicate these commands for the payload.

Going through this, I discovered that sed wouldn’t work because the payload string is too long. So we have the same basic command structure, but we use a perl command to replace the values.

Let’s run our script and see if it replaces the AESPAYLOAD value in malware.c.

And it looks like it worked! So now our malware.c file has the aes key and payload automatically copied into it.

Obfuscated Function Names

Let’s open our malware.c template file in the malware_project directory. Looking through here I see the function names that we changed in our first post. DecryptionIsFun, AnotherEncryption, cexe, vr, ect.

Let’s randomize these names. You can use an onboard bash command to get randomized values.

cat /dev/urandom | tr -dc ‘[:alpha:]’ | fold -w ${1:-8} | head -n 1

If you run this command you will get a random 8 character string.

If we pipe this into a txt file we can then use it to replace defined text in our malware.c template file.

Now let’s set a function to “Random1” in our malware.c file. Let’s replace every instance of “DecryptionIsFun” in our template file.

So this,

becomes this.

And if we go through the rest of the file we need to replace the other instance of DecryptionIsFun.

And if we rerun our script, we see that the Random1 has been replaced by a random 8 character string.

Let’s do the same thing for “AnotherEncryption”.

And we can do this for our WinAPI pointers, the XOR’d strings and the other constants in the malware.c file.

So we’ll replace pVirtualAlloc, pCreateThread, pWaitForSingleObject, VirtAlloc, CreatThr, WaitMe, cexe, vr, another_encry, saekey, and loadme.

After replacing these functions and strings, we get to Random9.

At this point, we need to change our scheme to RandomA. If we use Random10, it will get replaced with “Random1” in the beginning of the script.

After all of these entries, we can rerun our script and we should get randomized values in Resource/malware.c.

And it looks like it worked!

Replacing The XOR Key And The XOR Encrypted Strings

Now we need to add a line for replacing our XOR key. Up until this point, our key has been “HarrietIsAGoodDog”. But we want to replace this with a randomized value and then use that to encrypt our functions.

Let’s replace this with XORKEY.

Now in our malware_creator.sh script, we need to add an entry for our malware.c file and our XOR script.

Now in our malware.c file, we can replace the XOR’d strings with their actual variable names. These will be replaced with the newly encrypted strings. Notice that we must include the curly brackets and the semi-colon to the end of each string because these will be deleted when we get rid of the last byte except for WaitForSingleObject.

And we add some bash scripting to replace “VirtualAlloc” in Resources/malware.c with our encrypted string. Remember from the first post, the XOR script adds 1 byte to the end of our string, so we need to remove it. However, WaitForSingleObject does not need this in it’s script.

And we do the same thing for CreateThread and WaitForSingleObject.

Now we can rerun our script.

And in our Resources/malware.c file we see that that encrypted strings are present.

Compiling Our Implant

With all the hard work done, all we need to do is compile. Let’s add some printed text for debugging in the future and then add the compilation commands. We’ll also add a command to delete the shell files.

Let’s run it and see if we get an implant!

And it looks like it worked. Let’s transfer it to a Windows box and see if it works.

All right! It worked. Let’s scan it against AntiScan.me and see what kind of detections we have.

2/26 isn’t too bad! So as you can see, we can script out our malware pretty easily to give us a fresh implant whenever we want it. Remember, this is a calc payload so other payloads will probably go further.

As an exercise, you can go out and find a shellcode runner and see if you can script out an obfuscator like we did here. ired.team has some good ones!

You can find the completed scripts for this project here:

https://github.com/assume-breach/Malware_Project

If you liked this or have any questions, give me a follow on here or on Twitter @assume_breach

--

--

assume-breach

Security enthusiast that loves a good CTF! OSCP, CRTO, RHCSA, MCSA.