Using the Registry for Malware Command and Control

Using the Registry for Malware Command and Control

Welcome back to my mini-series on simple registry operations for malware development! If this is the first you're seeing of it, you can read the second article on writing to registry keys here on my blog, or here on Medium.


Alright, so now we know how to create registry keys and how to write to them. In this article we're going to talk about how to read from registry keys and how to combine everything we've discussed to create a communications system so that our malware can communicate with a command-and-control (C2) server. Obviously, most malware is pretty pointless if it can't even phone home, so this is a pretty vital part of malware development.

There are many ways to facilitate communication between the victim and the C2. I chose to use the registry just to teach myself how to use the registry, but you can also use named pipes, like APT41 did or just use raw socket programming. There are tons of ways to do it, but I think there are some benefits to this method that I'll discuss toward the end of the article.

Registry Reads

I was going to skip this part entirely, because it's that easy, but I literally already did creates and writes, so I figured I have to do reads as well.

The RegQueryValue function is very straightforward. You input an open key handle (HKEY) and an optional pointer to a C string object representing the sub-key (LPCSTR; here I left it null, so the value being read is going to be the default sub-key), a DWORD value representing the size and a pointer to a buffer to store the result in. In the code snippet above, I passed the size (DWORD *len) and buffer (char *ret) as variable inputs to the getRegVal function and I return the value.

Looking at it now, I realize that I'm passing the buffer by reference, so this should be a void function instead of one that's returning the pointer itself, but whatever... you get the point.

The System

Here's the basic idea:

  • We have one registry key that we write all info that we want sent to the C2
  • We have multiple "writing" processes that will write all relevant information to that registry key.
  • We have one "watching" process that will watch the registry key and send whatever data needs to go to the C2
  • The watcher will then wipe the registry key.

Why do it this way? Well, basically, it allows us to have a bit more modularity in our malware. We don't have to implement new net code in every new module of our malware, we just give them all the ability to write to the same registry key and the watcher module will do the rest. We can basically do the same thing in the opposite direction if we want certain modules to be able to listen out for incoming communication from the C2: we'll have a "listener" module that waits for communications from the C2 and writes that to the C2, while the module expecting that incoming communication knows to check that registry key for information. We don't need every module to listen out for incoming connections, just the one "listener" module that writes incoming comms to a hard-coded registry key. Then every module we write that depends on incoming data from the C2 just has to be able to read from that registry key.

Really, the implementation is easy. Just use the functions that create and write to registry keys (detailed in this blog on creating the key and this blog on writing to the key) and the mechanism to read from the keys detailed above. After that, you just need to separate the processes to create watchers, listeners and writers.

And if you want to know how to set up that process, you'll have to check in to the blog later, as that's its own blog series... 😉

(psst... I have an RSS feed set up. Check it out here)

Pros and Cons of the System

So, there are some issues with the system. First, registry reading and writing is highly visible to anti-virus solutions and reverse engineers. It's easy to find (we'll be proving this later on when we actually reverse engineer our own malware) and easy to write detections for. There are practical issues with it too: what happens if multiple modules try to write to the same registry key at once? Will we have to create a new registry key for each module to read from and write to, and then index that somehow for the watchers to find them? That makes this malware a pain in the ass to write and very noisy to reverse and detect.

The pros are obvious. As long as the system stays simple (ie. there are only a handful of modules running and doing IO on the same registry key at once) this is a pretty straightforward and simple solution. That being said, because of what we mentioned above, we're going to need to find a new solution relatively soon.

Check in to the blog to watch the development continue! This is a fun project to work on and you can watch its video form on my RRE playlist on YouTube here.