Blog
MOTW: PE Lurker Analysis: File Infection through a Kernel Driver
10.15.2007 - 4:00 PMPrevious Posts
October 2007| 10/31/2007 | Halloween storm » |
| 10/31/2007 | Hi I am an infected...Hi I am an infected MAC » |
| 10/29/2007 | Beware of Phresh Credit Union Vish » |
| 10/25/2007 | Southern California Wildfire Scams » |
| 10/16/2007 | Sending Out An SOS (Spam Over Skype) » |
| 10/15/2007 | MOTW: PE Lurker Analysis: File Infection through a Kernel Driver » |
| 10/02/2007 | Website Redirection Analysis » |
+ September 2007
+ August 2007
+ July 2007
+ June 2007
+ May 2007
This PE infector doesn't use any polymorphic engine, and isn't metamorphic either, but on the other hand, it uses a kernel driver as the infection component.
I) First run on a clean Windows OS
When an infected application is executed, the first thing the virus does is to get the delta offset used by the virus to access its own data and structures. (Because file infectors use position-independent code and don't know where they will be executed from, they depend on the infected host application).
Right after that, the virus checks whether the delta offset is null or not. If zero, it's the first generation of the virus, and the code actually accesses its data directly.
If not null, the virus fixes the first 6 bytes of its host application, starting from the entry point, because these bytes were overwritten at infection time. The virus doesn't change the entry point of the application; rather, it overwrites 6 bytes in order to call the virus body, probably to -naively- avoid some heuristic detections.
Every infected application starts with the following code:
PUSHFD
CALL VIRUS_START
Anyway, once the entry point code has been fixed, the virus loads a few API functions dynamically and stores them in an array, mimicking the Import Address Table mechanism.
The appended code then gets the local time on the machine, in order to limit the virus infection. Any infected file started after 31 December 2007 will simply return to its host and won't do anything else.
Again, it's rather naive to believe that this sort of time-check is going to stop a virus from spreading further, because the check could be removed by a third party, and many machines probably use incorrect time anyway.
If the virus is allowed to spread, it tries to open the \\.\OpenGL device. If it's the first execution of the virus, on a clean Windows OS, the device won't be present, and the function will fail. In order to fix this issue, the malicious application drops a kernel driver in the SYSTEM32\DRIVERS directory as well as WUpdate$!.TMP in the SYSTEM32 directory. The Driver is the infection component, and the .TMP file contains a few PE files. It's not executable directly, (it starts with the 31 December 2007 date, and then you have a PE header).
The driver will later extract a backdoor application from the .TMP file and will copy it to the root of the C: drive.
Once those files have been dropped to disk, the virus uses the "undocumented" ZwSetSystemInformation native function to load the kernel driver in memory. With this function, it's possible to load a driver without creating any registry key.
The only thing the driver is going to do, is register itself as a BOOT service in order to survive reboot. I suppose this is done to register without being caught by some HIPS applications, since the service is set from kernel mode, and not from user land. Loading a driver using the ZwSetSystemInformation has some limitations, and could create stability problems if the driver didn't take special precautions. I think this is why the rootkit doesn't do anything until loaded properly as a service.
Once the driver has been loaded, the virus returns control to the host application, simply by using the return address placed on the stack by the now overwritten call to the start of the virus.
Now any infected files are going to return to the host application directly, because the driver is indeed loaded in memory. As mentioned earlier, only the driver is able to infect files, and it won't do so, until it's properly loaded by the OS.
II) Virus operation once the infected machine has been rebooted
When the computer reboots, the driver loads at BOOT time and starts its malicious work.
It starts by creating an OpenGL device and a Symbolic link and starts hooking the System Descriptor Table (SSDT).
Three entries are hooked: ZwQueryDirectoryFile, ZwEnumerateKey, and ZwCreateSection. Nothing else is done by the driver; it waits for hooked functions to be called:

At this point, if any infected application is executed, it finds the driver device, and returns to the host directly. Infected applications are used only to drop the driver if the device cannot be found, and if a driver exists already, it is overwritten.
III) ZwEnumerateKey Hook
This hook is used to hide the service installed by the driver. The technique used is very standard, and the code is probably derived from Holy Father articles:

Note: Some code was hidden for clarity.
IV) ZwQueryDirectoryFile Hook
This is the most complex part of the virus, because a lot of things happen in this hook, depending on various conditions. I won't get into too many details, but basically this hook is used to infect files.
Pretty much like old-school DOS viruses that infected your files when you were listing directories, or searching your disk (like AV virus software scanning your hard drive), this hook is responsible for all the file infections.
Whenever you scan your disk or search for files, they can be infected by the viral driver.
This hook is also responsible for dropping yet two more files to disk: autorun.exe and autorun.inf. The dropped files are simply extracted from the TMP file (placed into SYSTEM32 by infected executables in the first place). The autorun file is actually an infected file that is restarted when the computer reboots in order to survive. The file is hidden using the same hook that dropped it to disk.
Once dropped (and they will do it only once), the driver gets the local time inside the kernel driver, and does a check on the date. Because the driver is responsible for the infection, it would have been a bit silly to check only the expiration of the virus, in the infected files. If expired, nothing else happens and the original function is called.
The hook is also used for infection as I mentioned earlier, so the next step is to open files, and read 0x40 bytes from them. The driver then checks whether the file starts with the letters MZ, and in this case, will read 0xF8 more bytes and will check for the letters PE, which in the end is a check for PE32 files (32-bit Windows Executables).
The driver then checks for a special marker in the PE header. This marker is an infection mark, to tell the driver whether an application is already infected by the virus or not.

In a hex editor, you can see this marker in the headers:

The file is then totally mapped in allocated memory and ready for further infection. The virus gets the entry point offset and reads 6 bytes from it. This is the part that saves the bytes to overwrite with virus code.

Then, the virus uses standard infection code. The last sectionheader is modified, the infection mark is placed, and the first twoinstructions are assembled at host entry point, as you cansee below:

The file is then unmapped and closed. The file infection is over. There are no other checks regarding files to be infected.
Prior to calling the original Native API, the hook checks whether we are working on "autorun.exe" or "autorun.inf". If that's the case, those files are not reported, assuring furtivity of the dropped files.
V) ZwCreateSection Hook
This hook is used to monitor process execution. Any time an application is executed, the driver takes over and does some tasks.
One of them is to check the path and name of the executed file. If the file is located in SYSTEM32 and is called userinit.exe, then it triggers a special routine.
On the other hand, if the file is located in SYSTEM32 and is called smartdrv.exe, then another routine is executed.
In the latter case, if smartdrv.exe is executed, the driver cleans the registry key that was added earlier to start this very same file at Windows startup (infamous RUN key).
The original function is then called, and smartdrv.exe executed.
On the other hand, if the file executed is userinit.exe, then the driver adds a key to the registry, the same one that gets deleted by the driver when smartdrv.exe is executed.
In a nutshell, when Windows boots, userinit is executed and the driver that took over earlier during boot intercepts the execution and adds a registry key to start smartdrv.exe. The RUN key is executed AFTER the userinit executable.
Windows keeps booting and sees the newly created key, and executes smartdrv.exe. The driver intercepts execution and deletes the RUN key, so there is no trace of any key in the registry. Smart, eh?
The smartdrv.exe is created on disk once the registry keys are set, ready to be executed by Windows.
At that time, the driver also changes the AutoRun Policy key, in order to avoid autorun execution of files (remember the autorun.exe from earlier?).
The virus can also infect from there, infecting files in the userinit directory. This way, the system is already highly infected when Windows is done loading.
If the file is neither smartdrv.exe nor userinit.exe, then the original ZwCreateSection is called, and the application is executed normally.
VI) Backdoor
The file smartdrv.exe is actually a backdoor installed on the machine. It's another malcious application, and isn't of interest in this research.
It can be seen as an external application used for the payload.
VII) Conclusion
It's been a while since I had some fun with PE infectors. Even though this one wasn't polymorphic at all, and is very easy to disinfect, it still showed up as a very interesting example, combining stealth and parasiting technology, in a well-written kernel mode driver.
No crashes were experienced during the research, and the virus seems to be very stable and working, even if it uses complex and low level techniques.
Researcher: Nicolas Brulez
Post a Comment:







