i/o, you own: regaining control of your disk in the presence of bootkits

78
I/O, YOU OWN: REGAINING CONTROL OF YOUR DISK IN THE PRESENCE OF BOOTKITS Aaron LeMasters @lilhoser

Upload: crowdstrike

Post on 05-Sep-2014

7.618 views

Category:

Technology


3 download

DESCRIPTION

 

TRANSCRIPT

Page 1: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

I/O, YOU OWN:

REGAINING CONTROL

OF YOUR DISK IN THE

PRESENCE OF

BOOTKITS

Aaron LeMasters @lilhoser

Page 2: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Introduction2

My background

Your background

Brief history of this presentation

Disclaimer: some of this might be wrong…

Please read white paper for details

Page 3: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Agenda3

Technical Background What is the crash dump stack in Windows?

How the operating system initializes and uses the crash dump stack (post Windows Vista) Pre Vista is in Appendix A

Bootkit Defeat Technique for SCSI drives How we can use this stack outside of the operating

system’s normal activity

IDE drive technique in Appendix B

Sneak peak at Windows 8 Release Preview changes

Demo – Defeating TDL4

Page 4: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Terminology and Concepts

Technical Background 4

Page 5: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Basics

Port driver – abstraction interface provided by OS, hides underlying protocol details from class driver

Miniport driver – manufacturer-supplied driver to interface with hardware (Host Bus Adapter/HBA); linked against port driver for specific transport technology

Class driver – a driver that abstracts the underlying technology of a category of devices that share similar qualities (e.g., cdrom.sys)

Normal I/O path – the route an I/O request takes during regular system operation

Crash dump I/O path – the route the kernel uses to write a crash dump file to disk during a crash

5

Page 6: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Normal I/O Path6

Page 7: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crash Dump I/O Path7

Page 8: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Why two paths?8

When a bugcheck occurs, the OS has no idea

where the problem occurred – it could have

happened inside a driver in the normal I/O

path.

What differs between the two paths?

Normal I/O Path Crash Dump I/O Path

Primary drivers Many, layered Modified port and miniport

Filter drivers Many, layered Crash dump filters only

Controlled by I/O manager Kernel or crashdmp.sys

Documented? Yes *cough*

Page 9: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

The Crash Dump Mechanism9

Encompasses the entire crash dump process

From when it is initialized during system boot up to when it is used after KeBugCheck2()

Primary components:

The kernel

Crashdmp.sys (Vista+)

The crash dump driver stack or just “crash dump stack”

Goal: Write a crash dump file to boot device or save state in a hibernation file

Page 10: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

The Crash Dump Stack10

A “stack” of drivers, consisting of:

A dump port driver

A dump miniport driver

One or more crash dump filter drivers

Initialized in two phases:

System startup/page file creation (pre-initialization)

System crash (post-initialization)

Used when:

A bug check occurs

The system is about to hibernate

Page 11: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

The Crash Dump Stack – Common Drivers

11

Driver Name On Disk Driver Base Name in

Memory

Purpose

diskdump.sys dump_diskdump SCSI/Storport dump port

driver with required exports

from scsiport.sys and

storport.sys. This driver is

unloaded.

dumpata.sys dump_dumpata IDE/ATA dump port driver with

required ataport.sys exports.

This driver is unloaded.

scsiport.sys dump_scsiport The final SCSI/Storport dump

port driver.

ataport.sys dump_ataport The final IDE/ATA dump port

driver.

atapi.sys dump_atapi An older, generic ATAPI

miniport driver provided by the

OS for IDE/ATA drives

vmscsi.sys dump_vmscsi The miniport driver provided

by VMWare for SCSI drives.

LSI_SAS.sys dump_LSI_SAS The miniport driver provided

by LSI Corporation for serial-

attached storage drives.

dumpfve.sys dump_dumpfve Windows full volume

encryption crash dump filter

driver

Page 12: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crash Dump Environment12

Normal I/O path is disabled

All processors are disabled except the one the

current thread is executing on

Active CPU becomes single-threaded (IRQL is

raised to HIGH_LEVEL) and uninterruptible

I/O sent to the crash dump stack is

synchronous

If IDE controller, only the channel containing

the device with the paging file is enabled

Page 13: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crash Dump Stack Initialization and Usage

after Windows Vista

Technical Background13

Page 14: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crash Dump Stack Configuration14

Crash dump is configured via IoConfigureCrashDump()

Reads in registry settings to control dump

behavior

Passes handle to system paging file to IopInitializeCrashDump()

Triggered via NtSetSystemInformation()

or PoBroadcastSystemState() or

PoShutdownBugCheck()

Page 15: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Initialization15

Page 16: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Load and Call Entry Point of Crashdmp.sys

16

Nearly all of crash dump code was removed from kernel and put in crashdmp.sys

KiInitializeKernel() IoInitSystem() OR NtCreatePagingFile()

IoInitializeCrashDump(HANDLE PageFile)

IopLoadCrashDumpDriver() – loads crashdmp.sys

Crashdmp!DriverEntry() – fills crash dump call table

Entry point called with two arguments:

Name of the arc boot device

Pointer to a global crashdmp callback table

Page 17: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Call Table17

Table Offset* Value

0x0 1

0x4 1

0x8 CrashdmpInitialize

0xC CrashdmpLoadDumpStack

0x10 CrashdmpInitDumpStack

0x14 CrashdmpFreeDumpStack

0x18 CrashdmpDisable

0x1C CrashdmpNotify

0x20 CrashdmpWrite

0x24 CrashdmpUpdatePhysicalRange

*Pointer width is 8 bytes on 64-bit systems

Page 18: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Identify and Initialize Crash Dump Drivers

18

KiInitializeKernel()

IoInitSystem() OR

NtCreatePagingFile()

IoInitializeCrashDump()

Crashdmp!CrashDmpInitialize():

Crashdmp!CrashdmpLoadDumpStack():

Crashdump!QueryPortDriver()

Crashdmp!LoadPortDriver()

Crashdmp!LoadFilterDrivers()

Crashdmp!InitializeFilterDrivers()

Page 19: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

CrashdmpInitialize() 19

References boot device’s FILE_OBJECT

Read registry for crash dump settings

Stored in local crashdump control block

Initializes crashdump control block

Registers a KbCallbackSecondaryDumpData

bugcheck callback

Calls CrashdmpLoadDumpStack()…

Page 20: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

CrashdmpLoadDumpStack() 20

Queries port driver capabilities using IOCTL_SCSI_GET_DUMP_POINTERS, IOCTL_SCSI_GET_ADDRESS, IOCTL_SCSI_GET_PARTITION_INFO, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, IOCTL_SCSI_GET_DRIVE_GEOMETRY_EX

Locates all crash dump drivers: port, miniport and crash dump filter drivers Copies them into memory with “dump_” prefix

No DRIVER_OBJECT or DEVICE_OBJECT!

Port driver will be one of dump_scsiport, dump_ataport or dump_storport; on disk either diskdump.sys (scsi/storport) or dumpata.sys (ataport)

Miniport can be named anything

Page 21: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Usage

21

Page 22: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Call Dump Driver Entry Points22

KeBugCheck2() IoWriteCrashDump():

Calls the eighth entry in the CrashDmpCallTable table,

CrashDmpNotify() - displays the string

“collecting data for crash dump”

Fills dump block with bug check codes and other

debug information

Appends a triage dump if necessary

Page 23: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Call Dump Driver Entry Points and

Dump Port Driver Callbacks23

KeBugCheck2() IoWriteCrashDump():

Calls the ninth entry in the CrashDmpCallTable

table, CrashDmpWrite():

CrashdmpInitDumpStack():

StartFilterDrivers() – calls the DumpStart

callback of each crash dump filter driver

InitializeDumpDriver() – calls the dump driver

entry point; calls the DiskDumpOpen callback provided by

the dump port driver; fills dump context structure with callback pointers CrashdmpWriteRoutine,

CrashdmpWritePendingRoutine,

CrashdmpFinishRoutine

Page 24: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Data Written to Dump File24

KeBugCheck2() IoWriteCrashDump(): CrashDmpWrite():

CrashdmpInitDumpStack():

DumpWrite() – creates dump file based on configuration: FillDumpHeader()

Calls one of: WriteFullDump()

WriteKernelDump()

WriteMiniDump()

InvokeSecondaryDumpCallbacks() - Invokes all BugCheckSecondaryDumpDataCallback callbacks to allow drivers to append data to the completed crash dump file.

InvokeDumpCallbacks() - Invokes all BugCheckDumpIoCallback callbacks, informing them crash dump is complete.

Page 25: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

How to bypass the Normal I/O Path and

use the Crash Dump I/O Path to read and

write to disk

Bootkit Defeat Technique25

Page 26: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Inspiration26

Restrictions on Miniport Drivers that Manage the Boot Drive:

“A storage miniport driver that manages an adapter for a boot device is subject to special restrictions during a system crash. While dumping the system's memory image to disk, the miniport driver must operate within a different environment. The usual communication between the miniport driver, the port driver, and disk class driver is interrupted. The kernel does disk I/O by direct calls to the disk dump port driver (diskdump.sys for SCSI adapters or dumpata.sys for ATA controllers), bypassing file systems, and the normal I/O stack. The disk dump driver, in turn, calls the boot device's miniport driver to handle all I/O operations, and the disk dump driver intercepts all of the miniport driver's calls to the port driver.” [1]

Page 27: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Leveraging the Crash Dump I/O

Path27

The crash dump mechanism provides a

pristine path to disk

But it only provides write capabilities

Leverage knowledge of the crash dump

mechanism and internals of the port/miniport

relationship to coerce read/write

Here’s how…

Page 28: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

..sort of like the O/S does…28

Page 29: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

…but more like this29

Page 30: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Identify Crash Dump Port/Miniport

Drivers30

Walk loaded module list

Single out dump drivers easily via “dump_” prefix

Port driver will be one of dump_scsiport, dump_storport or dump_ataport

Miniport driver name: open a handle to the class driver’s device object, walk

attached devices to the lowest one

Vista+ DUMP_POINTERS_EX.DriverList

Once drivers have been found, call their entry points with the appropriate arguments Dump port: DriverEntry(NULL, DumpInit*)

Dump miniport: DriverEntry(NULL, NULL)

Page 31: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Get Boot Device Information31

IOCTL to get hardware register mapping and port configuration information (IOCTL_SCSI_GET_DUMP_POINTERS); data returned in DUMP_POINTERS or DUMP_POINTERS_EX structure

IOCTL to get boot device location such as Target id, path Id, and Lun (IOCTL_GET_SCSI_ADDRESS); data returned in a SCSI_ADDRESS structure

Resulting information is stored in the DUMP_INITIALIZATION_CONTEXT structure before calling the dump port driver’s DriverEntry

Page 32: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Find StartIo or DispatchCrb32

How do we send I/O requests?

There is no device object for dump port driver

Use internal functions

StartIo (SCSI) – accepts a single

SCSI_REQUEST_BLOCK (SRB) as argument

DispatchCrb (IDE) – accepts a single

argument, a channel extension structure

Find functions by scanning dump port driver’s

image’s text section for “magic bytes”

Page 33: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Find the Dump Port Driver’s Device Extension (1/2)

33

Can’t simply call the internal functions, more initialization required

Port/miniport share a device extension structure that must be properly initialized An internal variable of the port driver

Most critical fields are filled in by dump port driver/miniport driver’s DriverEntry routines

Two methods to find Device Extension Call a dump port function that leaks a pointer to it

Use DumpInit.MemoryBlock + 16 Dump port’s DriverEntry()assigns Device Extension to DumpInit->MemoryBlock+16, which we control and pass as second argument to DriverEntry() when we call it

Both methods work for all transports all the way through Windows 8

Page 34: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Find the Dump Port Driver’s Device Extension (2/2)

34

Function pointer leak example: Diskdump.sys leaks in ecx register in

DiskDumpOpen()

Transport Leaking Function Leaked in Register Architecture

SCSI/Storoprt

(diskdump.sys)

DiskDumpOpen ecx x86

SCSI/Storport

(diskdump.sys)

DriverEntry rdx x64

IDE (dumpata.sys)* IdeDumpOpen ecx x86

IDE (dumpata.sys)* IdeDumpOpen rcx x64

Page 35: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Send SRB (SCSI) (1/2)35

Mimic DiskDumpWrite()

Allocate an MDL at offset 0xD0 (0x118 x64) into the

device extension structure – MDL describes the SRB.DataBuffer

Call StartIo()

Page 36: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Send SRB (SCSI) (2/2)36

After MDL is created, send an SRB as follows: SRB.Function - SRB_FUNCTION_EXECUTE_SCSI

SRB.PathId, SRB.TargetId, SRB.Lun – set to corresponding fields in SCSI_ADDRESS

SRB.CdbLength - 10 for 10-byte SCSI-2 command

SRB.SrbFlags - specify flags for a read operation

SRB.DataTransferLength - 512

SRB.DataBuffer - allocate 512 bytes NonPagedPool – result stored here

SRB.Cdb – the SCSI-2 command descriptor block (cdb) Describes the location on disk to read

Page 37: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Overview

Demo37

Page 38: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Recent Bootkits38

Alureon/TDL4 has gained popularity in the last few years

Abuses driver trust chain by hooking the port and miniport drivers, which are at the bottom of the disk driver stack trust chain

Modifies I/O requests in various ways to hide its rootkit file system, as well as return a clean MBR

Similar MBR/VBR rootkits include Popureb, Stoned, Hasta La Vista, Zeroaccess

Completely new strains, as well as variants, emerging constantly

Page 39: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

TDL4 Bootkit Infection39

Modifies the miniport’s device object and driver object

DRIVER_OBJECT.DriverStartIo hooked

DEVICE_OBJECT.DriverObject hooked

Lowest attached device is unlinked from the miniport device by hooking DEVICE_OBJECT.NextDevice

Monitors for read or write attempts to the boot sector and its hidden file system

If boot sector, return original, clean MBR

If hidden file system, return zeroes

For more info, see [2]

Page 40: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Defeating TDL4

Demo40

Page 41: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Results – Full Disclosure!41

SCSI – working from Windows XP – 7 (tested)

IDE – polling is hard

Method 1: IRB sent, garbage returned

Either the port driver is messing up the IRB somewhere

during polling or we are missing a field in dump extension

Method 2: IRB sent, nothing returned , IRB status 2

(data length mismatch), ATA status 0x20 (?)

IRB.TaskFile might have invalid values

IDE_TASK_FILE: No examples anywhere!

Dump extension field missing – data length?

Page 42: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

PoC Improvements42

POCs for both transports can cause

momentary lag or event deadlock, because

normal I/O path is not properly “shutdown”

Solution:

SCSIPort (push model, port driver controls

queuing I/O) - Need to send flush and lock

request SRB’s

StorPort – (pull model, miniport driver controls queuing I/O) – StorPortPauseDevice()

Page 43: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

A Sneak Peak at Exciting New Changes

Windows 8 Release Preview43

Page 44: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Core Kernel Changes44

Synchronization changes suggest crash dump

stack can be used in multiple places

New function IopInitializeCrashDump()

Contents of IoInitializeCrashDump() moved

here

only called if a prior initialize attempt fails and it guards call to IopInitializeCrashDump()with critical region

IopCrashDumpLock previously only used when

crash dump stack is (re)configured; now

additionally used when (re)initialized

Page 45: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp Call Table Changes45

Table Offset* Windows 7 Value Windows 8 RP Value

0x0 1 1

0x4 1 4

0x8 CrashdmpInitialize

0xC CrashdmpLoadDumpStack

0x10 CrashdmpInitDumpStack

0x14 CrashdmpFreeDumpStack

0x18 CrashdmpDisable

0x1C CrashdmpNotify

0x20 CrashdmpWrite

0x24 CrashdmpUpdatePhysicalRange

0x28 CrashdmpResumeCapable

0x2C CrashdmpGetTransferSizes

0x30 CrashdmpLogStatusData

0x34 CrashdmpReady

*Pointer width is 8 bytes on 64-bit systems

Page 46: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Changes (1/6)46

GetLegacyPortDriverName() no longer uses static dump port driver names (e.g, “diskdump.sys”, “storport.sys”, “scsiport.sys”)

After loading a crash dump driver in CrashdmpLoadDriver()via MmLoadSystemImage(), it uses RtlImageNtHeader on imageBase instead of direct return value – possible bug fix

New hiber functions, ResumeCapable

ETW tracing, performance counters

Enhanced logging in c:\DumpStack.log.tmp

Crashdmp.sys “drive telemetry” callback

New dump type: bitmap dump

Page 47: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Changes (2/6)47

New security checks using __fastfail

intrinsic [3]

CORRUPT_LIST_ENTRY cases

DumpWrite function used by call table’s

CrashdmpWrite is not handled by IDA auto

analysis – you must undefine bogus

data/code, restart analysis or force code

generation on block, and recreate the function

Several other functions have this issue

Page 48: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Changes (3/6)48

Page 49: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Changes (4/6)49

CrashdmpWrite behavior changed:

Checks that dump device is ready (eg, supported firmware); if so, call DumpWrite; if not, call

DumpWriteCapsule which simulates the write

by calling special “dump capsule” dump filters but

does not write actual dump to disk

“Dump capsule” concept not documented

Page 50: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Changes (5/6)50

Dump port driver DriverEntry() prototype

has changed

Old: DriverEntry(NULL, DumpInit*)

New: DriverEntry(NULL,

CrashdmpContext*)

This will affect our PoC (it won’t work on Win8)

New PoC coming soon…

Page 51: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crashdmp.sys Changes (6/6)51

New CrashdmpReadRoutine populated in

dump context structure by InitializeDumpDriver()

Wrapper around a call to new dump port driver function Diskdump!DiskDumpRead()

Calls new function DiskDumpIoIssue() which sets

up SCSI read SRB and performs all of the hard tasks

that the POC in this paper had to hack

Page 52: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Why a New Read Capability?52

Not to make my research irrelevant

Internally: supports logging and new hibernation resume feature

Externally: crash dump filter drivers now have the ability to filter read requests to dump port driver Define a DUMP_READ callback [4]

Provide a pointer to the callback in FILTER_INITIALIZATION_CONTEXT [5]

“Filter drivers can modify the contents of the data buffer contained in Mdl to revert any changes made to the data when it was written to disk” [4] Probably to support hibernation resume; for example,

encryption drivers need to decrypt

Page 53: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

How to Use It (1/3)53

Filter read callback is cool, but not helpful to the goal of

this research

We can only see read requests initiated by kernel/dump port

driver; not useful for controlling what is read

But the point is the Crash Dump I/O Path now supports

reading – we don’t need to hack it

At least not as bad as before

Contention issues with normal I/O path still exist

Page 54: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

How to Use It (2/3)54

We have two options:

1. CrashdmpReadRoutine(Type, Offset, Mdl): just a

wrapper for port read routine; only adds functionality to call

filter read callbacks

2. Diskdump!DumpRead(Type, Offset, Mdl): does the

actual work with miniport to complete I/O

The first option adds no value for us

Best option: call the port driver’s DumpRead() routine

directly

Determine any pre-requisites

Page 55: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

How to Use It (3/3)55

The dump port driver read routine is a simple wrapper:

DiskDumpIoIssue() kindly handles the entire I/O

issuing process for us (i.e, our POC’s hack):

SRB initialization for a read operation

Mapping the MDL if required

Calling StartIo(), which calls the dump miniport

Polling to wait on result

Can we call DiskDumpRead() directly?

Stay tuned…

Page 56: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Conclusions56

Page 57: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Takeaways57

Why is this important?

We have a separate path to disk which is not currently hooked by any malware I am aware of

Tampering with the crash dump mechanism could destabilize the system

We can read AND write to disk this way

The crash dump port driver only provides callbacks to write to disk, but the StartIo function lets us issue any arbitrary SRB

The ability to write to disk with this technique provides us unique remediation (file cleaning) opportunities

New read functionality in Windows 8 makes reading disk via dump port driver officially supported (sort of)!

Page 58: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Stay Tuned…58

Keep an eye on blog.crowdstrike.com

New series on Windows 8 coming soon

Alex Ionescu (author of Windows Internals) covers

new security features and how to break them

I will be posting about crash dump changes related to

this research

Whitepaper coming soon

Windows 8 PoC coming soon

Page 59: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

References59

[1] http://msdn.microsoft.com/en-us/library/ff564084(v=VS.85).aspx

[2] http://go.eset.com/us/resources/white-papers/The_Evolution_of_TDL.pdf

[3] http://www.alex-ionescu.com/?m=201110

[4] http://msdn.microsoft.com/en-us/library/windows/hardware/hh439713(v=vs.85).aspx

[5] http://msdn.microsoft.com/en-us/library/windows/hardware/ff553865(v=vs.85).aspx

Special thanks to Alex Ionescu

Page 60: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

60

Thanks for listening!

Questions ???

[email protected]

@lilhoser

Page 61: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Crash Dump Stack Initialization and Usage

before Windows Vista

Appendix A61

Page 62: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Initialization62

Page 63: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Initialize IopDumpControlBlock63

KiInitializeKernel()

IoInitSystem() OR

NtCreatePagingFile():

IoInitializeCrashDump():

IopInitializeDCB():

Allocate IopDumpControlBlock structure

Fill in basic debug information - # CPUs, architecture, OS

version, etc

Read registry settings for crash dump configuration

Page 64: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

IopDumpControlBlock64

IopDumpControlBlock – global kernel variable typedef struct _DUMP_CONTROL_BLOCK { UCHAR Type; CHAR Flags; USHORT Size; CHAR NumberProcessors; CHAR Reserved; USHORT ProcessorArchitecture; PDUMP_STACK_CONTEXT DumpStack; PPHYSICAL_MEMORY_DESCRIPTOR MemoryDescriptor; ULONG MemoryDescriptorLength; PLARGE_INTEGER FileDescriptorArray; ULONG FileDescriptorSize; … }DUMP_CONTROL_BLOCK, *PDUMP_CONTROL_BLOCK;

Page 65: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Identify and Initialize Crash Dump

Drivers65

IoInitializeCrashDump():

IoGetDumpStack() IopGetDumpStack(): Fills IopDumpControlBlock.DumpInit:

Boot device type, geometry and hardware attributes

Locates all crash dump drivers: port, miniport and crash dump filter drivers Copies them into memory with “dump_” prefix

No DRIVER_OBJECT or DEVICE_OBJECT! Port driver will be one of dump_scsiport, dump_ataport

or dump_storport; on disk either diskdump.sys (scsi/storport) or dumpata.sys (ataport)

Miniport can be named anything

Fills IopDumpControlBlock.DumpStack with linked list of copied drivers

Page 66: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

IopDumpControlBlock.DumpStack

66

typedef struct _DUMP_STACK_CONTEXT

{

DUMP_INITIALIZATION_CONTEXT Init;

LARGE_INTEGER PartitionOffset;

PVOID DumpPointers;

ULONG PointersLength;

PWCHAR ModulePrefix;

LIST_ENTRY DriverList;

ANSI_STRING InitMsg;

ANSI_STRING ProgMsg;

ANSI_STRING DoneMsg;

PVOID FileObject;

enum _DEVICE_USAGE_NOTIFICATION_TYPE UsageType;

} DUMP_STACK_CONTEXT, *PDUMP_STACK_CONTEXT;

Page 67: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

IopDumpControlBlock.DumpStack

67

DumpPointers - contains hardware-specific information about the disk drive (via IOCTL_SCSI_GET_DUMP_POINTERS) which is used during write I/O operations to the crash dump file.

DriverList - contains a linked list of data structures that describe the driver image of each driver in the crash dump stack; used at actual crash dump time to initialize each driver

Init - of type DUMP_INITIALIZATION_CONTEXT (undocumented but exported), shown below, is only partially filled in during the 1st phase of initialization.

Page 68: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Usage

68

Page 69: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Call Dump Driver Entry Points (1/3)69

During pre-initialization, drivers were only mapped into memory - no management blocks created, no entry points called

Each driver in the dump stack will now have its entry point called

The first driver in the stack is always the dump port and it is always called first

Two arguments: 1. NULL

2. IopDumpControlBlock.DumpInit

Page 70: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Call Dump Driver Entry Points (2/3)70

typedef struct _DUMP_INITIALIZATION_CONTEXT

{

ULONG Length;

ULONG Reserved;

PVOID MemoryBlock;

PVOID CommonBuffer[2];

PHYSICAL_ADDRESS PhysicalAddress[2];

PSTALL_ROUTINE StallRoutine;

PDUMP_DRIVER_OPEN OpenRoutine;

PDUMP_DRIVER_WRITE WriteRoutine;

PDUMP_DRIVER_FINISH FinishRoutine;

struct _ADAPTER_OBJECT *AdapterObject;

PVOID MappedRegisterBase;

PVOID PortConfiguration;

} DUMP_INITIALIZATION_CONTEXT,*PDUMP_INITIALIZATION_CONTEXT;

Page 71: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Call Dump Driver Entry Points (3/3)71

OpenRoutine, WriteRoutine and FinishRoutine fields are populated: pointers to functions exported by the dump port driver

which provide the kernel the ability to write the crash dump data to the crash dump file

The dump miniport driver’s DriverEntry is called registers with the dump port driver

All other dump driver’s DriverEntry are called with NULL arguments According to MSDN, this notifies them to operate in

“crash dump mode”

Page 72: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Call Dump Port Driver Callbacks72

KeBugCheck2() IoWriteCrashDump(): IoInitializeDumpStack() – performs post-initialization of

crash dump drivers

DiskDumpOpen() – this port driver export is called to prepare the crash dump file

Displays the dump string “Beginning dump of physical memory”, stored in the DUMP_CONTROL_BLOCK structure

Calculates the dump storage space required based on configuration

Fills a dump header with bug check codes and other debug information

Invokes all BugCheckDumpIoCallback callbacks registered with the kernel via KeRegisterBugCheckReasonCallback(), passing the dump header

Page 73: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Data Written to Dump File73

KeBugCheck2() IoWriteCrashDump(): IoInitializeDumpStack() – performs post-

initialization of crash dump drivers

One of the following functions calls DiskDumpWrite() until all crash dump data is written: IopWriteSummaryHeader()

IopWriteSummaryDump()

IopWriteTriageDump()

Invokes all BugCheckSecondaryDumpDataCallback callbacks to allow drivers to append data to the completed crash dump file

Calls DiskDumpFinish() to close crash dump file

Invokes all BugCheckDumpIoCallback callbacks, informing them crash dump is complete.

Page 74: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Bootkit Defeat Technique for IDE Drives

Appendix B74

Page 75: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Send IRB (IDE) – General Idea75

Page 76: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Send IRB (IDE) – Method 176

Relies on calling port driver internal functions

Mimic IdeDumpWritePending() Allocate a CRB in DUMP_INITIALIZATION_CONTEXT.MemoryBlock at the correct offset (0x120 for x86, 0x1C0 for x64)

Allocate and fill in an IRB at offset 0x288 (0x3E8 for x64) in the CRB

Store a pointer to a callback function in the CRB at offset 0x4, which will be invoked when the dump port driver is notified that the I/O request is complete

Allocate an MDL at offset 0x50 (0x88 for x64) in the CRB

Send the CRB to DispatchCrb()

Wait via IdeDumpWaitOnRequest()function

Page 77: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Send IRB (IDE) – Method 277

Completely bypass dump port driver

Mimic IdeDumpWritePending()

Allocate a CRB in DUMP_INITIALIZATION_CONTEXT.MemoryBlock at the correct offset (0x120 for x86, 0x1C0 for x64)

Store a pointer to a callback function in the CRB at offset 0x4, which will be invoked when the dump port driver is notified that the I/O request is complete

Allocate and fill in an IRB at offset 0x288 (0x3E8 for x64) in the CRB

Replace DispatchCrb() with Call the miniport’s HwStartIo routine, which is stored at offset 0x2E in the

device extension, passing the device extension and the IRB

Replace IdeDumpWaitOnRequest() with:

Poll the device until the IRB status changes from zero by calling the miniport’s HwInterrupt routine which is stored at offset 0x2F in the device extension, passing the device extension only

Page 78: I/O, You Own: Regaining Control of Your Disk in the Presence of Bootkits

Send IRB (IDE)78

IRB.Function - IRB_FUNCTION_ATA_COMMAND

IRB.Channel - should be set to the value stored in the channel extension’s Channel field which is at offset 0x8A (0xEA for x64) from the start of the CRB

IRB.TargetId - should be set to the value stored in the channel extension’s TargetId field which is at offset 0x45D (0x6A9 for x64) from the start of the CRB

IRB.Lun - should be set to the value stored in the channel extension’s Lun field which is at offset 0x45E (0x6AA for x64) from the start of the CRB