Inhibiting Malicious Macros by Blocking Risky API Calls


Microsoft Office Macros have been the bane of security analysts’ lives since the late 1990s. Their flexibility and functionality make them ideal for malware authors to use as a primary stage payload delivery mechanism, and to date the challenge they pose remains unsolved. Many organisations refrain from blocking them completely due to the impact it would cause to their users, and instead rely on a combination of detection and mitigation technology to compensate for the risk they pose.

I have long thought that it would be ideal if Microsoft were able to implement granular controls via group policy over which activities macros were permitted to perform, for example allowing the blocking of process execution or network activity. In the interim, I have been experimenting with alternative methods to limit which functions a macro can call, either by redefining or patching the high risk API calls to prevent their intended outcome.

Below we can see a very basic example of what a malicious macro might look like. The fact that the subroutine is named “AutoOpen” means that it will be run as soon as the document is opened (and if required, macros are enabled).  The command “Shell” at the beginning of the line instructs Word to execute the process as specified in the parameter, so in this case the macro will launch the Windows calculator.




Option 1 – Using global templates to override built-in functions

Shell is the function built into VBA which is used to launch new processes, and as such, can often be found in malicious macros. Malware authors leveraging macros as a primary stage payload typically want to either download or drop a file, and then execute it. Alternatively, they could decide to execute an existing process on the system, such as powershell, with parameters which will take actions against their intended target. Common to both of these methods is the requirement for something to be run, and this is where Shell comes in. If we were able to somehow disable the Shell function, then we might be able to prevent the malicious macro from succeeding in it’s goal.

The first experiment involved redefining the Shell function, with the hope that the newly defined function would override the built-in one. We can achieve this by placing the code in the global template which is named normal.dotm or within an add-in (which is effectively a template that is loaded every time Word is opened), either way, our code will become part of the malicious macros execution.

Below we can see the redefined function used as part of this experiment. This was saved within normal.dotm (the global template), with the intention that when Shell was called, rather than calling the system function to launch the process, our redefined function would be called, resulting in a popup warning the user that the activity had been blocked.




Then, using the one line test macro that attempts to execute ‘cmd.exe /c calc.exe’, we can see that the redefined function worked well and blocked the execution of the process. Unfortunately, it only seemed to work when the malicious code was placed within the document and not when it was within a seperate module. The reason for this is unknown and warrants further research, as if solved, this would be the easiest way to achieve our goal.




Option 2 – Patching associated API in VBE7.dll to alter behaviour

For a more surgical approach we can look at API hooking the dll which is leveraged when macro code is executed. Looking through the dlls, which are loaded into Word at runtime, we can observe that VBE7.dll includes a large number of exports that appear related to the execution of macro code. Below we can see a snapshot from the list of exports with one in particular highlighted, rtcShell, that warranted further investigation.




Digging into this function we can see that it’s nothing more than a small wrapper around the CreateProcess Windows API call. The particular code block which executes the process is listed below. Looking at the parameters being passed to the API,  we can see that the EBX register is being used to hold a pointer to the name of the process to be executed.




At this point, if we want to alter the way the process is launched we can patch the instructions to alter the process creation flags, which is one of the parameters passed to the CreateProcess API. Alternatively, we could completely patch out the API call to prevent the execution from occurring.

In this case we are going to leverage the CREATE_SUSPENDED process creation flag to allow the process to launch, but immediately be frozen into a suspended state, preventing the code from running.




The patch sets the ECX register to 4, which is the numeric value of CREATE_SUSPENDED, and then this is pushed as the creation flags parameter to the CreateProcess API call, resulting in the process being instructed to launch in a suspended state.




Following this patch, a test macro that was designed to launch powershell was executed, and as we can see from the process explorer window, it was placed into a suspended state, thus mitigating any impact and allowing an opportunity for endpoint protection sensors to scan and identify any threatening behaviour.




These are just proof of concepts, and would require more research and work before they were used in a production environment. I still believe that the ideal state would be for Microsoft to implement more granular security controls against macros, allowing organisations to continue using them, but at the same time empowering them with the ability to limit their capabilities depending on individual risk appetites.


Any comments or feedback would be very welcome!


-Adam (Twitter: @CyberKramer)

Leaving the Backdoor Open: Risk of Remotely Hosted Web Scripts


Many websites leverage externally hosted scripts to add a broad range of functionality, from user interaction tracking to reactive design. However, what you may not know is that by using them you are effectively handing over full control of your content to the other party, and could be putting your users at risk of having their interactions misdirected or intercepted.

How so? Well, when you reference a script file, either locally or remotely, you are effectively adding that code into your page when it’s loaded by the user. JavaScript, as an example, is a very powerful language that allows you to dynamically add or modify content on the fly. If the location and content of the script is controlled by someone else, the other party is able to modify the code as they see fit, whenever they wish. Let’s hope they never get compromised or go rogue!


How many of you would click Yes if this warning came with a script? Not many I suspect!

Demonstration of concept

I’ve put together a small demo page on my website to show the issue ( It’s pretty straight forward, I’ve referenced a script hosted on an external site – in this case my attempt to include some old style blink tags on my page.


However, rather than the intended script, the JavaScript on the other end was replaced with the following code, which redirects the user away from the intended site to, potentially, something malicious such as a phishing page.


It’s that easy. This concept is pretty basic, but what if the script was setup to conduct keylogging, or manipulate input data before it’s submitted? Uh-oh!

Well that doesn’t sound good, any suggestions?

Firstly, use the debugging functionality of your favourite browser to identify whether your website leverages any externally hosted scripts. I’ve used Google Chrome against my website and can see that Google Analytics fits into that category.


Now consider whether you can bring the scripts in-house and store them on your server. If you can’t and must use externally hosted scripts, it may be worth keeping an eye on what is being served up. Perhaps even schedule a web content malware scan against the script files on a regular basis. Additionally, make sure the site hosting the script is still live and the domain hasn’t expired, making it available for sale!

Happy holidays!

-Adam (Twitter: @CyberKramer)

Automated Hunting of Software Update Supply Chain Attacks


Software that automatically updates itself presents an attack surface, which can be leveraged en masse through the compromise of the vendor’s infrastructure. This has been seen multiple times during 2017, with high profile examples including NotPetya and CCleaner.

Most large organisations have built robust perimeter defences for incoming and outgoing traffic, but this threat vector is slightly different and far more difficult to detect. Update packages are often deployed in compressed, encrypted or proprietary formats and would not easily be subject to an antivirus scan or sandbox analysis during transit. This leaves us with a large number of trusted processes within our infrastructure that could turn on us at any time and download something evil, which could potentially be undetectable by endpoint antivirus software.

It would be almost impossible to detect all potential malicious code changes, as they could be as simple as changing a single assembly instruction from JNZ to JZ to allow for unauthorised access or privilege escalation to occur. However, this doesn’t prevent some additional proportionate due diligence on the update package being pulled down and installed.


Methodology for discovering inbound evil updates

1. Discover all the software across your estate that could be auto updating
Let us consider for a moment software that automatically updates, and how it looks on the endpoint. Firstly, it needs to open an internet connection to a server that will allow it to identify whether the version currently running is up to date, or whether there is a newer version available. This may occur when the process is first executed or at intervals (set dates or times or even randomly). If the version is current then it will try again later, mostly likely connecting to the same server and repeating the process of checking the version numbers. The traffic volume on each occasion is likely to be very small, after all, all that it needs to ask is “what is the current version number?” and the reply need only be “1.0.32” or similar.

If we put these components together we can build a search for a process, other than a browser (to reduce the noise), which makes repetitive connections to the same server on multiple occasions. We can further refine by looking for low volume traffic in the transmissions. This data may contain false positives such as the checking of licence validation, however this doesn’t matter as we will refine this further in the next stages.
2. Monitor traffic ratios for evidence of updates being downloaded
Once we have a list of processes, devices and servers that have displayed the behaviour from our discovery phase, we can now monitor the traffic volume ratios for abnormal behaviour. Consider a process that had been polling the same server with 5KB uploads followed by 50KB downloads for the past month when suddenly the volume of the download changes to 300MB. It would be a clear outlier based on volumes and upload/download ratios.
3. Perform automated sandbox analysis on detected binaries post update
Now we’re looking for a suspicious update, not just any update, so we can send the installer from the endpoint to an internal sandbox for analysis. Alternatively, we could trigger the same update to occur within a sandbox running our gold image. The sandbox would perform a behavioural analysis, which we would use to highlight any suspicious behaviour during, or after the update process takes place.
4. Alert CERT for further examination should there be evidence of anything suspicious
This can then feed the alerting system used by our SOC/CERT for a manual review and prompt containment activity should the updates contain malware – at this point the number of machines that have pulled the update should be small and we can prevent further infections through proxy blocks etc.


Demonstration of concept

Here we will demonstrate the concept by conducting a deep dive into the behavior of the Notepad++ update process. We begin by identifying the polling between the process and update server. We can see from Process Monitor below that the traffic volumes are low, and the upload / download ratio is relatively similar, approximately 1:11 when there is no update to be downloaded.


Now let’s have a look at what happens when there is an update available.


We can see the difference when there is an update to be pulled, in this case the download volume is significantly higher than the upload as we would expect, in fact it’s over 673 times higher at 1:7756.


In addition, following the network activity we can see that a process launch has been identified. This is the start of the update installation and provides us details on the location of the update binary.  At this point we can take the desired action to review the file, this may include a local scan or better yet, uploading the binary to an internal sandbox for behavioural analysis to take place – this would give us the added benefit of detecting a threat before the antivirus signatures are available.



Practicalities and further ideas

In a large network there is going to be a lot of noise and you may want to select the top 50 auto updating processes that are most widely utilised across the estate and focus on them. This way you can be more selective about the alerts that go to your SOC.

Some processes may update on the fly using hot patching, in which case better results would be obtained from the creation of a custom image for your sandbox with all of these processes installed, so there would be no need to send/pull binaries and you could monitor the entirety of the update process taking place, including all files dropped to disk and executed during the update.

Feedback and ideas are always welcome!

Happy hunting

-Adam (Twitter: @CyberKramer)

Acquiring a Memory Dump from Fleeting Malware


The acquisition of process memory during behavioural analysis of malware can provide quick and detailed insight. Examples of where it can be really useful include packed malware, which may be in a more accessible state while running, and malware, which receives live configuration updates from the internet and stores them in memory. Unfortunately the execution of some samples can be transient and the processes will be long gone before the analyst has a chance to fire up ProcDump. A while back, HBGary released a nifty tool called Flypaper, which prevented a process from closing down, allowing more time for the memory to be grabbed, but unfortunately the tool is now difficult to find and awkward to use. I’ve spent some time considering a suitable alternative that would work on the latest versions of Windows.

A little known feature…

During my research I found an article detailing a little known feature in Windows entitled ‘Monitoring Silent Process Exit‘.

TL;DR – You can configure Windows to automatically generate a memory dump when a process with a specified name exits.

So what this means for us is, even though the malware finishes running very quickly, we can obtain a full memory dump and extract what we need from it at our leisure.

This feature is designed as part of the Windows debugging portfolio, but we can use it as a tool in our belt. The easiest way to configure is by using a Microsoft tool named gflags.exe, which is easy to download and use. The screenshot below shows the configuration that I’ve had success with. You provide the name of the executable you’re interested in keeping an eye on (it doesn’t matter from where the process is run). In addition you have the option to choose what kind of memory dump you want generating, Custom Dump Type 2 represents MiniDumpWithFullMemory, which I found to give the most comprehensive output. There are plenty of other options that can be found on MSDN. Then you just need to run the process and wait for it to finish.


Testing the concept

To test the concept I wrote a tiny program, shown below, designed to load a string to memory and have the process exit very quickly – certainly before we would have a change to pull the string from live memory.

int main()
char secretString[] = “This is a secret string!”;
return 0;

I compiled, executed and the mini dump appeared in the appropriate folder. A quick check with BinText showed the secret string that had been stored in memory.


This is all instigated through a small number of registry entries, details of which are listed in the Microsoft article on the subject, and could easily be implemented into a sandbox or endpoint security setup to gather clues about what has occurred. I’ve found this to be a neat alternative to Flypaper without having to go to the trouble of writing a hook for the ExitProcess function.

Happy analysing!

-Adam (Twitter: @CyberKramer)

Uncovering Targeted Web-Based Malware Through Shapeshifting

Targeted Web-Based Malware?

Malware authors are frequently observed leveraging server side scripting on their infrastructure to evade detection and better target their attacks. This includes both exploit kits and servers hosting secondary stage payloads, all of which can easily be set up to alter their responses based on the footprint of the visitor. This could include geolocation of the IP address visiting the site if the attacker is targeting users from a particular country or region, or perhaps user-agent if they are only focused on certain browsers or operating systems. Without access to the source code leveraged on the server, it is difficult to detect whether it would alter its behaviour if you were visiting from a different device or location, and therefore malware analysts may find themselves declaring a link benign, or that the payload server is down, when in fact, it is only presenting that way to the analyst in question.

Got an example?

An example of this can be seen in the Malwarebytes blog on Magnitude exploit kit which details that  “…users are inspected at a ‘gate’ that decides whether or not they should be allowed to proceed to Magnitude EK. This gate, which has been nicknamed ‘Magnigate’ by Proofpoint, performs additional checks on the visitor’s IP address and user-agent to determine their geolocation, Internet Service Provider, Operating System and browser information…”

Hmm, so what can I do?

There is of course a balance here, even if you have access to VPN software, which allows you to select the country you want to appear from, it would be extremely time consuming and cumbersome to iterate through all of the available countries, each time using different browsers and painstakingly looking to identify whether there was any variation in the responses.

To aid in this task, I have written a new tool which automates this whole process and may be useful during malware analysis if you suspect the server is hiding something from you.

It works as follows –

  1. Loads a list of countries and user-agents that you want to appear from
  2. Leverages a proxy listing website’s API to obtain various country proxies
  3. Verifies that the proxies are working, and that the geolocation is per requirements
  4. Connects to the server using the proxy and iterates through all of the user-agents requesting the site multiple times
  5. Identifies any results which are different from the control value and highlights to the analyst


I’ve uploaded a number of test documents to my webserver, which you are welcome to use for your testing: &

Both of these do the same thing – they wait until they observe someone connecting from a Chinese IP address with an iPhone user-agent before presenting the main content. The first URL will return a result in all other circumstances stating “Go away”, and the second will return a 404 error unless the conditions are met.


The screenshot below shows the script iterating through various user-agents whilst connected to a Chinese proxy. In each case we can see the result was a 404 until the iPhone user-agent was sent, after which the script presented a ‘diff’ style output on what was different about this case.


Great! Where can I get it?

The script was written in Python (v3.x) and is available from Github here.

Please feel free to use / fork / enhance / provide feedback.


Happy analysing!

-Adam (Twitter: @CyberKramer)


Turning a Snapshot into a Story: Simple Method to Enhance Live Analysis

System snapshots are a core component when conducting forensic analysis on a live machine. They provide critical insight into what was going on at the time they were taken, but this is also their limitation: your view is limited to a precise moment in time, without context and the opportunity to observe changes as they occur.

Take an example of malware analysis – you’ve executed a malicious process within a virtual machine and run strings against the process memory. This can be exceptionally useful at obtaining information such as IP addresses and configuration information, but what if the sample hasn’t had the chance to contact it’s C2 server yet? You may not get the information you desire at the precise moment you execute the strings command.



Whilst considering options on how to expand on the snapshot and monitor system changes in real time, I experimented with several ideas including development of a system driver, or using Kernel Tracing, all of which were fairly complex, when it struck me – a snapshot is like a picture, and if you put together enough pictures, one after another and play them quickly, you end up with a film!

Eight lines of Python later I developed a proof of concept which works pretty well. It was designed to be flexible enough to allow the user to decide what snapshot tool was to be monitored, and the frequency to do so. Every iteration, it gathers the output from the executed subprocess and compares it against an array of previously observed results. If there is something new, that hasn’t been seen before, it displays it to the user along with a timestamp, and then adds it to the array to prevent future duplication.




Let’s play through an example. In the image below I have decided to dump the strings from process id 5284, which is a browser. I am piping the output into grep and only interested in strings that contain the phrase ‘cyberkramer’. When the script starts it will do a first pass against the process memory and store all the results it finds that meet the criteria into an array within the script. A second later, it will re run the process strings dump – as it has seen the same strings previously, they will not be displayed again. However, if I then typed cyberkramer_writes_code into the URL bar, it will find a new string in memory and display it to me along with the timestamp at which it was found.




Another example to demonstrate the flexibility of script is to run it against netstat. In this case I am only interested in results that contain “123”. When the script was first run at 12:39:38 I was presented with two lines ending * : *, at this point the script had stored the baseline values. I then loaded a browser a visited, and at 12:40:11 the script detected the new line output by netstat during that iteration, and it was presented it to me.



Tools such as Process Monitor can assist with monitoring for operating system changes, but here are a few examples of utilities not covered by traditional behavioural monitoring tools which it may be useful to try with:

The source code is available from my github repo – please feel free to fork and alter to suit your needs.

I would be very interested to hear your feedback and hope this is of some use to you. It can be used against any program which produces results via the command line, and may be especially useful for malware specialists conducting behavioural analysis.

Happy reversing!


Rapid Provisioning of a Malware Analysis Environment

The preparation of a malware analysis environment can often be a lengthy and repetitive process. I am not referring to setting up a virtual machine which contains all of your tools, but rather recognising that each sample you analyse may have very specific environmental requirements before it is willing to execute fully. For example, it may require a certain number of files to be present in the My Documents directory, or may check for a specific registry key.

If we consider how many analysts around the world were looking at the same major threats in 2016, it seems rather silly for each of them to have to manually setup their environments as required by the sample. One solution may be sharing of VMs, but this comes with issues such as operating system licensing and the shear size of the package to be exchanged, which got me thinking, there’s got to be an easier way.

Accordingly, I have been developing an open source tool ‘rapid_env’ (as in, ‘rapid environment’) which allows for the instant, template based provisioning of a Windows environment. This can include elements such as files, registry keys, processes and mutex, all of which can alter the way that many of the current threats behave.

[View C++ Source Code]
[Download Binary]
Continue reading Rapid Provisioning of a Malware Analysis Environment

Hindering Exploitation by Analysing Process Launches

Malware can do some nasty things to your system, but it needs to get on there first. Thankfully, users have become more suspicious of files named FunnyJokes.doc.exe and so malware authors have had to become more innovative, using a mix of social engineering and the constant stream of 0-day browser exploits to land evil code on your box.

Popular infection methods include leveraging exploit kits to run arbitrary code in the context of your browser and ‘infecting’ documents files, such as Microsoft Word documents, which still, 20 years since the first macro virus, allow you to automate the downloading and execution of files. Recently I have been pondering the similarities between various attack types and how they present themselves on the end users machine. It strikes me that, more often than not, the endgame is launching a process by the targeted program.

This begs the question:

Is there ever a legitimate reason for Internet Explorer or Microsoft Word to launch a child process?

Of course there are exceptions, I’m not talking here about Internet Explorer launching a low integrity version of itself every time it runs, but something infrequently seen and significantly less trusted.

Common attack surface: macros

Let’s start by looking at Microsoft Word macros, which are used by several current malware strains. If you interrogate the macro code you are likely to come across a call to the Shell() API, which is one method by which you can execute a process. It looks something like this:

Result = Shell(“C:\windows\system32\calc.exe”, vbNormalFocus)

No prizes for guessing what program is going to be launched here, but what is interesting is that the calculator launches as a child process of winword.exe (Microsoft Word), which can be seen in the ProcessHacker snippet show here:


Taking a look at a real world example, this neat analysis shows how again, based on the fact that this is dropped using a macro, we can see some strange child processes appearing from winword.exe – interesting!

Further attack surfaces: web browsers

How about Internet Explorer? Well, the desired outcome of any high-stakes exploit writing competition tends to look something like the picture below. Again, we can see the launched program is a child of the attack surface – in this case, iexplore.exe.


Again, in the real word, exploit kit authors leverage vulnerabilities in the browser and cause malware to spawn from iexplore.exe (see the image right at the bottom).

It appears a pattern is emerging!!

What can we do about it?

So here are my thoughts – if we watch for processes being spawned from these common attack surfaces we may be able to detect anomalous activity. I decided to experiment by writing a python script which does the following…

  • Utilise WMI to detect new processes being launched
  • For each new process launched, identify the name of its parent
  • If the name matches that of a common attack surface (browser, word processor etc)…
  • …alert the user and terminate the process!

My code looks like this (and is available here):


When I tested it and made Internet Explorer launch calc.exe the result I got looked like this:


and boom! it’s gone…

Running a python script in your environment may not be a viable solution, but if you have a flexible endpoint monitoring solution it may be worth considering implementing a rule to monitor for unexpected spawn!

Follow me on Twitter: @CyberKramer

Detecting Shellcode Hidden in Malicious Files

A challenge both reverse engineers and automated sandboxes have in common is identifying whether a particular file is malicious or not. This is especially true if the malicious aspects are obfuscated and only triggered under very specific circumstances.

There are a number of techniques available to try and identify embedded shellcode, for example searching for patterns (NOP sleds, GetEIP etc), however as attackers update their methods to overcome our protections it becomes more difficult to find the code without having the exact version of the vulnerable software targeted, and allowing the exploit to successfully execute.

In this post, I will discuss a new technique I have been experimenting with, which approaches this issue from a different perspective, forcing the execution of the exploit code, no matter what software you have installed. It is based on two core principles:

  1. If you try and execute something that isn’t code (e.g. a text string), the program will likely crash as the machine code interpretation of this data is unlikely to make much sense.
  2. If you begin executing code from the start (i.e. wherever the instruction pointer would have been set during the exploitation phase), it will run to completion – no matter how obfuscated the instructions are.

So here’s my theory: If we attempt to “execute” the contents of a malicious file (such as a pdf), byte by byte, catching the exceptions as the program continually crashes and then increasing the instruction pointer by one each time, we will eventually come across any malicious code contained therein which will be triggered, run to completion, and provide indicators of its malicious nature through behavioural analysis.

The experiment

In order to test this concept, I wrote a program which does the following:

  • Maps the requested file to memory (i.e. make a full copy of it in memory).
  • Set the instruction pointer to the first byte, and allow it to run.
  • It will probably crash! (The instructions won’t make sense!!)
  • Catch the error, and use the error handler to increase the instruction pointer by one.
  • Try again, and again, and again…
  • If the file contains shellcode, you should eventually hit it, and it will run – hurrah!
Demonstrating the concept
Step 1 – Generating malicious document and starting metasploit reverse handler

We begin by generating a malicious pdf document containing the reverse_tcp metasploit payload, and starting the handler to await incoming connections. The attacker is now waiting for the victim to open the file with a vulnerable pdf reader, at which point it will connect back to the attackers machine.


Step 2 – Dealing with the malicious pdf

Now, let us imagine we are conducting an analysis on this document (either manually, or using an automated sandbox) – the issue we are going to have in this case, is that we are unlikely to have the vulnerable version of the software installed, the exploit won’t work, and we will be none the wiser that it exists! This isn’t to say that the intended victim doesn’t have the vulnerable version installed.

Let us try running the PDF through our proof-of-concept shellcode hunter…


Step 3 – Bingo – shellcode has been located and triggered

As we can see below, the shellcode in the document has been triggered and established a connection back to the metasploit listener! If we were conducting a behavioural analysis, we would be able to identify the suspicious activity and take appropriate action.


Video demo

Check out the video demo if you’d like to see this in action live:


Code sample

If you’re interested in testing the concept, or integrating it into your software (anyone fancy writing a cuckoo module?) – The code I used was pretty simple, and looked like this:


It could definitely be a lot more advanced than the proof of concept I wrote for this demo, for example, if the shellcode started with a JMP $-2 instruction it would trap this code by causing an infinite loop. This could be potentially overcome using multi-threading to continue the search after the first code block has been found.

You may have to play with your compiler settings to get this to work. I set Visual Studio to compile with the ‘Debug’ configuration and switched off some of the protections. If you need some help getting it working, send me a tweet.

I will be presenting this and a few other concepts during a session at SANS London in a couple of weeks, if you’re attending the conference – it would be great to have you along!

Let me know what you think!

Follow me on Twitter: @CyberKramer

Identifying and Disrupting Crypto-Ransomware (and Destructive Malware)

In recent years, malware has become very personal. Crypto-ransomware threats, including CryptoLocker, CryptoWall and TorrentLocker (pdf), have infected home users, businesses and even police departments, all of whom have had their personal data and hard work held hostage. When we think of precious family photos or an academic thesis being wiped by pure greed, it can become rather emotive. This is nasty stuff, and we need to do something about it!

I have been giving some thought to how we can stop crypto-ransomware doing it’s thing. Initially, I thought about interfering with the Windows CryptAPI, perhaps hooking the CryptEncrypt function, however page 16 of a report analysing various samples by Bromium shows that some samples use CryptoAPI, others use OpenSSL libraries and a few even use custom inline code.

I then began thinking about what else was common to all of these threats and realised that they all (by their very nature) access a LOT of files, and therefore create an above average number of handles.

This is also true of destructive malware, a growing trend which strikes fear into most enterprise administrators. This involves vast numbers of personal and system files being overwritten to prevent them from being recovered. Sure, we (should) have backups, but can you imagine rebuilding a network with 200,000 endpoints? Ouch!

Okay, so what is a handle?

Microsoft provides a neat definition of a handle on MSDN, and rather than trying to re-word it, I have attached a quote from the site below:

Microsoft – Windows Dev Center – Handles and Objects
An object is a data structure that represents a system resource, such as a file, thread, or graphic image. An application cannot directly access object data or the system resource that an object represents. Instead, an application must obtain an object handle, which it can use to examine or modify the system resource. Each handle has an entry in an internally maintained table. These entries contain the addresses of the resources and the means to identify the resource type.

This is one of the several layers of abstraction that separate the user (and all the processes they’re running), from their physical assets, such as the hard drive. Any request to access a file on disk needs to go through the Windows kernel, and if you want to modify that file in user mode, you need to create a handle – simple as that!

So how are handles going to save me?

As we’ve discovered, if crypto-ransomware wants to read and then encrypt your files, it needs to create a handle for every file it interacts with. It doesn’t matter what encryption algorithm it uses, this is a much lower level concept based on how the Windows kernel interacts with system hardware.

If we can keep an eye on the frequency of new handles being created by every process we might be able to detect abnormal activity. This would also apply to destructive malware that has been designed to overwrite lots of files to prevent recovery. Don’t forget, if it wants to write to a file, it needs a handle.

To trial this concept, I’ve written a tool named handle_monitor, which takes stock of every file handle, by process, across the system. It then has a little pause (at the users discretion), and checks again, identifying any new handles which haven’t been seen before and tallies up the number of new handles created. If a threshold is passed within a defined number of cycles, then an alert is raised and an action (such as suspending the suspicious process) can be taken.


To replicate the effect of malware which makes a large number of disk read/write operations, I’ve written a small program called hm_test.exe, which writes the requested number of files to disk.

Figure 1. hm_test.exe writing to a large number of files

The Handles tab from the Process Hacker properties page shows the rapid creation and release of handles as the files are written.

Figure 2. Process Hacker demonstrating the open handles

Now as we launch handle_monitor, we are able to specify, in detail, every element of the analytical process and how the program will go about monitoring. Notice that in this case we are using the /suspend parameter which instructs the program to attempt to suspend any suspicious processes.

Figure 3. handle_monitor.exe being launched with custom parameters

Within seconds, the program identifies, based on our options, that hm_test is acting suspiciously and suspends the process. If this was crypto-ransomware, it would have been stopped after only encrypting approximately 30 files.

Figure 4. hm_test’s activity being caught (and suspended) by handle_monitor

How about a video demo?

You can watch the tool in action by clicking on the image below, which will take you to a YouTube video demo of the tool in action.


How about false positives? I don’t want to accidentally suspend my antivirus!

Good question. This isn’t an exact science and the key to this tool is that the user has the power to decide:

  • Whether suspicious processes are suspended, or we just raise an alert
  • Whether we ignore signed processes assuming they’re safe and focus only on unsigned or whether we review all of them
  • What the threshold is for suspicious activity? We can set it as X new handles in Y cycles

I’d be really interested in hearing what settings work for the samples you hold. A comprehensive analysis of what settings worked against a variety of samples might be a nice idea for a GIAC Gold paper for anyone who is interested in completing one!

The default settings are fairly conservative and you may want to start with a threshold of 2 in 10 cycles with a 100ms pause (as per the example) to increase your chances of finding something. It is worth noting that the lower the pause time, the higher the amount of system resources the program will use, and the lower the threshold, the higher the chances of false positives.

The next step is all about finding the right balance; I’d be very interested in hearing from you if you think you’ve got it right. If you want to get involved either tweet me or post it as a comment below, and once we have a general consensus, I will change the defaults in the source code.

Sounds great! How much?

Free of course! You can download the source code or pre compiled binaries from my GitHub page. I would very much welcome any feedback!

Follow me on Twitter: @CyberKramer