Understanding Windows DKOM(Direct Kernel Object Manipulation) techniques(Part 1-EPROCESS)

Windows uses different Objects structures for different purposes like io-management, process management etc. These structures are vulnerable to different attacks which we will going to discuss in this series.

8 min read
Understanding Windows DKOM(Direct Kernel Object Manipulation) techniques(Part 1-EPROCESS)

Last months I started reading about Rootkits and how they hide themself. While learning, I came across one of the windows kernel data structure called EPROCESS. I remembered that I have worked on some exploit technique related to EPROCESS earlier also. This structure make me curious to look for other such structure used by windows for different purposes, that can be misused in any way. Hence, I decided to know more about all of them because why not? If you want to be a windows security researcher, knowing about these kernel objects are really helpful. Also not to mention most rootkits hide themself by manipulating(DKOM) these structures only.

So I start researching about these structures and how they can be manipulated in different ways. I also noticed that there are not much stuff present on internet that really explain them well. Some really good resources are there but they are scattered on different places. That makes me think to write an article series on windows kernel objects and attacks related to them.

The structures list that I have decided to write about are mention below(list may expand or reduce in future) :
EPROCESS
ETHREAD
KPCR
KINTERRUPT
KDPC
IRP
MDL

Understanding DKOM (Direct kernel object manipulation)

Initially Rootkits usually use dedicated .sys system driver for there sort of malicious work. But this raises some barriers to the practical integration of this type of threat into real applications as they can detected with little effort because they have a large structure in memory. Moreover, the installation process requires interaction with the *Windows Service Control Manager *(SCM), or alternatively uses the undocumented API ZwSetSystemInformation. Both methods can create some evidence of the threats presence or can be blocked during the installation phase. So, better technique discovered later was DKOM in which the changes done directly in memory(kernel structures).

As already mentioned, there are various objects(structures) part of Windows kernel that windows use for various purposes like process scheduling. A kernel object is a virtual placeholder for a resource that contains information about it. Everything on a computer will have an associated kernel object, like every file, every process, every port, etc has one. When a kernel object is created, it is given an index number called a handle, through which it is accessed. When a program wants to make a change (e.g. create or destroy a process), it makes a request to change the kernel object, and the kernel itself (Object Handler) decides whether to grant or deny the request. Rootkits or sometime legitimate software(like your antivirus) change these structure mostly to filter/intercepting data or sometime execute thier own code on certain condition. Changing these structure is called DKOM. It is mention in wikipedia that DKOM can be used for given purposes.

  • Hide process
  • Hide drivers
  • Hide ports
  • Elevate privilege level of threads and processes
  • Skew forensics
  • Full control of system

These are mostly all that can be seen in wild but we try to look at the some other DKOM cases also.

Why DKOM is possible

This is possible due to the fact that kernel modules and loadable drivers have direct access to the kernel memory from its privileged access. More details regarding this will available later.

Lets dive into the first Windows kernel structure EPROCESS.

Understanding EPROCESS

The Windows Kernel uses the EPROCESS structure to represent a process, and it contains all the information that the kernel needs to maintain about the process.

A high level view of all the structure present in Windows kernel used for storing process and thread related details look like this.
getprocess.b0b8afd65613

Lets look at the first structure KPRCB.

KPCR and KPRCB

The name KPRCB stands for (Kernel) Processor Control Block. It is a structure that is embedded inside a another structure called KPCR. The KPCR contains per-CPU information which is shared by the kernel and the HAL.
As you can see in the diagram above, to reach to EPROCESS structure first we have to find the address of KPRCB structure.So, lets start finding out address of KPRCB structure for process 0 (system process) in windbg.

For demonstration purpose I am using Windows 7 sp1. You can get more details using vertarget windbg command.

vertarget

Before that you may want to start kernel debugging in your local machine. For that you can refer this article.Windbg local kernel debugging.
Since KPRCB is embedded inside KPCB, first lets look at KPCR structure of process 0.
pcr

You can see here that the KPCR structure starts at address 0x82931d00.
To get more details about this structure we will use dt(display) command.

kpcr

dt will provide a more detailed output that we wanted. The colored value points at KPRCB structure. Before moving to KPRCB, if you want to read more about KPCR you can refer here KPCR explained.

So, Our KPRCB structure has address of 0x82931e20. Lets look at that object next.

kprcb

KPRCB is a huge structure(You can found more details here). But the one we care about is KTHREAD structure which is present inside ETHREAD structure(as mentioned in diagram above). Also since it is the starting entry of ETHREAD you can get ETHREAD structure details by dt nt!ETHREAD 0x8293b480.
ethread

ETHREAD and KTHREAD

The Windows Kernel uses the ETHREAD structure to represent a thread. You already must be familiar that each process has multiple threads running. For every thread in the system there is an ETHREAD structure, including threads in the System Idle Process.
Although we are more interested in KTHREAD structure which is embedded inside ETHREAD because it has the value we need to reach to EPROCESS structure. KTHREAD is stored in the ETHREAD.Tcb field. It is used by the lower layers of the kernel and contains information like thread stacks, scheduling, APCs, system calls, priority, execution times etc. So lets look at the KTHREAD structure.
kthread-1

After Scrolling little, you will find ApcState value that point to \KAPCSTATE structure.

apcstate

This KAPCSTATE is a small structure that look like this.

kapc

_KPROCESS argument points to the structure of KPROCESS which is embedded inside the EPROCESS structure, and stored in the EPROCESS.Pcb field. Also since it is the first value in EPROCESS structure KPROCESS address gives address of EPROCESS. So, now look at EPROCESS structure:

EPROCESS and KPROCESS

nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x098 ProcessLock      : _EX_PUSH_LOCK
   +0x0a0 CreateTime       : _LARGE_INTEGER
   +0x0a8 ExitTime         : _LARGE_INTEGER
   +0x0b0 RundownProtect   : _EX_RUNDOWN_REF
   +0x0b4 UniqueProcessId  : Ptr32 Void
   +0x0b8 ActiveProcessLinks : _LIST_ENTRY
   +0x0c0 ProcessQuotaUsage : [2] Uint4B
   +0x0c8 ProcessQuotaPeak : [2] Uint4B
   +0x0d0 CommitCharge     : Uint4B
   +0x0d4 QuotaBlock       : Ptr32 _EPROCESS_QUOTA_BLOCK
   +0x0d8 CpuQuotaBlock    : Ptr32 _PS_CPU_QUOTA_BLOCK
   +0x0dc PeakVirtualSize  : Uint4B
   +0x0e0 VirtualSize      : Uint4B
   +0x0e4 SessionProcessLinks : _LIST_ENTRY
   +0x0ec DebugPort        : Ptr32 Void
   +0x0f0 ExceptionPortData : Ptr32 Void
   +0x0f0 ExceptionPortValue : Uint4B
   +0x0f0 ExceptionPortState : Pos 0, 3 Bits
   +0x0f4 ObjectTable      : Ptr32 _HANDLE_TABLE
   +0x0f8 Token            : _EX_FAST_REF
   +0x0fc WorkingSetPage   : Uint4B
   +0x100 AddressCreationLock : _EX_PUSH_LOCK
   +0x104 RotateInProgress : Ptr32 _ETHREAD
   +0x108 ForkInProgress   : Ptr32 _ETHREAD
   +0x10c HardwareTrigger  : Uint4B
   +0x110 PhysicalVadRoot  : Ptr32 _MM_AVL_TABLE
   +0x114 CloneRoot        : Ptr32 Void
   +0x118 NumberOfPrivatePages : Uint4B
   +0x11c NumberOfLockedPages : Uint4B
   +0x120 Win32Process     : Ptr32 Void
   +0x124 Job              : Ptr32 _EJOB
   +0x128 SectionObject    : Ptr32 Void
   +0x12c SectionBaseAddress : Ptr32 Void
   +0x130 Cookie           : Uint4B
   +0x134 Spare8           : Uint4B
   +0x138 WorkingSetWatch  : Ptr32 _PAGEFAULT_HISTORY
   +0x13c Win32WindowStation : Ptr32 Void
   +0x140 InheritedFromUniqueProcessId : Ptr32 Void
   +0x144 LdtInformation   : Ptr32 Void
   +0x148 VdmObjects       : Ptr32 Void
   +0x14c ConsoleHostProcess : Uint4B
   +0x150 DeviceMap        : Ptr32 Void
   +0x154 EtwDataSource    : Ptr32 Void
   +0x158 FreeTebHint      : Ptr32 Void
   +0x160 PageDirectoryPte : _HARDWARE_PTE
   +0x160 Filler           : Uint8B
   +0x168 Session          : Ptr32 Void
   +0x16c ImageFileName    : [15] UChar
   +0x17b PriorityClass    : UChar
   +0x17c JobLinks         : _LIST_ENTRY
   +0x184 LockedPagesList  : Ptr32 Void
   +0x188 ThreadListHead   : _LIST_ENTRY
   +0x190 SecurityPort     : Ptr32 Void
   +0x194 PaeTop           : Ptr32 Void
   +0x198 ActiveThreads    : Uint4B
   +0x19c ImagePathHash    : Uint4B
   +0x1a0 DefaultHardErrorProcessing : Uint4B
   +0x1a4 LastThreadExitStatus : Int4B
   +0x1a8 Peb              : Ptr32 _PEB
   +0x1ac PrefetchTrace    : _EX_FAST_REF
   +0x1b0 ReadOperationCount : _LARGE_INTEGER
   +0x1b8 WriteOperationCount : _LARGE_INTEGER
   +0x1c0 OtherOperationCount : _LARGE_INTEGER
   +0x1c8 ReadTransferCount : _LARGE_INTEGER
   +0x1d0 WriteTransferCount : _LARGE_INTEGER
   +0x1d8 OtherTransferCount : _LARGE_INTEGER
   +0x1e0 CommitChargeLimit : Uint4B
   +0x1e4 CommitChargePeak : Uint4B
   +0x1e8 AweInfo          : Ptr32 Void
   +0x1ec SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f0 Vm               : _MMSUPPORT
   +0x25c MmProcessLinks   : _LIST_ENTRY
   +0x264 HighestUserAddress : Ptr32 Void
   +0x268 ModifiedPageCount : Uint4B
   +0x26c Flags2           : Uint4B
   +0x26c JobNotReallyActive : Pos 0, 1 Bit
   +0x26c AccountingFolded : Pos 1, 1 Bit
   +0x26c NewProcessReported : Pos 2, 1 Bit
   +0x26c ExitProcessReported : Pos 3, 1 Bit
   +0x26c ReportCommitChanges : Pos 4, 1 Bit
   +0x26c LastReportMemory : Pos 5, 1 Bit
   +0x26c ReportPhysicalPageChanges : Pos 6, 1 Bit
   +0x26c HandleTableRundown : Pos 7, 1 Bit
   +0x26c NeedsHandleRundown : Pos 8, 1 Bit
   +0x26c RefTraceEnabled  : Pos 9, 1 Bit
   +0x26c NumaAware        : Pos 10, 1 Bit
   +0x26c ProtectedProcess : Pos 11, 1 Bit
   +0x26c DefaultPagePriority : Pos 12, 3 Bits
   +0x26c PrimaryTokenFrozen : Pos 15, 1 Bit
   +0x26c ProcessVerifierTarget : Pos 16, 1 Bit
   +0x26c StackRandomizationDisabled : Pos 17, 1 Bit
   +0x26c AffinityPermanent : Pos 18, 1 Bit
   +0x26c AffinityUpdateEnable : Pos 19, 1 Bit
   +0x26c PropagateNode    : Pos 20, 1 Bit
   +0x26c ExplicitAffinity : Pos 21, 1 Bit
   +0x26c Spare1           : Pos 22, 1 Bit
   +0x26c ForceRelocateImages : Pos 23, 1 Bit
   +0x26c DisallowStrippedImages : Pos 24, 1 Bit
   +0x26c LowVaAccessible  : Pos 25, 1 Bit
   +0x270 Flags            : Uint4B
   +0x270 CreateReported   : Pos 0, 1 Bit
   +0x270 NoDebugInherit   : Pos 1, 1 Bit
   +0x270 ProcessExiting   : Pos 2, 1 Bit
   +0x270 ProcessDelete    : Pos 3, 1 Bit
   +0x270 Wow64SplitPages  : Pos 4, 1 Bit
   +0x270 VmDeleted        : Pos 5, 1 Bit
   +0x270 OutswapEnabled   : Pos 6, 1 Bit
   +0x270 Outswapped       : Pos 7, 1 Bit
   +0x270 ForkFailed       : Pos 8, 1 Bit
   +0x270 Wow64VaSpace4Gb  : Pos 9, 1 Bit
   +0x270 AddressSpaceInitialized : Pos 10, 2 Bits
   +0x270 SetTimerResolution : Pos 12, 1 Bit
   +0x270 BreakOnTermination : Pos 13, 1 Bit
   +0x270 DeprioritizeViews : Pos 14, 1 Bit
   +0x270 WriteWatch       : Pos 15, 1 Bit
   +0x270 ProcessInSession : Pos 16, 1 Bit
   +0x270 OverrideAddressSpace : Pos 17, 1 Bit
   +0x270 HasAddressSpace  : Pos 18, 1 Bit
   +0x270 LaunchPrefetched : Pos 19, 1 Bit
   +0x270 InjectInpageErrors : Pos 20, 1 Bit
   +0x270 VmTopDown        : Pos 21, 1 Bit
   +0x270 ImageNotifyDone  : Pos 22, 1 Bit
   +0x270 PdeUpdateNeeded  : Pos 23, 1 Bit
   +0x270 VdmAllowed       : Pos 24, 1 Bit
   +0x270 CrossSessionCreate : Pos 25, 1 Bit
   +0x270 ProcessInserted  : Pos 26, 1 Bit
   +0x270 DefaultIoPriority : Pos 27, 3 Bits
   +0x270 ProcessSelfDelete : Pos 30, 1 Bit
   +0x270 SetTimerResolutionLink : Pos 31, 1 Bit
   +0x274 ExitStatus       : Int4B
   +0x278 VadRoot          : _MM_AVL_TABLE
   +0x298 AlpcContext      : _ALPC_PROCESS_CONTEXT
   +0x2a8 TimerResolutionLink : _LIST_ENTRY
   +0x2b0 RequestedTimerResolution : Uint4B
   +0x2b4 ActiveThreadsHighWatermark : Uint4B
   +0x2b8 SmallestTimerResolution : Uint4B
   +0x2bc TimerResolutionStackRecord : Ptr32 _PO_DIAG_STACK_RECORD
   +0x2c0 SequenceNumber   : Uint8B
   +0x2c8 CreateInterruptTime : Uint8B
   +0x2d0 CreateUnbiasedInterruptTime : Uint8B

Currently we have traversal through different structures to reach to the EPROCESS. But you can easily find the starting address of EPROCESS by using process extension present in windbg. This displays similar information to the _EPROCESS data structure, and can be used for displaying all the active processes running on the system.

process

The first entry with value Image:System is our process 0. The first address 0x84863020 is the address of EPROCESS structure for the given process.

process extension will not show process that are hidden by rootkits.So, it is always better to use the manual method. More on this is discussed later.

Now we have find the address of EPROCESS block so look at the values there.

eprocess

Here you can see the first structure embedded inside eprocess is KPROCESS and some other interested fields like token, UniqueProcessid etc. The whole EPROCESS block is huge with lots of other fascinating values. You can learn more about EPROCESS from here.
Till now we have successfully reached to the EPROCESS block and also learned what this structure contains. In the next part we will look at some EPROCESS related attacks/exploitation methods used by rootkits for different purposes like Process hiding or Token Stealing. Also in future posts we will look at other kernel objects and how they been manipulated by rootkits or other softwares. Stay Tuned!