0x00 Preface

---

In October 2016, the research team at cybersecurity company EnSilo disclosed a code injection method compatible with all Windows systems, naming it AtomBombing. It is claimed that this method can bypass most security software, and the system vulnerability exploited is difficult to patch.

Therefore, this article will study the principles, test the functionality, analyze exploitation approaches, and summarize defense methods based on open-source code and materials.

Learning materials:

https://blog.ensilo.com/atombombing-brand-new-code-injection-for-windows

Author: Tal Liberman

POC:

https://github.com/BreakingMalwareResearch/atom-bombing/

0x01 Introduction

---

This article will cover the following:

  • AtomBombing Implementation Method
  • Key Techniques
  • Defense Approach

0x02 Basic Knowledge

---

1. Atom Table

is a system-defined table that stores strings and their corresponding identifiers

An application places a string into an Atom Table and receives a 16-bit integer (WORD) as an identifier (called an Atom), which can be used to access the string content, enabling data exchange between processes

Classification:

(1) Global Atom Table

Available to all applications

When a process saves a string to the Global Atom Table, the system generates a globally unique atom to identify the string. All processes within the system can retrieve the string via this atom (index), thereby enabling inter-process data exchange

(2) Local Atom Table

Only available to the current program, equivalent to defining a global variable. If the program uses this variable multiple times, using the Local Atom Table requires only one memory operation

References:

https://msdn.microsoft.com/en-us/library/ms649053

Common APIs:

Add a Global Atom:

ATOM WINAPI GlobalAddAtom(_In_ LPCTSTR lpString);

Delete a Global Atom:

ATOM WINAPI GlobalDeleteAtom(_In_ ATOM nAtom);

Find the Global Atom corresponding to the specified string:

ATOM WINAPI GlobalFindAtom(_In_ LPCTSTR lpString);

Get the string corresponding to the specified atom:

UINT WINAPI GlobalGetAtomName(
_In_ ATOM nAtom,
_Out_ LPTSTR lpBuffer,
_In_ int nSize
);

Note:

For usage examples, refer to the following link:

https://github.com/sinmx/Windows2K/blob/661d000d50637ed6fab2329d30e31775046588a9/private/windows/base/client/tatom.c

2. APC Injection

APC stands for Asynchronous Procedure Call

Principle of APC Injection:

When a thread is in an alertable state, it checks the APC queue; if a function pointer is inserted into the APC queue, that function will be executed

Details of APC Injection:

(1) When a thread calls functions such as SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx, or WaitForSingleObjectEx, it switches to an alertable state

Note:

For reference on alertable state, see:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa363772(v=vs.85).aspx

(2) When a thread enters an alertable state, it repeatedly checks the APC queue in the thread; if a function pointer exists in the APC queue, it will call that function

(3) Use the QueueUserAPC function to insert the function pointer LoadLibrary() into the APC queue to load a DLL

(4) After successful injection, the alertable state ends, and the program continues running, which may cause instability and lead to a crash

(5) If the APC queue is not cleared, the same function cannot be injected repeatedly

(6) For APC injection to work, at least one thread in the target process must be in or capable of entering an alertable state; otherwise, APC injection cannot be achieved

Note:

Most system processes meet the conditions and support APC injection.

APC injection code for reference:

An open-source project

3. Shellcode

In vulnerability exploitation, shellcode refers to the code input into a vulnerable program.

It acts as a binary code framework, ultimately redirecting the program's flow to the payload.

4. Payload

The main functional code (common examples include download and execute, reverse shell, create new user, etc.) is contained within the shellcode.

0x03 Implementation Method

---

1. Write arbitrary data to any location in the target process's address space (Write-What-Where)

Pass shellcode to the target process by reading and writing atoms.

The local process adds the shellcode to the Global Atom Table via GlobalAddAtom, and the target process retrieves the shellcode from the Global Atom Table by calling GlobalGetAtomName.

Thus, the key challenge is how to make the target process call GlobalGetAtomName.

Tal Liberman's approach is to use APC injection to make the target process call GlobalGetAtomName.

However, a challenge was encountered here: the QueueUserAPC function can only pass one parameter to the target process, while GlobalGetAtomName requires three parameters.

Therefore, Tal Liberman debugged the QueueUserAPC function and discovered that the NtQueueApcThread function could pass three parameters.

This issue was resolved.

2. Execute shellcode

After the target process retrieves the shellcode from the Global Atom Table by calling GlobalGetAtomName, it needs to save the shellcode before executing it.

First implementation method: Find a section of RWX memory to store and execute the shellcode.

Not universal; current system protection mechanisms make it difficult to find such memory space.

Second implementation method: Call VirtualAllocEx to allocate a section of memory.

Common method.

Note:

Other common methods, such as using VirtualProtect to set the memory attributes of the shellcode to readable, writable, and executable, and then jumping to the shellcode to continue execution, do not work well here due to the need to consider the issue of passing parameters using the QueueUserAPC function.

Thus, Tal Liberman attempted a third method: Find a section of RW memory to write data and construct a ROP chain to execute the shellcode.

Finding a section of RW memory is not difficult; Tal Liberman chose unused space after the KERNELBASE data segment.

The ROP chain achieved the following functionality:

  1. Allocate RWX memory.
  2. Copy shellcode from RW memory to RWX memory
  3. Execute

Note:

Regarding ROP chain construction, Tal Liberman proposed his own approach, aiming to simplify the ROP chain as much as possible. This optimization mindset is worth learning.

3. Resume execution

After injection, the target process execution needs to be resumed using the undocumented function ZwContinue.

0x04 Practical Testing

---

Test system: Win7 x86

Install Python, install pefile (easy_install pefile)

Compile and generate AtomBombing.exe, AtomBombingShellcode.exe, and AtomBombingShellcode.h

Note:

AtomBombingShellcode.h is generated by \AtomBombingShellcode\Scripts\Post_Link.py. Specific parameters can be viewed in the post-build events of the AtomBombingShellcode project, as shown in the figure below.

Alt text

Launch chrome.exe, execute AtomBombing.exe, injection successful, as shown in the figure below.

Alt text

Alt text

Supplement:

Windows 8.1 update 3 and Windows 10 introduced a new protection mechanism called CFG (Control Flow Guard). For bypassing CFG, refer to the following link:

https://blog.ensilo.com/atombombing-cfg-protected-processes

0x05 Exploitation Analysis

---

Based on publicly available information and actual testing, AtomBombing can be understood as an enhanced version of APC injection: it uses the Atom Table to deliver shellcode, achieves APC injection via NtQueueApcThread, and the shellcode employs a constructed ROP chain to allocate memory, write the payload (which pops up a calculator), and execute it.

The Atom Table is supported across all Windows platforms, and this functionality is unlikely to be removed or patched in the short term, meaning there is essentially no patch to fix AtomBombing.

However, successfully exploiting AtomBombing requires addressing multiple challenges (such as obtaining a thread in an alertable state, passing parameters via NtQueueApcThread, locating RX memory, constructing a ROP chain, etc.), making the exploitation threshold relatively high.

It is not applicable to all processes (the target process must have at least one thread in an alertable state or capable of entering one).

It can bypass some antivirus software but not all (since it uses NtQueueApcThread for injection).

0x06 Detection and Defense

---

Considering AtomBombing as an enhanced version of APC injection, defense methods similar to those for APC injection can be applied. Attackers first need to gain execution privileges on the system and identify a suitable process that meets the criteria.

Detection:

Monitor calls to the NtQueueApcThread function

0.07 Summary

---

This article introduces the implementation approach and key techniques of AtomBombing. Through practical testing, the final conclusion is drawn: AtomBombing is a new DLL injection method, which can be understood as an upgraded version of APC injection. It utilizes the Atom Table to transmit shellcode, achieves APC injection via NtQueueApcThread, and employs a constructed ROP chain in the shellcode to implement the functions of allocating memory, writing the payload (launching calculator), and executing it.