We normally see malware developing and evolving over the years. One particular malware we've been following is ZeroAccess, which has been continuously improving which we first detected it in late 2010. Case in point: in the latest samples, its self-deletion routine has changed.
This is a simple Windows batch file ZeroAccess used to use to remove itself after execution, as a fast and simple way to hide any traces of its presence from the user (click for larger view):
Lots of other malware use this batch file self-deletion method. Recently though, it looks like ZeroAccess wants to be a bit more different and make things more complicated for analysts. It uses the following piece of code (shown without comments) to achieve this:
Now, ZeroAccess uses dynamic forking of Win32 EXE to execute code in another processís context, but with a twist. Basically, instead of loading a Win32 EXE into another processís memory space, ZeroAccess prepares a customized stack and inserts that into another process's context, where it gets executed according to the sequence in the stack.
The commented code below shows the difference between the method used by ZeroAccess and the traditional way:
For this to work, ZeroAccess also modifies the instruction pointer register to point to Windows' native API, ZwWaitForSingleObject. Once the modification and the customized stack are in place, the malware is all set to do some bad and then disappear.
When the remote process is executed after ResumeThread is called, it will first execute the ZwWaitForSingleObject pointed to by the modified instruction pointer register.
This function will wait until the caller process has been terminated and then resume execution on the remote process. It executes the next instruction at the top of the stack to close the terminated process handle, and then continues to execute the next function as the stack grows.
Eventually, this will execute the function for deleting itself by using FileDispositionInformation parameter to ZwSetInformationFile. The diagram below summarizes the custom stack's operations (click for larger view):
On a side note, the latest ZeroAccess is compatible with its older rootkit-capable variants, since we found a similar piece of code in both, which checks for the rootkit device object, \??\ACPI#PNP0303#2&da1a3ff&0 :
On a machine with a ZeroAccess rootkit installed, it returns the specially crafted value STATUS_VALIDATE_CONTINUE; if not, the value STATUS_OBJECT_NAME_NOT_FOUND is returned. This check allows the latest variant to skip over some of its routines if it finds that the machine has already been infected by one of the older, rootkit-enabled variants.
On a final note, our customers are protected from both old and new ZeroAccess variants by various signature, heuristic and cloud-based detections.