Back
EarlyBird Technique: An Advanced Malware Evasion Strategy
Cyber

EarlyBird Technique: An Advanced Malware Evasion Strategy

Liav Mizrahi, Red Team @ KPMG Israel September 2024

Introduction:

As of recent advancements, malware authors are leveraging artificial intelligence (AI) and machine learning (ML) to dynamically alter their evasion techniques. This means that malware can now adapt in real-time to changes in security environments, such as modifications in antivirus software or intrusion detection systems, making traditional static signature-based defences increasingly ineffective. This evolution highlights the growing arms race between cybersecurity defences and malware creators, with each side continuously adapting to outmanoeuvre the other. 

The EarlyBird technique has recently gained prominence in the realm of malware evasion by exploiting advanced methods to circumvent detection systems. This sophisticated strategy builds upon the traditional APC Injection method, creating a child process in a suspended state and injecting shellcode that is later executed via asynchronous procedure calls (APCs). This nuanced approach allows the malware to evade conventional antivirus (AV) and endpoint detection and response (EDR) systems, which are typically tuned to recognize more straightforward shellcode patterns. This article delves into the EarlyBird technique’s mechanisms and its implications for modern cybersecurity defenses.

Overview:

Traditional shellcode loaders typically operate by following a straightforward sequence:

  1. Allocate memory within the target process.
  2. Copy the shellcode to the base address of the allocated memory.
  3. Create a thread to execute the shellcode.

While this approach is effective, it has become heavily signatured, making it easily recognizable to modern antivirus (AV) and endpoint detection and response (EDR) systems.

The EarlyBird technique, however, deviates from this conventional method, enabling it to evade the signatures associated with basic shellcode loaders. By employing a more advanced execution strategy, EarlyBird successfully bypasses many detection mechanisms that would otherwise flag more traditional approaches.

The EarlyBird technique is a “Twist” on the classic APC Injection technique.
Before we dive into EarlyBird, a little background on APC Injection:

What is APC?

Asynchronous Procedure Calls are a Windows operating system mechanism that enables programs to execute tasks asynchronously while continuing to run other tasks. APCs are implemented as kernel-mode routines that are executed in the context of a specific thread. Malware can leverage APCs to queue a payload and then have it execute when scheduled.

Note: Not all threads are able to run APC functions, only threads in alertable state can do so. An alertable state thread is a thread that is in a wait state. When a thread enters an alertable state it is placed in a queue of alertable threads, allowing it to run queued APC functions.

The flow of APC Injection is as follows:

  1. Create a thread in an alertable state using various Windows APIs functions such as (SleepEx, MsgWaitForMultipleObjectsEx, WaitForSingleObjectEx and more)
  2. Inject the shellcode into memory
  3. Call the QueueUserAPC function to execute the shellcode

Back to EarlyBird technique.
Now that we understand the classic APC Injection, understanding EarlyBird should be much easier :)

The EarlyBird technique starts by creating a new process (child process) in debug mode or suspended state.
The function that creates the child process returns the process ID, a handle to the process and a handle to the main thread of the newly created process.

Figure 1 - The above code snippet demonstrates the function that creates the process based on the process name we provide
Figure 1 - The above code snippet demonstrates the function that creates the process based on the process name we provide

In the “CreateSuspendedProcess” function, we need to supply a process name that we want to create, in this context we are using GetEnvironmentVariableA API to get the “C:\Windows” environment variable.
After that we concatenate the variable that holds “C:\Windows” with “\System32\lpProcessName”, In this case it will be “C:\Windows\System32\notepad.exe”

The next function is responsible for injecting the shellcode to the remote process and return the base address of the shellcode in the child process.
The flow is as follows:

  1. Allocate memory inside the child process with “PAGE_READWRITE” permissions using VirtualAllocEx
  2. Coping the shellcode into the remote buffer using WriteProcessMemory
  3. Change the permission of the remote buffer to PAGE_EXECUTE_READ for later execution.

Figure 2 - The above code snippet demonstrates how we inject the shellcode into the newly created process using the process HANDLE we got from the previous function using VirtualAllocEx & WriteProcessMemory

Figure 2 - The above code snippet demonstrates how we inject the shellcode into the newly created process using the process HANDLE we got from the previous function using VirtualAllocEx & WriteProcessMemory

 

When the “InjectShellcodeToRemoteProcess” function finishes executing, it returns the remote address where the shellcode is located within the child process.

Moving onto the main function(){}
We start by defining the process_name as “notepad.exe”, and initialize variables that will hold the returned output from our functions

  • hProcess: HANDLE to the child process
  • hThread: HANDLE to the main thread of the child process
  • dwProcessId: The PID of the child process
  • pAddress: The base address of the shellcode stored within the child process’s memory

Once we created the process and injected our shellcode into that process, We pass the returned address of the shellcode in the child process into “QueueUserAPC” function along with the process’s main thread.

The child process is still in suspended mode, which means it won’t run immediately, our APC call is queued to the main thread, and once resumed with “ResumeThread”, will execute.

The same could be achieved with a debugged process, however in order to execute we will need to resume the thread using “DebugActiveProcessStop” instead of “ResumeThread”.

Figure 3 - The above image shows how we implement the two functions together inside the main function
Figure 3 - The above image shows how we implement the two functions together inside the main function

Let’s follow the process dynamically:

In the following image we can see that the program created notepad.exe, Injected the shellcode into notepad and executed our shellcode with QueueUserAPC.
And we got a beacon! :)

Figure 4 - successfully created the child process and got the beacon to our Sliver C2 server and ultimately bypassed Microsoft Defender
Figure 4 - successfully created the child process and got the beacon to our Sliver C2 server and ultimately bypassed Microsoft Defender

Digging a little deeper with x64dbg, we can see the shellcode address inside notepad.exe:

Figure 5 - Using x64dbg debugger to view the shellcode that was injected to the child process
Figure 5 - Using x64dbg debugger to view the shellcode that was injected to the child process

Final note:

In today's ever-evolving threat landscape, traditional security measures like antivirus (AV) and endpoint detection and response (EDR) often fall short. Even the most sophisticated defenses can be circumvented through clever techniques and vulnerabilities.

Imagine malware that can slip past multiple security vendors with relative ease. Our method represents a glimpse into the complex world of evasive malware development. While a single technique might not always be enough, combining various approaches can significantly enhance a malware's ability to evade detection.

This example demonstrates the fundamental principles involved in creating evasive malware. By understanding these techniques, you can better anticipate and defend against advanced threats.

Don't let your organization become the next victim. Upgrade your security strategy with our innovative solutions.

More techniques to combine with this shellcode loader are recommended as follows:

•  Shellcode obfuscation/Encryption
•  IAT Obfuscation
•  Function encryptions and decryptions during runtime
•  Signing the binary
•  Adding metadata to the binary
•  Sandbox detection

Until the next one! (:
Liav Mizrahi

Find out how KPMG

can help your company

 

 

site by: TWB.co.il
© 2024 KPMG Somekh Chaikin, an Israeli partnership and a member firm of the KPMG global organization of independent member firms affiliated with KPMG International Limited, a private English company limited by guarantee
Contact KPMG Home page