This article is the first iteration of a series introducing several malware techniques for both persistence and propagation.
Most of these techniques were discovered and disclosed several years ago by security researchers. The aim of this approach is to build a knowledge base on these technique’s system and forensics aspects.
Along with the article a proof of concept code can be retrieved on the CERT’s Github.
The knowledge base will be continuously improved with field experience of Devoteam CERT’s analysts.
This first article will treat the following aspects of DKOM process hiding :
- Windows processes
- Hiding with Direct Kernel Object Modification
- Proof of concept
- RAM detection with Volatility
This concept, introduced at a Black Hat USA’s talk in 2004, has been (and is still) employed by several kernel rootkits such as the famous FU-rootkit, developed by Jamie Butler (author of the talk).
The Windows kernel makes use of the EPROCESS structures to handle processes.
These are opaque structures: barely documented by Microsoft and not detailed by standard programming headers.
MSDN reference:EPROCESS (Windows Driver)
They can still be analysed via kernel debugging, using KD:
The structure has 207 fields in this example (Windows 10 64 bits).
Only three of them are relevant to explain the technique:
This list contains two links: Flink and Blink.
These links are interesting because they point to two other LIST_ENTRY structures belonging to the next process (Forwardlink) and previous process (Backlink).
All processes in a Windows system refer to each other via pointers in their ActiveProcessLinks structures. They make up a double chained list used by tools such as taskmgr.exe (task manager) or some SysInternals tools (e.g. procexp.exe).
The double chained list is periodically checked to update processes display.
Hiding processes using Direct Kernel Object Modification
The DKOM technique hides a process unlinking its own ActiveProcessLinks and linking the “previous” and “next” processes directly to each other.
Getting the process (smss.exe in the example figure) out of the double chained list makes it invisible from tools relying on this list to display processes.
Unlinking a process does not affect its execution flow. The scheduler allocates computing time to threads unitarily, not to processes.
When modifying the malicious process’ ActiveProcessList, its Blink and Flink are modified to refer to their own structure. This is done to avoid any problem at the process’ exit. If Blink or Flink refers to an old or invalid memory address the kernel might raise an exception when trying to update the “neighbor” processes.
Comment on the Proof of Concept (first version)
The driver configuration initialization was hooked using WDF_DRIVER_CONFIG_INIT().
The hook searches a process whose ImageFileName field is virus.exe and hides it using the DKOM technique.
This driver is not a functional Rookit (only tries to hide a process once at installation) and is only meant as an educational example.
The code makes heavy use of hardcoded memory offsets tested on Windows 10 64 bits (up to date on January 2nd, 2017). They are used to access directly EPROCESS fields and will probably not work at all on other Windows releases.
Offsets shown above can be found in the first KD screen captures in the Windows Processes section.
The code can be easily improved, using more stable ways of accessing these fields and providing a user land control interface.
EPROCESS fields access and edition
The Windows API does not provide EPROCESS structure definition but pointers to these structures can be retrieved using API calls.
The function used in the PoC is PsGetCurrentProcess(), which returns a pointer to the current process’ EPROCESS structure. In this driver’s execution context it returns a pointer to the System process’ structure. Once an EPROCESS structure is located, a search function is called in order to go through the EPROCESS’ circular list looking for the virus.exe ImageFileName.
If the search returns an EPROCESS structure, then its ActiveProcessLinks are modified to hide it. This is achieved via in-memory manipulation of the EPROCESS structures.
Relevance and current operating system protection
The PoC generated driver has been submitted to the https://nodistribute.com/ platform to check for Antivirus awareness.
No antivirus considered the binary as harmful, which is not surprising considering the code simplicity and very low amount of system calls.
Despite its apparent stealth, the technique is not stable on all Windows releases.
A protection for Windows 64 bits called PatchGuard can detect the previously mentioned manipulations.
PatchGuard, also referred to as Kernel Patch Protection (KPP), was introduced in Windows XP 64 bits and Windows Server 2003 SP1 in 2005.
This mechanism, very lightly documented by Microsoft, checks kernel structures integrity in order to avoid patching and hooking from a kernel land driver.
KPP verifies kernel structures on a random frequency; tens of minutes can separate two checks. When an anomaly is detected a 0x109 – CRITICAL_STRUCTURE_CORRUPTION kernel error is raised, brutally stopping system’s execution.
KPP does not really block this technique’s execution then but simply shuts down the OS.
Since this technique aims to provide stealthiness, the regular display of Blue Screens disrupts its effectiveness.
The protection has only been implemented in 64 bits versions of Windows, leaving 32 bits systems vulnerable. Nowadays, most recent installations are 64 bits; hence they somewhat protect against this threat.
Even with KPP, this technique should not be ignored because:
- It can be encountered in incident response on 32 bits system.
- Attacks against PatchGuard exist from kernel mode drivers (still an active research area).
In-memory detection with Volatility
Whereas it could be tricky to detect the technique using tools live on an infected host, it is easily detected within a memory capture.
Indeed, many monitoring / system tools (e.g. SysInternals Microsoft suite) are based on the double chained list for processes enumeration.
To demonstrate this concept the PoC has been executed on a host running Windows 10 Professional version 14393.
Example with Process Explorer, VMMap, ListDlls and Handle64, executed on the PoC system
The process is invisible for several tools. However, the process is running and its system events can be caught by the Process Monitor.
In the real world rootkits can modify and hijack a great number of system functionalities, making most live detection way harder. It is recommended to investigate offline on a RAM dump with an adapted framework such as Volatility.
The previously mentioned Windows version is supported by Volatility 2.6 with the Win10x64_14393 profile.
The memory dump was realized with Winpmem, a tool distributed by the Google’s Rekall project.
In Winpmem output, the drivers names are listed and we can notice the PoC binary (here called 2017_remote_helloworld).
Once the memory capture process is completed, the investigation can start.
Volatility has several plugins to analyze running processes in a dump, a quick comparison can be realized this way:
Only psscan and psxview found our hidden process.
These plugins’ documentation helps us understand why some of them found the process and why some did not.
pslist – detects processes checking the double chained list
pstree -uses the same technique, simply displays results differently
psscan – scans memory for _POOL_HEADER structures (pools of memory pages) to identify associated processes
psxview – combination of several techniques, one by column:
- pslist as described above
- psscan as described above
- thrdproc thread scan, retrieves the _KTHREAD list used by the scheduler (which cannot be modified without disrupting the process execution) and search it for associated _EPROCESS objects.
- csrss The csrss.exe process maintains an independent list of processes which can be retrieved in its memory
Within these plugins, psxview is the quickest way to analyze running processes, it gives users a great cover of different detection techniques.
We know that the hidden process is called virus.exe and has the PID 4952, further investigation is now possible with Volatility.
The PID cannot be used directly by Volatility plugins in this “hidden” case, the process memory offset must be specified instead.
The memory offset (P stands for Physical) can be used instead of the PID for most Volatility plugins.
With this information it is possible to get many items, for example :
- Open handles to system’s resources (files, registry keys…)
- The process command line
The driver/rootkit can also be recovered from the memory dump
Direct Kernel Object Manipulation. Jamie Butler, Black Hat 2004.
The Rootkit Arsenal, Escape and Evasion in the dark Corners of the System. Bill Blunden, 2013.
FU rootkit source code, Jamie Butler.
FUTo rootkit source code, Peter Silberman.
Windows Internals, Mark Russinovich, David A. Solomon, Alex Ionescu, 2012.
Microsoft Developer Network, https://msdn.microsoft.com/