In previous post, my colleague talked about new way to inject virus codes into other normal processes in order to bypass firewall’s detection. During the continuous research of ZeroAccess, we found there’re some improvements for this series of anti-detection and anti-debug methods. And what’s most interesting is ZeroAccess seems to really like lsass.exe. It often wears lsass’s clothing.
In this case, the variation of ZeroAccess did not use ZwMapViewOfSetion to inject into explorer.exe. It just used normal ZwAllocateVirtualMemory and ZwWriteVirtualMemory to fill in explorer.exe’s memory with virus codes.
After entered explorer’s virus code space, it will first calls RtlAddVectoredExceptionHandler to install an exception handler.
After that, it has a smart way to allocate a new block of memory. It calls ZwCreateSection with below parameters:
We can see the FileHandle’s value is NULL. That means the section is backed by the paging file. Then it calls ZwMapViewOfSection to map 0x1F0000 bytes of zero to this section. So in this way, it allocates a memory block without calling normal memory allocation functions, such as VirtualAlloc, LocalAlloc, HeapCreate, etc.
Next, it will fill in this block of memory with virus codes which will be executed at last.
Now what’s interesting comes.
It calls ZwSetContextThread to modify current thread’s context. The context is as follows:
The context flag’s value is 0×00010010, which means CONTEXT_DEBUG_REGISTERS. So with this flag, current thread context’s debug registers will be set after calling ZwSetContextThread. Let’s have a look at some introductions for debug register:
So according to above two pictures, we can see that this sample adds a hardware breakpoint at 0x7c92d500, which points to ZwMapViewOfSection. And it declares that this breakpoint is only effective in current task.
After setting the context, this sample will call an undocumented Windows API, LdrLoadDll, to load lsass.exe. If we continue to track with OllyDbg and ignore the exceptions, the previously installed VEH handler will be invoked. Why? It seems that the ZeroAccess writers know a lot about what LdrLoadDll does. ZwMapViewOfSection will be called more than twice, depending on the process flow, within LdrLoadDll. We already know that a hardware breakpoint is set at ZwMapViewOfSection. So when ZwMapViewOfSection is invoked within LdrLoadDll, an exception is triggered. Since we ignore the exceptions in OllyDbg, the VEH handler will handle this exception.
During the VEH handler, it is mainly to do three things:
- It will first check the exception code to decide how to handle this exception.
- Set the EIP value in current exception’s context in order to make ZwContinue go to virus code.
- Check current Windows version. It only runs in Windows 2000/XP/2003
After these, it sets EXCEPTION_CONTINUE_EXECUTION as the exception handling result.
Since the EIP in exception context it changed, now ZwContinue brings us here:
Now, at first it checks the memory pointer, [esi], to see whether the memory is allocated successfully within LdrLoadDll. If yes, remove the hardware breakpoint. Otherwise, set the memory pointer to 0xA80000. Then set STATUS_IMAGE_NOT_AT_BASE as ZwMapViewOfSection’s return value. This is important. LdrLoadDll will consider 0xA80000 points to the memory which is just allocated for Lsass.exe. It will deal with this block of memory as Lsass’s space. But actually it is hijacked!
After above steps, this sample will go back to LdrLoadDll’s space to continue the execution after the calling of ZwMapViewOfSection.
We mentioned above that ZwMapViewOfSection is called several times within LdrLoadDll. So when ZwMapViewOfSection is invoked again, the VEH handler is triggered again as well. The handler does the same thing as before. But when it goes to ZwContinue, something different will happen. Since [esi] is set to 0xA80000 last time, this time it calls ZwSetContextThread with an empty context to remove the hardware breakpoints.
Then it will go back to LdrLoadDll again to continue the process. Till now, this sample triggers two times of exception. And it uses its own exception handler to do two things:
- Hijack LdrLoadDll.
- Remove the hardware breakpoint if the hijacking is done.
After LdrLoadDll’s execution is finished, the memory block at 0xA80000 is identified as lsass.exe. But actually it’s virus code space.
Then, this sample will call several cleaning functions. Then jump to 0xA80000’s code space at last.
During above article, we missed one thing. That’s the anti-debug measures in this sample. Because this sample installs a VEH handler and adds a hardware breakpoint, when we debug this sample with OllyDbg, we should pay more attention. First, we should make the exception be handled by the VEH handler. So we should set OllyDbg ignore all exceptions. Second, we could not destroy this sample’s hardware breakpoint. But actually, when we debug this sample, we often use single-step command which will obviously destroy this sample’s hardware points. So most of the time, the ZwMapViewOfSection exception will not be triggered. Then we go the wrong process. Last, this sample changes the EIP value in thread context for several times to change the process flow. So we should pay much attention to where the sample will go for next.
So to sum up, this sample adds a hardware breakpoint by itself at ZwMapViewOfSection to hijack LdrLoadDll in order to dress virus memory section in lsass’s clothing. And this way also makes it difficult for analysts to debug it.