The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,949 other followers

I had some Windows ATOM issues before, but this beats them easily

Posted by jpluimers on 2022/10/19

I’ve had some issues with Windows ATOM tables filling up, but nothing like this security bypass:

A new Windows code injection technique, atombombing, which bypasses current security solutions.

Source: AtomBombing: Brand New Code Injection for Windows – Breaking Malware [WayBack] with source code at BreakingMalwareResearch/atom-bombing: Brand New Code Injection for Windows

Note that since writing the first draft, the above AtomBombing article moved via Wayback: to [Wayback/] AtomBombing – A Brand New Code Injection Technique for Windows | FortiGuard Labs.


Edit 20221021

Note that this technique in the end might be less serious than initially thought, see the answer in [Wayback/Archive] security – So, just what are Windows Atom tables for? – Stack Overflow (thanks [Wayback/Archive] Stone True, [Wayback/Archive] Hans Passant and [Wayback/Archive] Anders):


The security world has been abuzz over a new code injection technique called “atom bombing” (see [Wayback/Archive] Injection Attack Description and [Wayback/Archive] Information Security Stack Exchange Question). Simply stated, an attacker can use atom tables to store executable code.

A concern is that the global atom table feature exists across all versions of Windows, and is a deliberate feature, not a bug. It is not clear how to mitigate the threat through changes to Windows.

Just what are Windows atom tables used for? If Microsoft simply said “that’s it, no more atom tables”, what would be the impact?


They are a simple Dictionary<int, string>. One of the many tricks Microsoft used to shoe-horn a GUI operating system and its apps into 640 KB of RAM. Carrying around a 16-bit int is a lot cheaper than having to use a string literal. It doesn’t care that it is actually a string at all, any blob of bytes will do. It is still just plain data. Exploiting it doesn’t just require already having control over the process, you’d still need to turn that data into code. A fallacy that Raymond Chen likes to [Wayback/Archive] make fun of.


TL;DR: I personally don’t think Microsoft is going to make any changes to the global atom table because it is only a minor security issue.

An atom table lets you associate a string with a 16-bit number. You give Windows your string and it gives you back a number. You can then retrieve the string again just by knowing the assigned number.

Every normal process has its own local atom table but it is usually empty and is not a security issue.

There are multiple “global” atom tables that are shared by all processes in the same window station. 1 of them is documented and it is called the global atom table. MSDN is also nice enough to tell us that RegisterClipboardFormat and RegisterClass also use their own atom tables internally in their current implementation. Other functions like SetProp also use atoms but we are only interested in the atom table used by the exploit and atoms are added to that table with the GlobalAddAtom function.

The main purpose of this atom table is to act as a simple storage location so that different processes can communicate with each other in a protocol called DDE. When a process wants to send a message to a window in a different process you cannot send more than 8 bytes (2 parameters, 4 bytes each) and this is not enough space to transfer a filesystem path or a URL.

To work around this limitation the application stores the string/path/URL in the public global atom table by calling GlobalAddAtomGlobalAddAtom returns a number that the application can send to the other process. When the other process receives the DDE message it just passes the number to the GlobalGetAtomName function to retrieve the string.

How is any of this a security issue? It turns out that this overhyped (IMHO) exploit [Wayback/Archive] uses the global atom table to do exactly what the table was designed to do; transfer a string from one process to another.

To inject code into another process you would normally call OpenProcess to get a handle to the desired process, VirtalAllocEx to allocate some memory in this process, WriteProcessMemory to fill this newly allocated memory with your code and finally CreateRemoteThread to start executing this code.

The exploit basically calls GlobalGetAtomName in a complicated way (NtQueueApcThread) to avoid using WriteProcessMemory. It is more impressive how it builds a ROP chain and executes it with NtQueueApcThread but that is not really related to the atom table, the atom table was just a unusual/clever way to transfer memory.

The exploit does not allow evil code to elevate or otherwise get privileges the source process does not already have because NtQueueApcThread cannot be used on any random process, you still need the appropriate privileges to access the desired target process. NtQueueApcThread might have caught some anti-virus companies off guard when the exploit came out but as a standalone piece of code that has to be executed by someone in the first place it cannot do much damage on its own, it has to be combined with other code to be scary.

Can Microsoft remove the atom tables? No, not really, the other tables are too important.

Can they remove the global atom table? No, not really, it is a documented API and has been for more than 20 years and Microsoft does not like to break compatibility.

They could however neuter the global atom table a little. They could make it less global by dividing it into multiple compartments based on the [Wayback/Archive] integrity level of the calling process. This would not change the exploit in question since it cannot access processes with a higher integrity level in the first place.

If we pretend that Microsoft changed the global atom table so that it acts as a per-process table, what would happen?

Microsoft started to move away from DDE in Windows XP but got a lot more serious about it in Vista/7. On this Windows 8.1 machine Internet Explorer still uses DDE for the “Open in same window” command but that is not the default verb for a .html file. Search the registry for ddeexec to find all the applications that use DDE to handle its file associations. On the bright side, file association DDE is only used when a instance of the application is already open. Worst case scenario; close the application before double-clicking a new file.

DDE can also be used to do other things but it is hard to say which applications and/or features would break and how broken they become.

The global atom table can be used for things other than DDE but it is hard to say how common it is to do so.

If the global atom table was restricted to only sharing its strings to processes with the same filename then a lot of these issues would go away because it is often used to just communicate with other instances of the same application.


Related: Some notes and links: when a filled ATOM table is not caused by your Delphi app.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: