41
Reverse Engineering The Windows Kernel (2) Kent Huang

Reverse eningeering

Embed Size (px)

Citation preview

Page 1: Reverse eningeering

Reverse EngineeringThe Windows Kernel (2)

Kent Huang

Page 2: Reverse eningeering

Asynchronous and Ad-Hoc Execution

Page 3: Reverse eningeering

Introduce the Component inside Windows Kernel

1. Usage

2. Introduce the data structure

3. How it work inside Windows Kernel

4. What’s the usage in root-kit

5. Exercises

Page 4: Reverse eningeering

System Threads • Driver may create multiple threads handling

different requests from kernel or user.

• Call API PsCreateSystemThreadNTSTATUS PsCreateSystemThread( _Out_ PHANDLE ThreadHandle, _In_ ULONG DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ HANDLE ProcessHandle, _Out_opt_ PCLIENT_ID ClientId, _In_ PKSTART_ROUTINE StartRoutine, _In_opt_ PVOID StartContext );

Page 5: Reverse eningeering

System Threads

• If process handle is not NULL, thread will be created under that process.

• Someone say, if call PsCreateSystemThread in an IOCTL handler, the new thread will be in the user-mode application ???

Page 6: Reverse eningeering

Exercises

• Determine whether any of them pass a non-NULL ProcessHandle parameter. Explain the purpose of these routines. Repeat the exercise for as many functions as possible.

Page 7: Reverse eningeering

Work Items• Similar to system threads

• Except that no physical thread object

• Common driver programming pattern to queue work items inside a DPC

PIO_WORKITEM IoAllocateWorkItem( _In_ PDEVICE_OBJECT DeviceObject ); VOID IoQueueWorkItem( _In_ PIO_WORKITEM IoWorkItem, _In_ PIO_WORKITEM_ROUTINE WorkerRoutine, _In_ WORK_QUEUE_TYPE QueueType, _In_opt_ PVOID Context );

Page 8: Reverse eningeering

Structure1: kd> dt _IO_WORKITEM nt!_IO_WORKITEM +0x000 WorkItem : _WORK_QUEUE_ITEM +0x010 Routine : Ptr32 void +0x014 IoObject : Ptr32 Void +0x018 Context : Ptr32 Void +0x01c Type : Uint4B +0x020 ActivityId : _GUID 1: kd> dt _WORK_QUEUE_ITEM nt!_WORK_QUEUE_ITEM +0x000 List : _LIST_ENTRY +0x008 WorkerRoutine : Ptr32 void +0x00c Parameter : Ptr32 Void 1: kd> dt _WORK_QUEUE_TYPE TmXPFlt!_WORK_QUEUE_TYPE CriticalWorkQueue = 0n0 DelayedWorkQueue = 0n1 HyperCriticalWorkQueue = 0n2 MaximumWorkQueue = 0n3

1: kd> dt _KPRCB ParentNode nt!_KPRCB +0x338 ParentNode : Ptr32 _KNODE 1: kd> dt _KNODE nt!_KNODE +0x000 DeepIdleSet : Uint4B +0x004 SharedReadyQueueLeaders : Uint4B +0x040 ProximityId : Uint4B +0x044 NodeNumber : Uint2B … 1: kd> dt _ENODE nt!_ENODE +0x000 Ncb : _KNODE +0x0c0 ExWorkQueue : [2] _EX_WORK_QUEUE … 1: kd> dt _EX_WORK_QUEUE nt!_EX_WORK_QUEUE +0x000 WorkPriQueue : _KPRIQUEUE +0x19c WorkItemsProcessed : Uint4B +0x1a0 WorkItemsProcessedLastPass : Uint4B +0x1a4 ThreadCount : Int4B +0x1a8 TryFailed : UChar

Page 9: Reverse eningeering

kd> !thread THREAD 865b2da8 Cid 0004.003c Teb: 00000000 Win32Thread: 00000000 RUNNING on processor 0 Not impersonating DeviceMap e1004438 Owning Process 0 Image: <Unknown> Attached Process 865b5490 Image: System Wait Start TickCount 19549 Ticks: 0 Context Switch Count 901 IdealProcessor: 0 UserTime 00:00:00.000 KernelTime 00:00:01.062 Start Address nt!ExpWorkerThread (0x80534b02) Stack Init f78eb000 Current f78ead1c Base f78eb000 Limit f78e8000 Call 0 Priority 13 BasePriority 12 PriorityDecrement 0 DecrementCount 16 ChildEBP RetAddr Args to Child f78ead60 8056bcc5 86124338 00000000 8055b0fc NotYourFault!TesterWorkerItemRoutine+0x52 (FPO: [Non-Fpo]) (CONV: stdcall) [c:\users\kent_huang\perforce\pd_kent_huang\core\vsapi\pd\kent_huang\vsapi\tools\notyourfault\notyourfault\reverseengineering\workeritem.c @ 19] f78ead74 80534c02 86121548 00000000 865b2da8 nt!IopProcessWorkItem+0x13 (FPO: [Non-Fpo]) f78eadac 805c6160 86121548 00000000 00000000 nt!ExpWorkerThread+0x100 (FPO: [Non-Fpo]) f78eaddc 80541dd2 80534b02 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo]) 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

Page 10: Reverse eningeering

Reverse follow API (Win8)

• IoAllocateWorkItem

• IoInitializeWorkItem

• IoQueueWorkItem

• IopQueueWorkItemProlog

• ExQueueWorkItem

Page 11: Reverse eningeering

Asynchronous Procedure Calls

• Asynchronous I/O completion, thread suspension, and process shutdown

• Undocumented API

• Kernel Mode (PASSIVE_LEVEL , APC_LEVEL)

• User Mode (PASSIVE_LEVEL)

• Rootkits achieve this by queueing a user-mode APC to a thread in the process in which they want to inject code.

Page 12: Reverse eningeering

Structure1: kd> dt _KAPC nt!_KAPC +0x000 Type : UChar +0x001 SpareByte0 : UChar +0x002 Size : UChar +0x003 SpareByte1 : UChar +0x004 SpareLong0 : Uint4B +0x008 Thread : Ptr32 _KTHREAD +0x00c ApcListEntry : _LIST_ENTRY +0x014 KernelRoutine : Ptr32 void +0x018 RundownRoutine : Ptr32 void +0x01c NormalRoutine : Ptr32 void +0x014 Reserved : [3] Ptr32 Void +0x020 NormalContext : Ptr32 Void +0x024 SystemArgument1 : Ptr32 Void +0x028 SystemArgument2 : Ptr32 Void +0x02c ApcStateIndex : Char +0x02d ApcMode : Char +0x02e Inserted : UChar

1: kd> dt _KTHREAD ApcState nt!_KTHREAD +0x070 ApcState : _KAPC_STATE 1: kd> dt _KAPC_STATE nt!_KAPC_STATE +0x000 ApcListHead : [2] _LIST_ENTRY +0x010 Process : Ptr32 _KPROCESS +0x014 InProgressFlags : UChar +0x014 KernelApcInProgress : Pos 0, 1 Bit +0x014 SpecialApcInProgress : Pos 1, 1 Bit +0x015 KernelApcPending : UChar +0x016 UserApcPending : UChar

Page 13: Reverse eningeering

Deferred Procedure Calls

• Routines executed at DISPATCH_LEVEL

• Hardware drivers use them to process interrupts coming from the device

• Some rootkits use DPCs to synchronize access to global linked lists

Page 14: Reverse eningeering

IRQL

Page 15: Reverse eningeering

Structure1: kd> dt _KDPC nt!_KDPC +0x000 TargetInfoAsUlong : Uint4B +0x000 Type : UChar +0x001 Importance : UChar +0x002 Number : Uint2B +0x004 DpcListEntry : _SINGLE_LIST_ENTRY +0x008 ProcessorHistory : Uint4B +0x00c DeferredRoutine : Ptr32 void +0x010 DeferredContext : Ptr32 Void +0x014 SystemArgument1 : Ptr32 Void +0x018 SystemArgument2 : Ptr32 Void +0x01c DpcData : Ptr32 Void

1: kd> dt _KPRCB DpcData nt!_KPRCB +0x21e0 DpcData : [2] _KDPC_DATA 1: kd> dt _KDPC_DATA nt!_KDPC_DATA +0x000 DpcList : _KDPC_LIST +0x008 DpcLock : Uint4B +0x00c DpcQueueDepth : Int4B +0x010 DpcCount : Uint4B +0x014 ActiveDpc : Ptr32 _KDPC

138 Chapter 3 ■ The Windows Kernel

c03.indd 11:7:49:AM 01/21/2014 Page 138

KPRCB KDPC KDPC KDPC

Type Type Type

DpcData[0]

DpcData[1] DpcListEntry DpcListEntry DpcListEntry

DeferredRoutine DeferredRoutine DeferredRoutine

… … …

…… …

Figure 3-7

DpcStack is a pointer to a block of memory to be used as the DPC routine’s stack.

Windows has several mechanisms to process the DPC queue. The fi rst mecha-nism is through KiIdleLoop. While “idling,” it checks the PRCB to determine if DPCs are waiting and if so to call KiRetireDpcList to process all DPCs. This is why sometimes these two functions appear on the stack while executing a DPC. For example:

0: kd> kn # Child-SP RetAddr Call Site00 fffff800`00b9cc88 fffff800`028db5dc USBPORT!USBPORT_IsrDpc01 fffff800`00b9cc90 fffff800`028d86fa nt!KiRetireDpcList+0x1bc02 fffff800`00b9cd40 00000000`00000000 nt!KiIdleLoop+0x5a

The second mechanism occurs when the CPU is at DISPATCH_LEVEL. Consider the following stack:

0: kd> kn# Child-SP RetAddr Call Site00 fffff800`00ba2ef8 fffff800`028db5dc USBPORT!USBPORT_IsrDpc01 fffff800`00ba2f00 fffff800`028d6065 nt!KiRetireDpcList+0x1bc02 fffff800`00ba2fb0 fffff800`028d5e7c nt!KyRetireDpcList+0x503 fffff880`04ac67a0 fffff800`0291b793 nt!KiDispatchInterruptContinue04 fffff880`04ac67d0 fffff800`028cbda2 nt!KiDpcInterruptBypass+0x1305 fffff880`04ac67e0 fffff960`0002992c nt!KiInterruptDispatch+0x21206 fffff880`04ac6978 fffff960`000363b3 win32k!vAlphaPerPixelOnly+0x7c07 fffff880`04ac6980 fffff960`00035fa4 win32k!AlphaScanLineBlend+0x30308 fffff880`04ac6a40 fffff960`001fd4f9 win32k!EngAlphaBlend+0x4f409 fffff880`04ac6cf0 fffff960`001fdbaa win32k!NtGdiUpdateTransform+0x112d0a fffff880`04ac6db0 fffff960`001fdd19 win32k!NtGdiUpdateTransform+0x17de0b fffff880`04ac6ed0 fffff960`001fded8 win32k!EngNineGrid+0xb10c fffff880`04ac6f70 fffff960`001fe395 win32k!EngDrawStream+0x1a0

Page 16: Reverse eningeering

kd> !thread THREAD 8649d020 Cid 0134.032c Teb: 7ffdf000 Win32Thread: e1634008 RUNNING on processor 0 IRP List: 8692cf68: (0006,0094) Flags: 40000000 Mdl: 00000000 Not impersonating DeviceMap e21e88b0 Owning Process 0 Image: <Unknown> Attached Process 864a07f0 Image: ReverseEngineer Wait Start TickCount 20134 Ticks: 0 Context Switch Count 23 IdealProcessor: 0 LargeStack UserTime 00:00:00.000 KernelTime 00:00:00.015 Win32 Start Address ReverseEngineeringTester!ILT+1240(_wmainCRTStartup) (0x0042e4dd) Start Address kernel32!BaseProcessStartThunk (0x7c8106f5) Stack Init f7517000 Current f7516b8c Base f7517000 Limit f7513000 Call 0 Priority 8 BasePriority 8 PriorityDecrement 0 DecrementCount 0 ChildEBP RetAddr Args to Child f78b2fd0 80541b8d f7516bc8 00000000 00000000 NotYourFault!TestDpcRoutine+0x52 (FPO: [Non-Fpo]) (CONV: stdcall) [c:\users\kent_huang\perforce\pd_kent_huang\core\vsapi\pd\kent_huang\vsapi\tools\notyourfault\notyourfault\reverseengineering\workeritem.c @ 57] f78b2ff4 8054185a f7516b20 00000000 00000000 nt!KiRetireDpcList+0x46 (FPO: [0,0,0]) f78b2ff8 f7516b20 00000000 00000000 00000000 nt!KiDispatchInterrupt+0x2a (FPO: [Uses EBP] [0,0,1]) WARNING: Frame IP not in any known module. Following frames may be wrong. 8054185a 00000000 00000009 bb835675 00000128 0xf7516b20

Page 17: Reverse eningeering

Timer• Signal the expiration of a certain amount of time

• Periodically or at some time in the future

VOID KeInitializeTimer( _Out_ PKTIMER Timer );

BOOLEAN KeSetTimer( _Inout_ PKTIMER Timer, _In_ LARGE_INTEGER DueTime, _In_opt_ PKDPC Dpc );

BOOLEAN KeSetTimerEx( _Inout_ PKTIMER Timer, _In_ LARGE_INTEGER DueTime, _In_ LONG Period, _In_opt_ PKDPC Dpc );

Page 18: Reverse eningeering

Structure1: kd> dt _KPRCB TimerTable nt!_KPRCB +0x2260 TimerTable : _KTIMER_TABLE 1: kd> dt _KTIMER_TABLE nt!_KTIMER_TABLE +0x000 TimerExpiry : [16] Ptr32 _KTIMER +0x040 TimerEntries : [256] _KTIMER_TABLE_ENTRY 1: kd> dt _KTIMER nt!_KTIMER +0x000 Header : _DISPATCHER_HEADER +0x010 DueTime : _ULARGE_INTEGER +0x018 TimerListEntry : _LIST_ENTRY +0x020 Dpc : Ptr32 _KDPC +0x024 Period : Uint4B 1: kd> dt _KTIMER_TABLE_ENTRY nt!_KTIMER_TABLE_ENTRY +0x000 Lock : Uint4B +0x004 Entry : _LIST_ENTRY +0x010 Time : _ULARGE_INTEGER

Page 19: Reverse eningeering

Process and Thread Callbacks

• Callback function when create or terminate process or thread

• PsSetCreateProcessNotifyRoutine

• PsSetCreateThreadNotifyRoutine

• PsSetLoadImageNotifyRoutine

Page 20: Reverse eningeering

• Many anti-virus software products register these callbacks to monitor system behavior.

• Kernel-mode root-kits sometimes use them in conjunction with APCs to inject code into new processes

Page 21: Reverse eningeering

Completion Routines

• Completion routines are used to notify drivers that their I/O request has been completed

• Use when low-level driver complete a IRP

• IoCompleteRequest, IoSetCompletionRoutine

Page 22: Reverse eningeering

Structure

1: kd> dt _IO_STACK_LOCATION nt!_IO_STACK_LOCATION +0x000 MajorFunction : UChar +0x001 MinorFunction : UChar +0x002 Flags : UChar +0x003 Control : UChar +0x004 Parameters : <unnamed-tag> +0x014 DeviceObject : Ptr32 _DEVICE_OBJECT +0x018 FileObject : Ptr32 _FILE_OBJECT +0x01c CompletionRoutine : Ptr32 long +0x020 Context : Ptr32 Void

Page 23: Reverse eningeering

I/O Request Packets

Page 24: Reverse eningeering

• Windows uses I/O request packets (IRPs) to describe I/O requests to kernel- mode components (like drivers)

• IRP can be divided into two areas

• static, dynamic

• Ex. IRP_MJ_CREATE, IRP_MJ_READ, etc…

Page 25: Reverse eningeering

146 Chapter 3 ■ The Windows Kernel

c03.indd 11:7:49:AM 01/21/2014 Page 146

IRPStatic Port

Dynamic Port

StackCount

Tail.Overlay.CurrentStackLocation

IO_STACK_LOCATION IO_STACK_LOCATION

“next” IRP stack location

“current” IRP stack location

IO_STACK_LOCATION

IO_STACK_LOCATION

IO_STACK_LOCATION

IO_STACK_LOCATION

an IO request packet relationship between IRP and IO_STACK_LOCATIONin an IO request packet

Figure 3-8

Note that the “next” stack location is the element immediately above the “cur-rent” one (not after it). This is important to know because stack location routines such as IoGetCurrentIrpStackLocation, IoSkipCurrentIrpStackLocation, IoGetNextIrpStackLocation, and others are simply returning pointers to these array elements using pointer arithmetic.

Although IRPs are typically generated by the I/O manager in response to requests from users or other devices, they may also be created from scratch and sent to other devices for processing. A driver can allocate an IRP with IoAllocateIrp, associate it with a thread, fi ll out the IRP major and minor code, set up IO_STACK_LOCATION count/size, fi ll in parameters, and send it to the destination device for processing with IoCallDriver. Some rootkits use this mechanism to directly send requests to the fi le system driver in order to bypass system call hooking. You will analyze one such rootkit in the exercise.

Structure of a Driver

A driver is a piece of software that interacts with the kernel and/or controls hardware resources. While there are many different types of drivers, we are primarily concerned with the following types of kernel-mode drivers:

■ Legacy software driver—Software that runs in ring 0 and interacts with the kernel through documented and undocumented interfaces. Most rootkits and security drivers are of this type.

kd> dt _IRP ntdll!_IRP +0x000 Type : Int2B +0x002 Size : Uint2B +0x004 MdlAddress : Ptr32 _MDL +0x008 Flags : Uint4B +0x00c AssociatedIrp : __unnamed +0x010 ThreadListEntry : _LIST_ENTRY +0x018 IoStatus : _IO_STATUS_BLOCK +0x020 RequestorMode : Char +0x021 PendingReturned : UChar +0x022 StackCount : Char +0x023 CurrentLocation : Char +0x024 Cancel : UChar +0x025 CancelIrql : UChar +0x026 ApcEnvironment : Char +0x027 AllocationFlags : UChar +0x028 UserIosb : Ptr32 _IO_STATUS_BLOCK +0x02c UserEvent : Ptr32 _KEVENT +0x030 Overlay : __unnamed +0x038 CancelRoutine : Ptr32 void +0x03c UserBuffer : Ptr32 Void +0x040 Tail : __unnamed

kd> dt _IO_STACK_LOCATION ntdll!_IO_STACK_LOCATION +0x000 MajorFunction : UChar +0x001 MinorFunction : UChar +0x002 Flags : UChar +0x003 Control : UChar +0x004 Parameters : __unnamed +0x014 DeviceObject : Ptr32 _DEVICE_OBJECT +0x018 FileObject : Ptr32 _FILE_OBJECT +0x01c CompletionRoutine : Ptr32 long +0x020 Context : Ptr32 Void

Page 26: Reverse eningeering

Structure of a Driver

Page 27: Reverse eningeering

Kernel Driver

• Type of Kernel Driver

• Legacy software driver

• Legacy filter driver

• File system minifilter driver

Page 28: Reverse eningeering

How to Write Kernel Driver• WDM ( Windows Driver Model )

• Defined since Windows 2000 and all drivers you analyze are based on it

• KMDF ( kernel-mode driver framework )

• WDF is basically a set of libraries built on top of WDM that simplifies driver development

Page 29: Reverse eningeering

Entry Points

• The primary responsibility of DriverEntry

• Initialize driver-specific settings

• Register IRP dispatch routines DriverEntry: DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateCloseHandler; DriverObject->MajorFunction[IRP_MJ_CLOSE] = CreateCloseHandler; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControlHandler;

Page 30: Reverse eningeering

• If you do not initialize the MajorFunction table, default handler is “IopInvalidDeviceRequest”

• If a driver supports dynamic unloading, it must also fill out the DriverUnload field

Page 31: Reverse eningeering

STATUS_INVALID_DEVICE_REQUEST

Page 32: Reverse eningeering

Driver and Device Objects

typedef struct _DEVICE_OBJECT { CSHORT Type; USHORT Size; LONG ReferenceCount; struct _DRIVER_OBJECT *DriverObject; struct _DEVICE_OBJECT *NextDevice; struct _DEVICE_OBJECT *AttachedDevice; struct _IRP *CurrentIrp; ... PVOID DeviceExtension; DEVICE_TYPE DeviceType; CCHAR StackSize; ... ULONG ActiveThreadCount; PSECURITY_DESCRIPTOR SecurityDescriptor; ... PVOID Reserved; } DEVICE_OBJECT, *PDEVICE_OBJECT;

Page 33: Reverse eningeering

IRP Handling • The prototype for these dispatch routines

• If the dispatch routine successfully completes:

• Calls IoCompleteRequest and returns

• If it cannot complete:

• Return an error, pass the IRP to another driver, or pend the IRP

NTSTATUS XXX_Dispatch ( PDEVICE_OBJECT *DeviceObject, PIRP *Irp );

Page 34: Reverse eningeering

A Common Mechanism for User-Kernel Communication

• Shared memory region double-mapped in user and kernel space

• Create an event that a user-mode thread can wait on; the event state can be used as a trigger for further action

• Interrupt handling

• IRP_MJ_DEVICE_CONTROL operation and commonly referred to as device I/O control or simply IOCTL

Page 35: Reverse eningeering

I/O Control Code• User-mode code can request these IOCTL

operations through the DeviceIoControl API. User Mode: bResult = DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, &Overlapped);

Kernel Mode: NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath) { … DriverObj->MajorFunction[IRP_MJ_CLEANUP] = DispatchFilter; DriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchFilter; … }

NTSTATUS DispatchFilter(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); switch(IrpStack->MajorFunction) { … case IRP_MJ_DEVICE_CONTROL: // Handle IOCTL break;

… }

}

Page 36: Reverse eningeering

• Buffering Methods

• Buffered I/O

• Direct I/O

• Neither

• I/O Control Code

Page 37: Reverse eningeering

Miscellaneous System Mechanisms

• System Control Registers

• Root-kit developers resort to hooking func- tions in the kernel. But Kernel code is mapped as Read-Only.

• Protect by hardware level special control register: CR0

• CPU can write to read-only pages (WP bit)

Page 38: Reverse eningeering

System Control Registers

Page 39: Reverse eningeering

KeServiceDescriptorTable

• Many root-kits resort to hooking system calls

• But the system call table (KiServiceTable) is not exported

• How to access KiServiceTable?

• Ex. Sample G

Page 40: Reverse eningeering
Page 41: Reverse eningeering

Sections