© Abhijit Mohanta, Anoop Saldanha 2020
A. Mohanta, A. SaldanhaMalware Analysis and Detection Engineeringhttps://doi.org/10.1007/978-1-4842-6193-4_11

11. Stealth and Rootkits

Abhijit Mohanta1  and Anoop Saldanha2
(1)
Independent Cybersecurity Consultant, Bhubaneswar, Odisha, India
(2)
Independent Cybersecurity Consultant, Mangalore, Karnataka, India
 

When malware executes, it makes several changes to the system, including creating new files, processes, registry keys, services, injecting code, and DLLs into other processes, initiating network connections, and so forth. They are called malware artifacts and indicators of compromise . There are chances that a victim of the malware infection might identify any of these malware artifacts like malicious files while browsing through the system or may observe a suspicious malware process while looking into the Task Manager.

The end-user victim is less likely to observe these malware artifacts unless he is a security professional or a malware analyst with malware analysis tools installed on his machine. But anti-malware products like antiviruses do always pose a threat to malware and can easily detect these complex malware artifacts, thereby detecting the presence of a malware infection.

Malware is not going to like being detected either by an end-user victim or by any anti-malware products; to prevent this, almost all malware prefers stealth so that they and their artifacts can stay hidden. To stay hidden, malware might use simple tricks like hidden files and fake process names . Malware can also use complex techniques like code injection and kernel rootkits to achieve stealth.

While most malware prefers stealth, not all need it—for example, ransomware. In this chapter, we explore various techniques that malware can use to stay hidden and avoid detection both by end users and anti-malware products.

Why Stealth?

Stealth is a crucial part of most malware’s feature arsenal. The following are some of the main reasons why malware prefers stealth.
  • Prevents end users from identifying them and their artifacts as malicious.

  • Prevents end users from detecting their presence and the presence of any of their artifacts

  • Prevents detection by anti-malware products

  • Prevents disrupting regular user/victim workflow

  • Makes malware analysis hard

  • Reveals little information during debugging

In the next set of sections, we go through various techniques, both simple and complex, that are commonly used by malware for stealth, and the various ways by which we can detect and circumvent these stealth techniques.

Simple Stealth Techniques

Malware uses various techniques to hide its artifacts. Some of these techniques, like rootkits, are complex and can even have a kernel component. There are other techniques as well, which are simple and are more commonly used by most malicious actors. Though they are simple, these techniques are very effective when it comes to deceiving victim end users. In this section, let’s go through some of these simple stealth techniques used by malware.

File Properties and Permissions

All kinds of operating systems, Linux and Windows included, have a provision to hide and protect sensitive files from the user. End users prefer to hide files and folders from being viewed to protect their sensitive personal documents. Similarly, the OS also uses this feature to protect its system files.

In Figure 11-1, Folder Options is the default selected option on the system. It hides the files and folders that have a hidden property set. In the same figure, you can see that protected OS system files are also selected to be not visible to the end users of the system. Clicking these checkboxes shows us all the hidden files and protected OS system files despite hidden attributes being set on them.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig1_HTML.jpg
Figure 11-1

Options to hide both protected OS system files and other hidden files

As an exercise, open C: in your file browser, and it should resemble the left side of Figure 11-2. Toggle these checkboxes in Folder Options from Figure 11-1 so that both hidden files and folders and protected OS system files are now visible. If you observe C: in your file browser, you can view files and folders which were previously not visible, as seen on the right-hand side of Figure 11-2.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig2_HTML.jpg
Figure 11-2

Hidden Folders/Files now visible after toggling the checkboxes in Folder Options

Malware is not far behind when it comes to using the same file-and-folder hiding features provided by the OS. They extensively use these features to drop their files and folders on the system and set the hidden attribute on them so that they are no longer visible.

Malware typically creates hidden files using two methods.
  • Use the CreateFile() Win32 API while passing a FILE_ATTRIBUTE_HIDDEN parameter to this API, which creates a file that is hidden from the start.

  • Use the CreateFile()Win32 API but without passing the FILE_ATTRIBUTE_HIDDEN parameter, which creates a non-hidden file. But the malware next calls the SetFileAttributes() Win32 API against the file but with the FILE_HIDDEN_ATTRIBUTE parameter/attribute set, which hides the file.

To catch hidden malware artifacts, you need to make sure that viewing hidden files and folders is enabled by selecting the Show hidden files, folders and drives option in Folder Options, as seen in Figure 11-1. Next, in combination with ProcMon and APIMiner tools, you can analyze the events and APIs from these malware samples that help us detect these hidden artifacts dropped by malware. Obtaining these hidden artifacts is very important since they might be secondary malware payloads and config, which might reveal the true functionality and intent of the malware infection.

Exercise 1

As an exercise, let’s take Sample-11-1 from the samples repo. Make sure to add the .exe extension to this sample. This sample creates a file named Sample-11-1-hidden-file.txt in the same folder by using the CreateFile() API, but FILE_ATTRIBUTE_HIDDEN hides the file. Let’s run this sample using the APIMiner tool using the command prompt, as seen in Figure 11-3. But before you run this sample using the command line running ProcMon as well.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig3_HTML.jpg
Figure 11-3

Command line to run Sample-11-1.exe using the APIMiner tool

Once the sample is run, you can stop ProcMon. If you check the folder where the sample is located, you see a new hidden file called Sample-11-1-hidden-file.txt that is now created, as seen in Figure 11-4. When running this sample using APIMiner.exe, sometimes the hidden file is created in the C:Users<username>AppDataLocalTempSample-11-1-hidden-file.txt path. If you can’t find this file created in the same folder as Sample-11-1.exe, check this AppData folder path, which should hold this hidden file.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig4_HTML.jpg
Figure 11-4

Hidden file created by Sample-11-1.exe

The reason why you can still see this hidden file is because we enabled the Show hidden files, folders and drives option in Folder Options.

From an analysis perspective, filter all the events in ProcMon to only show you File System Related Activity and only show you events related to the Sample-11-1.exe process. If you now search through the events, you see a CreateFile event type for the newly created hidden file, and if you further check its details by double-clicking it, you see that it has Attributes: H, where the H indicates that it is a hidden file, as seen in Figure 11-5.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig5_HTML.jpg
Figure 11-5

ProcMon shows us the hidden file created by Sample-11-1.exe

let’s look at identifying the same by using APIMiner API logs. The API logs dumped by APIMiner for our sample holds the key APIs used that can help us identify the creation of the hidden file artifacts. In Figure 11-6, the log file shows that the sample calls a variant of CreateFile API, NtCreateFile, but with the hidden attribute set which is noted from the [file_attributes] 2, where the value of 2 for [file_attributes] indicates that the attribute used by the API is FILE_ATTRIBUTE_HIDDEN. You can verify that FILE_ATTRIBUTE_HIDDEN indeed is equal to the value 2 by going through the MSDN documentation for the CreateFile API and searching for FILE_ATTRIBUTE_HIDDEN.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig6_HTML.jpg
Figure 11-6

APIMiner logs show Sample-11-1.exe using CreateFile API to create a hidden file

Exercise 2

Let’s now try Sample-11-2 the same way we ran Sample-11-1, by first starting ProcMon and then running the sample using APIMiner. Sample-11-2 works by first creating a non-hidden file in the same folder as itself called Sample-11-1-Regular-File-To-Hidden.txt by using CreateFile API but then changes this file into being hidden by calling the SetFileAttributes API. Compared to Sample-11-1, this difference in the technique used is seen in both ProcMon and the APIMiner logs. In some cases, when running this sample using APIMiner.exe, the file is created in the path C:Users<username>AppDataLocalTempSample-11-1-Regular-File-To-Hidden.txt. If you can’t find this file created in the same folder as Sample-11-1.exe, check this AppData folder path, which should hold this file.

In the ProcMon logs seen in Figure 11-7, the Sample-11-2.exe creates the file but not as a hidden file. But then we notice another event called SetBasicInformationFile, whose details for the same file shows FileAttributes: HN, where the letter H indicates that it is changing the file attribute to now make it hidden.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig7_HTML.jpg
Figure 11-7

ProcMon shows us the Sample-11-2.exe creating a file and then making it hidden

Going through the APIMiner logs in Figure 11-8 shows us that the sample calls SetFileAttributes API with [file_attributes] 2, where the value of 2 for [file_attributes] indicates that it is FILE_ATTRIBUTE_HIDDEN.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig8_HTML.jpg
Figure 11-8

APIMiner logs show Sample-11-2 using SetFileAttributes API to make a file hidden

Thumbnail Faking

When viewed using a file browser, files on your system have a default icon associated with them, as seen in Figure 11-9, where we have a Microsoft Word file and a Microsoft Excel sheet.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig9_HTML.jpg
Figure 11-9

Default icons for files shown to us by the system that helps us identify files

these icons help us identify the type of file. But we can take any file and force change the icon/thumbnail that is shown for the file. For example, you can take an executable PE file .exe and attach a Microsoft Word icon/thumbnail to it.

As an example, have a look at this malware file in Figure 11-10, which though is a PE executable .exe file, still shows an icon/thumbnail that of a Microsoft Word document, with the idea to fool the user into thinking it is a Microsoft Word file and open it. Unless you have extension viewing enabled in Folder Options, as explained in Chapter 2, you wouldn’t know it is an .exe file masquerading as some other file type. As an analyst, such image faking is a telltale sign that the sample is suspicious.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig10_HTML.jpg
Figure 11-10

Malware file faking the icon attached to its .exe file to fool users

If you analyze the sample using CFF Explorer and observe its resource editor, you can see that the attacker attached the Microsoft Word icon thumbnail as a resource that is used by the system to display the file’s thumbnail (see Figure 11-11).
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig11_HTML.jpg
Figure 11-11

The resource section of an executable holds the thumbnails

Also, take a look at the “Thumbnail Faking” section in Chapter 3 and Figure 3-11, which also explains the technique used by malware.

Filename Faking and Extension Faking

Email carrying malware relies heavily on social engineering to fool users into clicking malware attachments. One such mechanism uses filename faking by using fake user attractive filenames that are aimed to deceive the user into thinking it is benign and click it. Malware authors and malware botnets send spam mail, and in some cases, even targeted emails with attachments that use names that look like invoices, salary slips, or any other important documents. For example, the names can look like January_salary.pdf.exe or Invoice.doc.exe. These attachments are named in a way to manipulate a user into downloading and clicking to open them.

These filenames are also known to use extension faking wherein they use fake extensions as a part of the filenames, also explained in Chapter 3 (see Figure 3-10). When Extension Hiding is enabled in Folder Options, the real extension is hidden, and these files now appear as January_salary.pdf and Invoice.doc, with the real file extension .exe now being hidden, giving the user the impression that these are .pdf and .doc files.

As an analyst, we must disable extension hiding on your analysis systems and watch out for malware samples that use such tricks to fool users. If you are part of a SOC (security operations center), it is very important to get the full context of a malware sample, including information on the email and other delivery mechanisms by which the malware infection occurred. Having access to the full context helps you see the actual email attachment filename, email message, and so forth that can help you conclude more easily if the sample is malicious or benign.

Stealing System File Names

The Windows system has many of its native system files and programs, for example, svchost.exe, notepad.exe, explorer.exe, calc.exe, and so forth. Malware is known to name their malware files after these OS system files and start a process out of it, to deceive the user into thinking that these malware files/processes are the OS system files/processes.

But it is important to remember that the OS does not allow two files with the same name in the same directory. So, the malware with the same name as an OS system program is dropped into a different folder and not the OS system folder that holds these OS programs.

While analyzing malware filenames and processes using Process Hacker, it is important to verify the folder path of the file or the image path of the process. If you notice a file or a process with a name that resembles an OS system program, but the path is not the OS System path containing these OS system programs like C:windowssystem32, it very likely indicates that the process is malicious and warrants further inspection.

The Psycholinguistic Technique

Can you understand the following sentence? The vheclie epxledod. Two of the words are misspelled, but you can probably still figure out the meaning of the words. This is how human beings read most of the words or sentences, regardless of whether there are spelling mistakes or not. With small, subtle spelling mistakes, we understand without even noticing the spelling mistake. Psycholinguistic is the science of how the human mind reads and understands text and speech.

Malware authors misuse this knowledge of psycholinguistics quite often. As analysts, you come across various malware files created on the system with names like sv0host.exe, scvhost.exe, scchost.exe, and so forth. The malware author has intentionally misspelled it with an intention that the user misreads it as the well-known benign OS program svchost.exe.

As an exercise, check out Sample-11-3. Add the .exe extension suffix to this file. Run this sample as an administrator by right-clicking the sample and selecting Run as Administrator. This sample copies itself into the OS system folder C:WindowsSystem32 as svohost.exe and runs it from there, as you can see in Figure 11-12. The svohost.exe name can fool the user into believing that it is the OS system program svchost.exe. The path of the folder holding this malicious file C:WindowsSystem32 can even fool experienced analysts into thinking that this is a clean OS system process.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig12_HTML.jpg
Figure 11-12

Sample-11-3 running a copy of itself under the name svohost.exe to fool the user

Hiding Process Window

All kinds of applications on Windows have a window. Even if you create a command-line application and execute it, a console window opens in the application, as you have seen earlier while running our samples from the repo, where the console window is the minimal graphical interface. Most malware is console-based applications that have a noninteractive GUI, but when run, have a console window.

Malware doesn’t want the user to see their console window when run. Malware achieves this by finding its console window on startup and hiding it. They do so by using two APIs, as shown in Listing 11-1. The first API, FindWindowA(), finds the window of the current process’s open console window, and the second call to ShowWindow() with the argument of 0 or NULL, requests the system to hide the window. Do note that though the console window is now hidden, the process is still running and is visible in the Task Manager or Process Hacker.
HWND consoleWindow = FindWindowA("ConsoleWindowClass", NULL);
ShowWindow(consoleWindow, 0);
Listing 11-1

APIs Used to Find the Console Window of the Current Process and Hide It

As an example, check out Sample-11-4. Add the .exe file extension and run it by double-clicking it. This process is visible in Process Hacker, as seen in Figure 11-13, but it doesn’t have a console window.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig13_HTML.jpg
Figure 11-13

Sample-11-4 running as seen in Process Hacker, but without a console window

Code Injection

The malware does not need complex engineering coding techniques for any of the simple stealth techniques we mentioned in the previous sections. But their demerits are that they can easily be identified by anti-malware software. Malware authors can opt for other more complex stealth techniques like code injection and rootkits.

Code injection is a malware staple used by most of them out there for various reasons, one of them mainly being stealth. If you go back to Figure 10-2) in Chapter 10, we explain how malware use code injection as a stealth technique. What better way to hide oneself than inside another running a clean system process. Process hollowing takes it one step further by hollowing out clean system processes, injecting themselves into it, and running out of the hollowed system processes, thereby hiding under the fake name and properties of these system processes.

Code injection can also create rootkits that use hooks to hide and protect their malicious artifacts. Creating a rootkit requires much more complex programming techniques and in-depth knowledge of OS internals compared to what we saw till now. In the next section, let’s get our hands dirty with hands-on samples that explain well-known rootkit techniques used by malware on Windows.

Rootkits

Rootkits are advanced stealth techniques used by malware, often mistaken as a type of malware, which it isn’t. A rootkit is a feature or functionality or technology used by malware to hide and protect its actual payloads, executables, binaries, files, and any other artifacts created by the malware on the victim’s machine.

A rootkit is created both in user mode and kernel mode. But what are the differences between these two? While user-mode rootkits mostly depend on creating API hooks in user mode processes by injecting code into these processes, kernel rootkits require a kernel module/driver to be installed into the kernel.

User-mode rootkits are specific to a process into which the rootkit code is injected into, while kernel-mode rootkits are global. For example, if a user-mode rootkit is injected into the Task Manager to hide the malware processes that work great since you won’t find the malware processes if you are looking at the Task Manager. But you can still view the malware processes via other tools like Process Hacker and Process Explorer since the rootkit has not been injected into them. The application of the user-mode rootkit extends only to the process it has been injected into. For it to be truly effective, the user-mode rootkit code has to be injected into every user-mode process that is connected to the stealth you are trying to achieve.

On the other hand, kernel-mode rootkits work using kernel-mode drivers installed by the rootkit. They affect all the tools and processes running on the system since the kernel is a layer used by all the processes on the system. But rootkit-ing into the kernel may not be that easy. It is a tedious job to create any kind of kernel code as it needs accurate programming code since it might otherwise crash the system.

User Mode Rootkits

In the previous chapter, you learned about code injection and API Hooking. User-mode rootkits work by using both essentially, where they inject their rootkit code into other processes running on the system and hook Win32 APIs to manipulate the results of these APIs that are returned to the caller.

For example, Win32 consists of many APIs that enumerates various system states. The Task Manager that we use to view the list of processes running on the system calls the NtQuerySystemInformation Win32 API, which returns a list of processes running on the system. Malware that wants to hide its processes injects its rootkit code into processes like Task Manager, Process Hacker, and Process Explorer, and hooks the NtQuerySystemInformation API. When these tools call this API, the rootkit code intercepts the API call and manipulates the list of processes by removing its malware processes from the results and returning the modified results to the caller of the API, thereby hiding its malware processes.

Malware wants to hide the presence of its files on the system. The file browser that we use to browse files on the system internally calls APIs like NtQueryDirectoryFile, FindFirstFileA, and FindNextFileA to obtain the list of files and folders. Like the earlier process hiding rootkit, file hiding malware works by injecting code into the file browser represented by the process explorer.exe and hooking these APIs. When the file browser finally calls these APIs, the rootkit code intercepts them and manipulate the results by removing the names of any malware files and folders from being returned to the caller of the API. As a result, the rootkit can mislead the caller of the API, which in this case, is the file browser into showing the user that no malware files/folder exist on the disk.

Let’s look at Sample-11-5-rootkit and Sample-11-6-malware. Add the .exe suffix to both samples. Run Sample-11-6-malware.exe. Open Task Manager and Process Hacker and hold them side by side. Both show Sample-11-6-malware.exe as a process, as seen in Figure 11-14.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig14_HTML.jpg
Figure 11-14

Sample-11-6-malware.exe running shown by Task Manager and Process Hacker

Keep Task Manager, and Process Hacker running, and don’t kill the Sample-11-6-malware.exe process yet. Run Sample-11-5-rootkit.exe, and then go back to Task Manager and Process Hacker to double-check if you can see the Sample-11-6-malware.exe process anymore. Process Hacker continues to show Sample-11-6-malware.exe as a process running on the system, but you can no longer see it in Task Manager, as seen in Figure 11-15.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig15_HTML.jpg
Figure 11-15

Sample-11-6-malware.exe no longer visible in Task Manager because of rootkit

This is because, when you ran Sample-11-5-rootkit.exe, it searched for the taskmgr.exe process, which is the process for Task Manager, injected its rootkit code into it and hooked its NtQuerySystemInformation API. The hook inserted to intercept this API manipulates the list of process names returned by this API and removes any process names from this list if it contains the word malware. So next time when the Task Manager called this API, this rootkit code intercepted this API and removed from the list of processes the process name Sample-11-6-malware.exe and returned this modified list of process names to the Task Manager, thereby hiding the presence of this process.

At this point, if you have still not killed the Task Manager after you ran Sample-11-5-rootkit.exe, run Ring3 API Hook Scanner, which tells you if any API has been hooked. As you can see in Figure 11-16, it reports that the NtQuerySystemInformation API in Task Manager’s process taskmgr.exe has been hooked.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig16_HTML.jpg
Figure 11-16

Ring3 Scanner shows NtQuerySystemInformation in taskmgr as hooked

The following lists the various APIs that are mainly hooked by various user-mode rootkits for stealth.

These are APIs that are usually hooked by process hiding rootkits.
  • NtQuerySystemInformation

  • CreateToolhelp32Snapshot

  • OpenProcess

  • Process32First

  • Process32Next

These are APIs that are usually hooked by file and folder hiding rootkits.
  • NtCreateFile

  • NtQueryDirectoryFile

  • NtDeleteFile

  • FindFirstFile

  • FindNextFile

you can catch a user-mode rootkit via API logs from APIMiner or any other sandbox or API logger. But do note that a malware that uses a rootkit has multiple stages. You have the actual main malware, which first injects the rootkit code into the target process like taskmgr.exe or explorer.exe. And after the injection of rootkit code into the target process, the rootkit code now runs within the target process hooks the APIs.

So, when you use API loggers like APIMiner to analyze such malware samples, you get multiple log files, including the following.
  • One log file is for the main malware (and its children) that does the code injection for the rootkit code into the target process. When analyzing such samples in the API logs, search for code injection-related APIs. The APIs for code injection are mentioned in Chapter 10.

  • The other log files are for the target process where the rootkit code is injected and hooks the APIs. Some of these APIs were listed earlier.

If you see code injection-related APIs calls and either API hooks or API logs for any of the APIs that are likely to be hooked by rootkits, you have an indicator that you are possibly dealing with a user-mode rootkit.

Kernel Mode Rootkits

In kernel-mode rootkits, it involves a kernel component like a kernel-module/driver to provide the rootkit functionality. One way that a kernel-mode rootkit is implemented is via hooks for kernel APIs/functions, very similar to the API hooks placed by user-mode rootkits. But either way, it needs a kernel module/driver to implement the rootkit functionality.

But a malware writer needs to have in-depth knowledge about the kernel to create kernel rootkits. With user-mode rootkits, injecting faulty rootkit code at most can crash the process. But a faulty code injected into the kernel can crash the whole OS. A kernel-mode rootkit written for one version of Windows may not work on other versions because of the differences in the structures and the kernel features across variants of the OS. Writing these kernel-mode rootkits gets even more cumbersome from a deployment and testing perspective for the attacker.

Malware with kernel-mode components used to be common; Stuxnet, TDSS, ZeroAccess, Sality, and Necurs are some of the popular malware families that use them. To counter it, Windows introduced some protection features, like driver signing and patch guard. But it’s a cat-and-mouse game, and malware attackers find ways around these protection techniques.

In the next set of sections, let’s get a basic understanding of some rootkit concepts related to kernel modules, drivers, and SSDT. Let’s explore how kernel-mode malware work internally and play around with some hands-on kernel-mode rootkits, and learn techniques to identify their presence while analyzing such malware samples.

Request Flow from User to Kernel

In the previous chapter, we have seen that a user-mode application calls the code in the kernel to perform low-level operations, and this happens using a system call, or syscall, as illustrated in Figure 11-17. We briefly explained this in Chapter 10.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig17_HTML.jpg
Figure 11-17

The flow of an API call in user space to the kernel code via a syscall

An API call made from a user application is passed on to the kernel through kernel32.dll and NTDLL.dll. The APIs in NTDLL.dll use syscalls to pass on these API requests to the kernel. On the kernel side, there are corresponding functions that handle the request coming in from these user mode syscalls.

Which services (different from services in the user space) in the kernel handle these syscalls? The kernel holds a table called the SSDT (system service descriptor table) that holds a list of pointers to these kernel services (functions) that handle incoming syscalls from the user space. So, when a syscall comes in, the corresponding kernel service (function) is picked up from the SSDT and invoked to handle the syscall. The invoked kernel service (function) can now carry out the required activity to process the request, which might also involve calling another device driver using IRP packets. For example, a file operation request from the user space gets finally passed to a file system driver, while a network operation request is passed on to the network driver.

Injecting Code into Kernel Space

In kernel mode, there is no concept of a process, so the entire kernel code is one big virtual address space that is shared by the kernel, including the kernel modules and drivers. But how do we inject our code into the kernel? For this, we create what is called a kernel module, using the driver development kit (DDK) or the Windows driver kit (WDK) from Microsoft, which are nothing but frameworks and helper modules and utilities that can help you create kernel modules.

Most kernel modules have a .sys file extension, and it is either an executable file format type or even a DLL. As an example, have a look at the folder C:WindowsSystem32drivers and you note a lot of files with the .sys extension which are all drivers which are all kernel modules. If you open any of the .sys files using the CFF Explorer tool and check Optional Header ➤ Subsystem; it holds a value of Native as seen in Figure 11-18.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig18_HTML.jpg
Figure 11-18

A kernel driver holds a value of native for Subsystem property in Optional Header

Viewing Loaded Kernel Modules and Drivers

DriverView (which we installed in Chapter 2) is a useful tool for viewing all the loaded kernel modules on Windows. Figure 11-19 shows the output of DriverView on my system. You can run it as well to view the kernel modules loaded in your system.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig19_HTML.jpg
Figure 11-19

DriverView tool to view all the kernel modules loaded on the system

The tool displays a lot of columns by default, but we have shrunk the display only to five fields. You can identify the kernel driver by looking into the address of the module. By default, the address of a kernel module should lie above the memory address 0x7FFFFFFF for a 32-bit version of Windows. ntkrnlpa.exe (often named as ntoskrnl.exe) is the kernel image and is one of the most important kernel modules responsible for various system functions like hardware abstraction and memory management. It holds the SSDT table that we spoke about earlier, and we cover it in more detail later. It starts at 0x82A13000 and ends at 0x82E25000. Do note that the address might vary on your system. You can also obtain the path of the kernel module file on disk via its properties, which shows it as C:Windowssystem32 tkrnlpa.exe.

Note

A kernel executable can have different names: NTOSKRNL.EXE, NTKRNLPA.EXE, NTKRNLMP.EXE, NTKRPAMP.EXE.

SSDT and How to View It

An incoming syscall from the user space is handled by kernel functions located in the SSDT (system service descriptor table). These kernel functions that handle these syscalls are called services (not to be confused with the Windows services in the user space you read about in Chapter 5). Let’s call them service functions to avoid any confusion.

Many service functions are defined and held in the kernel, and each of them is defined according to function; they provide to serve various kinds of user-space requests. For example, some of them are for creating and deleting files, creating, modifying, and deleting registry entries, allocating memory, and so forth.

Note

Do not confuse the kernel services with user space Windows services, which are nothing but managed processes in the background. These kernel services are just kernel functions, very similar to how you have APIs in DLLs in user space, where the kernel is like one large DLL, and the kernel services are the APIs it provides.

The SSDT is nothing but a table that contains pointers to these service functions. Each service function pointer has a corresponding index in the SSDT. The pointers in the SSDT point to the memory locations in the kernel code where the service functions reside. The service functions are defined in ntoskrnel.exe(ntkrnlpa.exe) and win32k.ksys kernel modules.

The NovirusThanks SSDT View tool that we installed in Chapter 2 views the contents of the SSDT, as seen in Figure 11-20.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig20_HTML.jpg
Figure 11-20

SSDT View tool that can view the service functions in SSDT

As you can see, the leftmost column displays the index of the service function in the table; the second column displays its name; the third displays the address; and the fourth column shows where the module resides. Look at the entry for the NtDeleteFile service function with index 102. This function is located at 0x2BA66AD in the ntkrnlpa kernel module. You can verify the address range of the ntkrnlpa kernel module using the Driver View tool from Figure 11-20.

The syscall from the user space uses the index value to transmit the request to the kernel mode and thereby invoke the correct service function in the SSDT, as illustrated in Figure 11-21.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig21_HTML.jpg
Figure 11-21

syscall uses the index of a service function in SSDT to invoke it in the kernel

Do note that many of these service functions in the SSDT have a corresponding API in the user space Win32 DLL NTDLL.dll with the same name. A NtDeleteFile in user-space Win32 DLL NTDLL.DLL has a NtDeleteFile in the kernel as a service function whose function pointer is in the SSDT.

Drivers and IRP

A driver is a kernel module that is separated into three broad categories: function drivers, bus drivers, and filter drivers. The drivers that directly talk to the device they are managing are called function drivers . Filter drivers don’t directly interface with the physical device but sit slightly higher in the device driver path, and their main task is to filter the requests coming into the drivers below it and to the actual device. Bus drivers drive the individual physical buses that the devices are plugged into. These three driver categories have subcategories.

To communicate with the device drivers and the device, the kernel provides a subsystem called the I/O manager, which generates and dispatches what are called I/O request packets (IRP). An IRP is a data structure that has information on the I/O operation needed from the device driver/device, with some of the common request operations being write requests, read requests, control requests, and so forth. When starting up, device drivers can register themselves to handle these I/O request types thereby giving them the ability to service these I/O operation requests.

A device on the system may have multiple drivers associated with them. When the I/O manager creates an IRP and sends it to the device, it flows through all the drivers associated with the device in a sequential manager. This is illustrated in Figure 11-22. A device driver if it has registered to handle the IRP type processes it. A driver can also filter any IRPs headed to the device and even filter/alter them out so that they are no longer passed to the subsequent drivers. An example of such a category of drivers that filter IRP packets are filter drivers.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig22_HTML.jpg
Figure 11-22

Flow of an IRP across device drivers to the device

How to Insert Kernel Modules and Driver?

Kernel modules and drivers are loaded into the kernel as a service (Windows services). We have gone through the various ways to create a Windows service in Chapter 5. As a malware analyst, keep in mind all the various techniques to identify the registration of services. It comes in handy when you are analyzing a sample that registers a rootkit kernel module into the kernel via a service.

To summarize the steps to programmatically register a service using Win32 APIs.
  1. 1.

    The kernel module is dropped by malware into the disk using the CreateFile API.

     
  2. 2.

    OpenSCManager opens the service manager to register a new service.

     
  3. 3.

    CreateServiceA registers a new service by supplying the kernel module file that it dropped into the disk in step 1.

     
  4. 4.

    StartService starts the service created in step 1, which loads the kernel module.

     

You most likely see this sequence of APIs in malware that is trying to install a kernel module rootkit . You see this hands-on when we play with some exercises later.

As an analyst, you’ve got to make sure you can differentiate between the sample trying to register and create a regular Windows service and another case where it is trying to create a service that intends to load a kernel module or rootkit. To differentiate between the two, you can use the Subsystem value of the executable file that is registered as a service in the CreateService API from step 3.

A few other APIs can also load a kernel module, which can be used by malware. Two of them are ZWSetSystemInformation and ZwLoadDriver. With the help of the APIMiner tool that logs various APIs used by these rootkit malware samples, we can identify kernel-based malware and rootkits if we see any of them using these APIs.

SSDT Rootkits and SSDT Table Hooking

SSDT rootkits work by hooking the SSDT, very similar to how user-space rootkits use API hooking, as we saw earlier. To hook the SSDT, you need to locate the address of the SSDT in the kernel. To do so, you need to create a driver that can first locate the SSDT, and that can then traverse the service entries in SSDT and then hook it.

To locate the SSDT, Windows has a structure called _KeServiceDescriptorTable, which has a pointer that points to the SSDT. Listing 11-2 shows the definition of the structure.
typedef struct _KSERVICE_DESCRIPTOR_TABLE {
    PULONG ServiceTableBase;
    PULONG ServiceCounterTableBase;
    ULONG NumberOfServices;
    PUCHAR ParamTableBase;
}
Listing 11-2

Definition of _KeServiceDescriptorTable Struct That Points to the Location of SSDT

The structure contains the following fields.
  • ServiceTableBase points to the start of the SSDT.

  • ServiceCounterTableBase tells how many times each service is invoked.

  • NumberOfServices tells the number of services.

  • ParamTableBase is the base address of SSPT (system service parameter table). SSPT is another table that holds the number of bytes needed for the parameters of a service.

A malware kernel module rootkit once inserted into the kernel first locates _KeServiceDescriptorTable, from which it can find the base address of the SSDT using the ServiceTableBase field. With the SSDT location known, the malware can either replace these service function pointers in the SSDT that it intends to hook/intercept, using a technique similar to IAT hooking (refer to IAT hooking in Chapter 10). The other option is to use inline hooking by going to the actual kernel service function that the malware wants to hook by obtaining the address of the said service function from the SSDT. Then replace the initial bytes of the service function code to redirect to the malicious malware code in its kernel module rootkit (the same as inline hooking in user space also explained in Chapter 10). Both techniques are explained in Figure 11-23.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig23_HTML.jpg
Figure 11-23

SSDT rootkits are implemented by using either IAT hooking or inline hooking

Creating SSDT hooks on 32-bit machines was easy because the kernel exported _KeServiceDescriptorTable, but Windows stopped it with 64 bits. Hence with 64-bit Windows, SSDT hooking was harder but not impossible.

Malware can use SSDT hooks to implement rootkits, and it can be used by them to protect and hide their files, processes, registries, and so forth. The advantage of using kernel-based SSDT rootkits is that it applies globally to all processes on the system, unlike user-mode rootkits, where the rootkit must be inserted into every process that you want to rootkit.

SSDT Rootkit Exercise
As an exercise, let’s look at Sample-11-7-ssdt-rootkit. Add the .exe file extension suffix to it. The sample needs to be run as an admin for the kernel module to be inserted into the kernel. To do that right-click the sample and click Run as Administrator. The sample creates a C:hidden folder. Try to access this folder, and it throws an error, as seen in Figure 11-24.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig24_HTML.jpg
Figure 11-24

SSDT rootkit from our exercise Sample-11-7-ssdt-rootkit

As analysts, how can we identify and detect an SSDT rootkit? We go back to the APIs that we spoke about earlier that are used by malware to insert kernel modules. These are the service creation APIs. Let’s open a command prompt as an administrator and run the same sample using the APIMiner tool, as seen in Figure 11-25.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig25_HTML.jpg
Figure 11-25

APIMiner running the SSDT rootkit from our exercise Sample-11-7-ssdt-rootkit

Inspecting the API logs from APIMiner point to the same API sequence we spoke about earlier: OpenSCManager, CreateService, and StartService, as seen in Figure 11-26.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig26_HTML.jpg
Figure 11-26

API logs for Sample-11-7-ssdt-rootkit show APIs used for registering service

This only tells you half the picture that the sample is trying to register a service. But it is a Windows service. What proves that we have a rootkit kernel module being inserted by this sample? If you further check the CreateService arguments in your APIMiner API log file, it provides the path of the kernel module C:hidden ootkit.sys. If you try to access this folder, you are denied permission, as you saw in Figure 11-25, which is a telltale sign that we have a file rootkit.

We can further confirm this by running the GMER tool, which clearly shows us that we have an SSDT rootkit in place, as seen in Figure 11-27.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig27_HTML.jpg
Figure 11-27

GMER identifies that we have an SSDT rootkit installed on the system

Since GMER identifies it as an SSDT rootkit, let’s now run the SSDT View tool, which double confirms if any of the service functions in the SSDT are hooked, and if hooked which ones. As you can see in Figure 11-28, SSDT View shows us that the NtCreateFile service function has been hooked, which in combination with our failure to access C:hidden ootkit.sys indicates that we have a File Hiding rootkit installed by our sample. We can also infer that it is file hiding rootkit from the name/type of SSDT service function that has been hooked, which in this case is NtCreateFile/ZwCreateFile.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig28_HTML.jpg
Figure 11-28

SSDT View identifies the hook placed by our sample for hiding files

As an analyst, it is important to know the various service functions that are targeted by malware to hook to implement rootkits. These are service functions that are hooked in SSDT by implementing rootkits.
  • ZwOpenFile

  • NtCreateFile

  • ZwQueryDirectoryFile

  • ZwTerminateProcess

  • ZwOpenProcess

  • ZwQuerySystemInformation

  • ZwQueryValueKey

  • ZwEnumerateValueKey

  • ZwEnumerateKey

  • ZwSetValueKey

  • ZwCreateKey

DKOM Rootkits and Kernel Object Manipulation

Another way to implement rootkits is by manipulating the list that is returned by the enumeration APIs like the ones that enumerate files, registry, and processes. Some of these lists are created by referring to some of the data structures that are available in the kernel called kernel objects. These rootkits are called direct kernel object manipulation (DKOM).

Before looking into the kernel-mode DKOM rootkits, let’s look at how the object manipulation happens at a very high level.

Figure 11-29 represents a list of processes in the kernel as an object, which is referred throughout the system to display the list of processes. The Process_Mal process object in the middle of the list is a malware process that the malware wants to hide in the Task Manager and any other process viewing tool. To do so and implement the process hiding rootkit, the malware kernel module unlinks that malware process from the list, as seen in Figure 11-30, thereby making all the process viewing tools on the system blind to the presence of this malicious process.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig29_HTML.jpg
Figure 11-29

A list of processes, including a malware process represented in the kernel

../images/491809_1_En_11_Chapter/491809_1_En_11_Fig30_HTML.jpg
Figure 11-30

The process hiding rootkit unlinks the malware process from the list, thereby hiding the process

Process Hiding Using DKOM In-Depth

We talked about how kernel object manipulation works at a high level to hide processes running on the system. Let’s explore the particulars of how DKOM can hide a process.

In the kernel, each process is represented by an object called EPROCESS. The EPROCESS data structure has multiple fields, including Pcb, which points to the process environment block. A partial view of the various fields of this data structure is seen in Figure 11-31.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig31_HTML.jpg
Figure 11-31

The EPROCESS data structure used to represent the process in the kernel

The structure and its fields and offsets can be explored using kernel debuggers for Windows like Windbg. The EPROCESS objects for all the processes running on the system are connected using a structure called ActiveProcessLinks(AP_LINK in Figure 11-32), which further has FLINK and BLINK subfields that contain pointers that point to other EPROCESSes. A FLINK field in an EPROCESS points to the FLINK of the next process, while the BLINK field points to the FLINK in a previous EPROCESS. This results in a doubly-linked list of EPROCESS structures. This is illustrated in Figure 11-32.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig32_HTML.jpg
Figure 11-32

The doubly-linked list of EPROCESS structures of all the processes

Figure 11-32 shows how EPROCESS of PROCESS_1 and PROCESS_MAL and PROCESS_3 are connected into a doubly-linked list. A user-mode API like NtQuerySystemInformation, which can retrieve a list of processes in the Task Manager or any other tools, refers to this doubly linked list. The entire list is traversed programmatically using FLINK and BLINK pointers. A FLINK or BLINK can reach from one EPROCESS to another, and the rest of the fields can be accessed as an offset from these structures from the pointers. A malware rootkit can tamper this doubly linked list to hide its processes.

To hide a malicious process, the FLINK and BLINK pointers are disconnected, and then the EPROCESS before and after the malicious process is connected by manipulating their pointers. Figure 11-33 explains how this delinking happens.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig33_HTML.jpg
Figure 11-33

DKOM manipulation where we have manipulated the doubly linked list to delink the EPROCESS structure of a malicious process we want to hide

DKOM Rootkit Exercise
Let’s run Sample-11-8-dkom-rootkit. Make sure that you add the extension .exe. Let’s run it directly using the APIMiner tool so that you also learn how to identify and detect malware samples that use process hiding rootkits. To do this, open the command prompt as an administrator and run Sample-11-8-dkom-rootkit.exe using APIMiner, as shown in Figure 11-34.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig34_HTML.jpg
Figure 11-34

APIMiner running the DKOM rootkit from our exercise Sample-11-8-dkom-rootkit

This sample creates a new process with PID 3964 and then inserts a kernel module that manipulates DKOM to hide this process from the Task Manager. Let’s see how we can analyze this sample.

Running it as a part of APIMIner, there are two API log files generated by our tool, as seen in Figure 11-35.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig35_HTML.jpg
Figure 11-35

APIMiner API log files for Sample-11-8-dkcom-rootkit

APIMiner generates API log files with filenames containing the PIDs of the processes it creates API logs for, which in this case is PID 3964. But if you check Process Hacker as seen in Figure 11-36, you won’t see a process by this PID. This is the first sign that the process is hidden by a rootkit.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig36_HTML.jpg
Figure 11-36

No process with PID 3964 found indicating it is most likely hidden by a rootkit

Further inspecting the logs shows us the same sequence of APIs that register a service, as seen in Figure 11-37. But if you further inspect the arguments for CreateService API from the log file, you obtain the path of the file that is being registered as a service, which for us is C:hiddendkom.sys. Inspecting this file using CFF Explorer, you notice that it has the Native Subsystem in Optional Header, indicating that it is a kernel module. This proves that this service creation is to insert a kernel module by the sample.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig37_HTML.jpg
Figure 11-37

API sequence indicates the sample is creating and starting a service.

To further double confirm that the kernel module inserted is a rootkit, you can run GMER. Either way, if you see a service created by the sample, it probably also makes sense to quickly check with a tool like GMER and Ring3 API Hook Scanner to see if it detects any kind of hooks both in user-space and kernel. Running GMER shows us that we have a process hiding rootkit installed and the PID of the process it is trying to hide, as seen in Figure 11-38.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig38_HTML.jpg
Figure 11-38

GMER shows we have a kernel process hiding rootkit installed by Sample-11-8

Rootkits Using IRP Filtering or Filter Driver

IRP packets flow from the I/O manager across device drivers so that drivers can carry out operations on the device based on the action requested by the IRP packet. Filter drivers are a category of drivers that are created to filter IRP packets. Filter drivers can also contain logic to carry out other bookkeeping related operations based on the IRP action requested.

Filter drivers give one the flexibility to implement various kinds of middleware. A good example is encryption software. Take the example of a file system driver that processes IRP and ultimately talks to the disk device to carry out various operations like creating, deleting, modifying files, and so forth. This is illustrated in Figure 11-39.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig39_HTML.jpg
Figure 11-39

Flow of IRP across the file system driver which then operates on the disk

But we want to implement file encryption functionality, and we can achieve this using a filter driver. A file encryption software may need to encrypt the file contents before it is written to the hard disk, and at the same time, it needs to decrypt the file contents after reading back from the hard disk and returning it to the applications asking for contents of the file. To implement this whole functionality, it can place another driver or be more appropriate a filter driver before the main file system driver, where this new driver is responsible for decrypting and encrypting the contents of the file, as illustrated in Figure 11-40.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig40_HTML.jpg
Figure 11-40

Flow of IRP across the file system driver, which then operates on the disk

The IRP packet coming from the OS now passes through this file encryption filter driver before reaching the final file system driver , which is responsible for writing to the disk. The file encryption driver is stacked on the top of the actual driver.

This functionality, while good, can also be misused, and malware can use IRP filtering by utilizing filter drivers to implement rootkits. For example, the regular flow of IRP across drivers, as seen in Figure 11-41.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig41_HTML.jpg
Figure 11-41

Flow of IRP across the driver stack for a device

To implement rootkit functionality, a malware registers a filter driver (kernel module), which sits before the other drivers in the stack, as shown in Figure 11-42.
../images/491809_1_En_11_Chapter/491809_1_En_11_Fig42_HTML.jpg
Figure 11-42

Malware filter driver sits on top of other drivers filtering IRPs as a rootkit

the malicious filter driver from the malware sees the IRP before the function driver and the other drivers and can carry out various rootkit related functionality by filtering out the IRP packets and carrying out various actions based on the IRP packet contents and actions.

Going back to the file encryption driver, malware can place a malicious driver instead of a file encryption driver, which can hide malicious files and directories and prevent the deletion of its malicious files. Even keystrokes can be logged, and ports can be hidden by inserting malicious drivers to the device drivers stack.

Other Ways of Creating Rootkits

We have covered the most prevalent rootkit techniques used by malware out there. There might be other techniques that can implement rootkits. For example, malware can use its own file system and replace the one used by the OS to hide their artifacts on disk. Whatever the rootkit technique used, the methods to detect and identify malware that uses rootkits are the same as the ones we used in this chapter. Most of the techniques involve seeing mismatches and anomalies and proving these anomalies are malicious.

Summary

Stealth is an important functional feature used by most malware. In this chapter, you learn why malware use stealth and the various simple yet effective stealth techniques used by them. We went through some more complex hiding techniques like code injection, which we covered in Chapter 10. You learned about rootkits, an advanced stealth technique used by malware, that is implemented in both the user space and the kernel space.

You now understand how user-space rootkits are implemented by making use of code injection and API hooking and learn various techniques by which we can dissect malware that uses them. We also explore how kernel-mode rootkits work internally and the various types of kernel-mode rootkits prevalent, including SSDT rootkits, DKOM rootkits, and IRP filter rootkits. Using hands-on exercises for all the stealth techniques, we now have a fundamental understanding of how to detect and identify malware that uses them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.184.89