We recently encountered a piece of malware via a tweet, which caught our eye because it appeared to be searching for folders related to our product. During analysis we discovered that this malware employs a novel technique to prevent reverse engineering via a debugger, and we felt that it was worth writing about, in case other malware is using similar tricks to make a researcher’s job more difficult.
Basic analysis using Procmon shows that the malware relaunches itself as a child process, which is where most of the action takes place. However, all attempts to attach to the child process with a debugger to get a closer fail with the following error:
The explanation resides in the flags passed to CreateProcess by the parent. When the malware relaunches itself as a child process it does so with the DEBUG_ONLY_THIS_PROCESS flag specified. This causes the parent to act as a debugger to the child, which prevents analysts from attaching their own debugger to get a closer look at what it’s doing.
Then, the parent walks through the child’s execution using the WaitForDebugEvent and ContinueDebugEvent API calls for creating a co-dependent relationship between the parent and the child with no room for an additional debugger:
Since it is not possible to attach a debugger to the child directly, the next best option is to perform a memory dump of the child and analyse this instead. However, the malware is prepared for this kind of approach and takes steps to make it more difficult.
After launching the child with the parent set to debug it, the child calls VirtualProtectEx with the NO_ACCESS flag set on its own memory space. This means that any attempt to read, write or execute in this space will result in an access violation exception.
However, because the exception gets passed to the parent, which is debugging it, the parent handles the exception by calling VirtualProtectEx again on the section with the flags set to EXECUTE_READWRITE to temporarily allow execution. After this, it sets the memory back to NO_ACCESS again to prevent dumping:
Luckily, we can get around this by using IDA to patch the arguments passed to VirtualProtectEx changing the the NO_ACCESS flag to a EXECUTE_READWRITE flag allowing for a complete memory dump of the child: