PDA

View Full Version : x86 Kernel Memory Space Visualization (KernelMAP v0.0.1)


j00ru vx tech blog
January 4th, 2010, 17:21
What I would like to write about today is a subject I have been playing with for quite some time – Windows kernel vulnerability exploitation techniques. While digging through various articles and other materials, I appeared to find bunches of interesting facts that are worth being described here. The post presented today aims to describe various ways of obtaining kernel-mode addresses from the user-mode (application) level.

One could ask, what would we want to retrieve any internal system addresses for. Well, it is indeed a very good question – as for me, the kernel addresses become most useful in the vulnerability exploitation process. Since a majority of bugs found in device drivers belong, directly (pointer validation) or indirectly (pool buffer overflow), to the write-what-where condition family, one must know the exact address to be overwritten before performing the operation. This basically means that the more information about kernel memory layout we can gather, the more stable and effective attacks can be conducted.

The idea I am writing about is not new, for sure. A great part of kernel exploits programmers has already used such techniques in their source code. However, I haven’t ever found any publication that would thoroughly describe every possible vector of obtaining somewhat “sensitive” kernel data (addresses) from within user-mode. Hence, I would like to present a short introduction of each method I could think of – a longer article will presumably be released within a few days. Huh, let’s get to the point, already!

NtQuerySystemInformation function

Before trying to retrieve any information from the kernel, one should firstly realize, what are the possible “communication channels”, that could be used to get the desired data from. The most basic method division could look like this:


Kernel communication – calling some of the exported system routines and receive the data we are interested in, through the output buffer
Processor communication – directly using some of the processor characteristics (i.e. instruction set) in order to query for some processor-specific values that the system is obliged to fill.
All in all, the kernel isn’t meant to release too much information about itself to the user (since every leaked piece of data could potentially help the attacker to hack the machine); due to this fact, there are special routines designed to handle queries about the system state, configuration etc. As it turns out, these system calls (named NtQuery*Information) can provide very miscellaneous kinds of information that not every low-level coder is aware of. I strongly advice you to take a look and test the functions below, using many different arguments:


NtQueryInformationThread ("http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Thread/NtQueryInformationThread.html")
NtQueryInformationProcess ("http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Process/NtQueryInformationProcess.html")
NtQuerySystemInformation ("http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/NtQuerySystemInformation.html")
Even thought these syscalls are either documented very poorly or not documented at all, some independent researchers have already managed to describe a great part of them – their work is publicly available, for example here ("http://undocumented.ntinternals.net/"). For our purposes (global system info), the last function on the list seems to be the most useful one – it is, indeed. As one can see, the first routine parameter is _SYSTEM_INFORMATION_CLASS – a single enum containing all the possible request types, shown below:

Code:
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemInformationClassMin = 0,
SystemBasicInformation = 0,
SystemProcessorInformation = 1,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemPathInformation = 4,
SystemNotImplemented1 = 4,
SystemProcessInformation = 5,
SystemProcessesAndThreadsInformation = 5,
SystemCallCountInfoInformation = 6,
SystemCallCounts = 6,
SystemDeviceInformation = 7,
SystemConfigurationInformation = 7,
SystemProcessorPerformanceInformation = 8,
SystemProcessorTimes = 8,
SystemFlagsInformation = 9,
SystemGlobalFlag = 9,
SystemCallTimeInformation = 10,
SystemNotImplemented2 = 10,
SystemModuleInformation = 11,
SystemLocksInformation = 12,
SystemLockInformation = 12,
SystemStackTraceInformation = 13,
SystemNotImplemented3 = 13,
SystemPagedPoolInformation = 14,
SystemNotImplemented4 = 14,
SystemNonPagedPoolInformation = 15,
SystemNotImplemented5 = 15,
SystemHandleInformation = 16,
SystemObjectInformation = 17,
SystemPageFileInformation = 18,
SystemPagefileInformation = 18,
SystemVdmInstemulInformation = 19,
SystemInstructionEmulationCounts = 19,
SystemVdmBopInformation = 20,
(...)
} SYSTEM_INFORMATION_CLASS;
(you can find the complete definition in the standard ddk\ntapi.h header file). As the name implies, there are really plenty of information to get – the only thing required is the knowledge of how to the input/output structures for each request looks like. At this point, we are particularly interested in three query types – SystemModuleInformation, SystemHandleInformation and SystemLocksInformation. Moreover, SystemObjectInformation could be also useful, under specific circumstances. Let’s go through these requests and find out, what information can we get.

SystemModuleInformation

As far as my observations go, this request is the most commonly used type, across kernel-mode exploits. To understand why, one should first take a look at what this operation returns:

Code:
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
ULONG** * Unknown1;
ULONG** * Unknown2;
PVOID* Base;
ULONG* Size;
ULONG* Flags;
USHORT* Index;
/* Length of module name not including the path, this
field contains valid value only for NTOSKRNL module */
USHORT** *NameLength;
USHORT* LoadCount;
USHORT* PathLength;
CHAR* ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;

typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG* Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
What the listing presents is a main structure, containing the number of module information entries returned. Right after this value, Count SYSTEM_MODULE_INFORMATION_ENTRY structures follow, each containing information about one, specific executable image, loaded inside the kernel-mode address space.

As the names themselves suggest, after calling NtQuerySystemInformation(SystemModuleInformation,… and passing a properly-sized buffer, the application obtains the Name, ImageBase and ImageSize of every single device driver (excluding those that are hidden by rootkits, of course http://j00ru.vexillium.org/wp-includes/images/smilies/icon_wink.gif ). This includes the very first Windows kernel images like ntosknrl.exe (or other types of the system core), HAL.dll (hardware support), win32k.sys (std graphic device driver) and so on. Because of the fact that most write-what-where attacks are based on modyfing the ntosknrl.exe memory regions (such as the [HalDispatchTable+4] technique), obtaining the kernel ImageBase* value is an essential part of the entire exploitation. Some very educational articles covering kernel-mode exploitation techniques can be found here ("http://www.uninformed.org/?v=10&a=2") (Analyzing local privilege escalations in win32k), here ("http://reversemode.com/index.php?option=com_content&task=view&id=38&Itemid=1") (Exploiting Common Flaws in Drivers) and here ("http://www.piotrbania.com/all/articles/ewdd.pdf")(Exploiting Windows Device Drivers).

SystemHandleInformation

Another interesting request type, already used by some rootkit detection mechanisms (RootkitAnalytics.com ("http://www.rootkitanalytics.com/userland/Hidden-Service-Detection.php")). The general purpose is providing information about all the active HANDLE objects present in the system memory. Performing a NtQuerySystemInformation(SystemHandleInformation,… will result in filling the output buffer with structures of the following definition:

Code:
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG* ProcessId;
UCHAR* ObjectTypeNumber;
UCHAR* Flags;
USHORT* Handle;
PVOID* Object;
ACCESS_MASK* GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
Not too many fields, this time; however, the most important part of the struct is present – PVOID Object. This is where we can find another kernel-mode pointer (inaccessible from user-mode, of course). Apart from the address itself, the HANDLE is also described with the creator process ID, type of the object and most importantly – the HANDLE value itself. Therefore, the object identification is very easy to perform and should not cause too much of a problem to the coder. More information will follow in the upcoming paper http://j00ru.vexillium.org/wp-includes/images/smilies/icon_smile.gif

SystemLocksInformation

This time, what we are getting is the information regarding locks used by the kernel. Locks in Windows are special “multiple reader single writer” synchronization mechanisms, otherwise known as “resources”.* The output structure definition follows:

Code:
typedef struct _SYSTEM_LOCK_INFORMATION {
PVOID* Address;
USHORT* Type;
USHORT* Reserved1;
ULONG* ExclusiveOwnerThreadId;
ULONG* ActiveCount;
ULONG* ContentionCount;
ULONG* Reserved2[2];
ULONG* NumberOfSharedWaiters;
ULONG* NumberOfExclusiveWaiters;
} SYSTEM_LOCK_INFORMATION, *PSYSTEM_LOCK_INFORMATION;
where the PVOID Address value points to a ERESOURCE structure in the kernel memory. These structures can be initialized using the ExInitializeResourceLite ("http://msdn.microsoft.com/en-us/library/ms797091.aspx")routine and are said to be documented in DDK (Windows NT 2000 Native API Reference).

These are, more or less, all the places (known by me), one can request K-M addresses from. Even though only three sources could seem to be little, it is enough to create a really impressive (imho) kernel memory map, as you will see in a few minutes. If you – the blog reader – are aware of any other kind of system information request leading to kernel address “leak”, please let me know through e-mail / post comments – I will be more than happy to add it to this list.

Processor specific structures

Apart from asking the system kernel to provide some information about its memory layout, one can also use direct application -> processor communication in order to read addresses related to some of the architectural structures that the system has to implement to work correctly. To be more precise, these structures are Global Descriptor Table ("http://en.wikipedia.org/wiki/Global_Descriptor_Table") (per processor/core) and Interrupt Descriptor Table ("http://en.wikipedia.org/wiki/Interrupt_descriptor_table") (per processor/core) plus structures implemented inside GDT (Task State Segment ("http://en.wikipedia.org/wiki/Task_State_Segment"), Local Descriptor Table ("http://en.wikipedia.org/wiki/Local_Descriptor_Table") etc).

To start playing with these structures, one should begin by reading Intel Software Developer’s Manuals: Volume 1 (Basic Architecture) and Volume 3A, 3B (System Programming Guide) – all of these can be found here ("http://www.intel.com/products/processor/manuals/"). The most interesting instructions here appear to be SGDT and SIDT, storing the GDTR and IDTR registers in user-specified memory.

What is more, the system itself also makes some segment-related API functions available; these are:


GetThreadSelectorEntry ("http://msdn.microsoft.com/en-us/library/ms679363(VS.85).aspx") – documented
NtSetLdtEntries – undocumented
?
It should be noted (once more), that each processor has its own GDT/IDT structure. Hence, in order to retrieve all the addresses possible, it is necessary to make sure that a specified thread/routine is executed in the context of a chosen processor. This can be achieved by using SetThreadAffinityMask ("http://msdn.microsoft.com/en-us/library/ms686247(VS.85).aspx") or SetProcessAffinityMask ("http://msdn.microsoft.com/en-us/library/ms686223(VS.85).aspx") API functions. Please refer to the KernelMAP source code to get more information about how to implement it in practice.

KernelMAP v0.0.1

Despite some strictly theoretical deliberations, I would also like to present a simple program of mine. Its main purpose is to gather all (or most, at least) information about kernel-mode memory layout and show it to the user in the most attractive way possible. The application consists of two windows: the first, text window prints some basic, statistical information based on the data provided by kernel. Second, graphical window is responsible for the real visualization. Its size is equal 1024512 (400200 hexdecimally), and every virtual page is represented by a single pixel on the board. These pixels have various colors associated to themselves, depending on what type of data the page in consideration contains.

As the above description might not give you any idea of how it looks like on a real system, some screenshots from various systems follow:

http://j00ru.vexillium.org/blog/04_01_10/Windows_XP_SP3.png ("http://j00ru.vexillium.org/blog/04_01_10/Windows_XP_SP3.png")

Windows XP SP3

http://j00ru.vexillium.org/blog/04_01_10/Windows_Vista_SP2.png ("http://j00ru.vexillium.org/blog/04_01_10/Windows_Vista_SP2.png")

Windows Vista SP2

http://j00ru.vexillium.org/blog/04_01_10/Windows_7_SP0.png ("http://j00ru.vexillium.org/blog/04_01_10/Windows_7_SP0.png")

Windows 7 SP0

Some strictly technical info: this program is designed to be compiled using MinGW GCC compiler and is probably not MS VC++ compatible. In order to make it work correctly, the program needs to find the SDL.dll, libpng3.dll and zlib1.dll libraries – you can find them inside the package.

A complete ZIP file, including the source code, executable and external DLL files can be downloaded from here ("http://j00ru.vexillium.org/blog/04_01_10/KernelMAP v0.0.1.zip") (387kB)

Since I am myself very curious about how the kernel memory layout looks like on different systems that I don’t have access to, you should feel encouraged to make your own shot and share (I hope this is not too much of information disclosure ;D). Furthermore, if you find any bugs in the existing code, or would like it to be extended with some additional functionalities (like new kernel addresses I don’t know about, yet), please let me know.

Every single comment is very welcome!

Have fun!



http://j00ru.vexillium.org/?p=269&lang=en

LaBBa
January 5th, 2010, 04:06
wow! this is looking very nice!!!
but can you explaing what we are seeing ? i mean i can see RED and GREEN and BLUE marks but what are they stand for ? more over what does the space between each mark stand for ?


Thanks,
LaBBa.

Kayaker
January 5th, 2010, 06:20

That was my initial thought too Labba, then I remembered Star Wars and "Use the Source Luke!".  The colors are listed there (color descriptions added by me using a color ref):





struct _AddressConf

{

  CHAR Name[256]; // XXX: should be always enough

  struct {BYTE r,g,b;} Color;

} AddressConf[] =

{

  {"UNKNOWN",{0x50,0x50,0x50}}, // black(ish)

  {"MODULE", {0xff,0x00,0x00}}, // red

  {"HANDLE", {0x00,0xff,0x00}}, // green

  {"LOCK",   {0x00,0x00,0xff}}, // blue

  {"GDT",    {0xff,0xff,0x00}}  // yellow,

  {"LDT",    {0x00,0xff,0xff}}, // cyan

  {"IDT",    {0xff,0x00,0xff}}  // pink

};





There's also output in the console window which is easy to miss since it's in the background.





Nice J00ru.  One quick thought I had, though I don't know if it adds to what you're aiming for. Some of the black "blanks" of the complete memory map might be filled in with the Paged/Unpaged pools, something along the lines of:



<div style="margin:20px; margin-top:5px"><div class="smallfont" style="margin-bottom:2px">Code:</div><pre class="alt2" style="margin:0px; padding:6px; border:solid 1px; width:90%; height:80px; overflow:auto"><div dir="ltr" style="text-align:left;">

KdDebuggerDataBlock = (PKDDEBUGGER_DATA64)GetKdDebuggerDataBlock();



// Get PagedPool limits

MmPagedPoolStart = *(ULONG*)KdDebuggerDataBlock-&gt;MmPagedPoolStart; // 0xE1000000

MmPagedPoolEnd = *(ULONG*)KdDebuggerDataBlock-&gt;MmPagedPoolEnd; // 0xEBFFFFFF

</div></pre></div>



Individual blocks, though perhaps an extreme step for the purposes, might be parsed out by following PoolHeader allocations within the region.  



KdDebuggerDataBlock is obtained from KdVersionBlock, which in turn is obtained from KPCR, or probably more legally from NtSystemDebugControl with DEBUG_CONTROL_CODE = 7 (DebugSysGetVersion). KdSystemDebugControl in Vista.  If I've got the details correct.  





btw, I apologize for the oversized png graphics in the rss imported blog, this post has made us realize vbulletin doesn't resize [IMG] tags, but we'll try to take care of that with the next forum upgrade coming soon.



Cheers,

Kayaker


Silkut
January 5th, 2010, 06:28
LaBBa, look at GlobalInformation.cpp =)

j00ru, Thanks for sharing the source over here.

EDIT:Ah speedy Kayaker got it first.

LaBBa
January 5th, 2010, 07:31
Thanks.
I will next time i'm not used to have the code .. allways reversing for it

j00ru
January 5th, 2010, 14:22
Hi there!

I'm really glad you like the tool ;>
Yep, I forgot to mention what do the colors mean, however I can see the case is already solved the source code doesn't bite, even the RE-s

@Kayaker:
Thanks for your message. However, I'm not really sure if what you have written is possible to be performed from within user-mode. I've read some info about the mentioned NtSystemDebugControl routine.

YES, it is possible to retrieve the KdVersionBlock data (0x28 bytes long) using the DebugSysGetVersion (7) code. The structure's definition is as follows:
Code:
typedef struct _DBGKD_GET_VERSION64 {
USHORT MajorVersion;
USHORT MinorVersion;
UCHAR ProtocolVersion;
UCHAR KdSecondaryVersion; // Cannot be 'A' for compat with dump header
USHORT Flags;
USHORT MachineType;

//
// Protocol command support descriptions.
// These allow the debugger to automatically
// adapt to different levels of command support
// in different kernels.
//

// One beyond highest packet type understood, zero based.
UCHAR MaxPacketType;
// One beyond highest state change understood, zero based.
UCHAR MaxStateChange;
// One beyond highest state manipulate message understood, zero based.
UCHAR MaxManipulate;

// Kind of execution environment the kernel is running in,
// such as a real machine or a simulator. Written back
// by the simulation if one exists.
UCHAR Simulation;

USHORT Unused[1];

ULONG64 KernBase;
ULONG64 PsLoadedModuleList;

//
// Components may register a debug data block for use by
// debugger extensions. This is the address of the list head.
//
// There will always be an entry for the debugger.
//

ULONG64 DebuggerDataList;

} DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64;

Moreover YES, it is possible to get the address of KdDebuggerDataBlock (it is present in the DebuggerDataList field plus it is placed right after KdVersionBlock in the systems I tested). However, I cannot see any way of obtaining the Data Block content from application level.

You referred to some GetKdDebuggerDataBlock (dummy?) function... Again, I would be very happy to find such a routine in UM libraries - the paged memory ranges, together with other info present in this structure would be very useful.

Since the major purpose is to present the possible ways of gathering information about the kernel memory layout (presumably before some ring-0 vulnerability exploitation), we assume that the user has minimum privileges. Hence, ring-0 code is not the case.

Cheers,
j00ru//vx

Kayaker
January 5th, 2010, 19:24
Oh, that damn pesky user mode limitation. Yeah, I try to avoid that wherever possible

I understand and you're right, the useful info stops at KdDebuggerDataBlock then in UM.

If I can continue to be annoying though , the PngFile.SetPixel function seems to be based on a system address range that starts at 0x80000000, which is what we're all used to, but a more rigorous method might be as mentioned in

http://ericuday.googlepages.com/EICAR2008_UserMode_Memory_Scanning_3.doc

Quote:

Usually the system address range begins at 0x80000000. However, it is not right to assume this because of the ability to boot Windows with the /3GB boot.ini switch. In order to determine the correct system address range start address, we can use the native API call to NtQuerySystemInformation (exported by ntdll.dll) with the SystemInformationClass parameter set to SystemRangeStartInformation sub-function (whose information class number is 50).






This is sort of off topic now, but in case anyone is interested the dummy GetKdDebuggerDataBlock() function from above is just:

Code:


/////////////////////////////////////////////////////////////////////
//
// GetKdVersionBlock
//
/*

For XP and above only!

For full explanation of how these structures relate to each other, see

How to get some hidden kernel variables without scanning by Opc0de
http://www.rootkit.com/newsread.php?newsid=101

Getting Kernel Variables from KdVersionBlock, Part 2 by Alex Ionescu
http://www.rootkit.com/newsread.php?newsid=153



KdVersionBlock field is only valid in the 1st processor KPCR,
so we use KeSetSystemAffinityThread to set to CPU 0. See

Multi-Processors and KdVersionBlock
http://www.msuiche.net/2009/01/05/multi-processors-and-kdversionblock/


One could also use:

KAFFINITY AffinityMask;
AffinityMask = (1 << ProcessorNumber);

ZwSetInformationThread(ThreadHandle, // IN HANDLE ThreadHandle
ThreadAffinityMask, // IN THREADINFOCLASS ThreadInformationClass
&Affinity, // IN PVOID ThreadInformation
sizeof(KAFFINITY)); // IN ULONG ThreadInformationLength



Under a MP/HT system, the multiple _KPRCB addresses are found in KiProcessorBlock
kd> dd KiProcessorBlock

*/

/////////////////////////////////////////////////////////////////////

PDBGKD_GET_VERSION64 GetKdVersionBlock()
{

UCHAR ProcessorNumber = 0;
// PKPCR pKpcr = (PKPCR)0xffdff000;
PKPCR SelfPcr;
PDBGKD_GET_VERSION64 KdVersionBlock;

/////////////////////////////////////////////////////

// Set the system affinity of the current thread
// (set to first processor for multiprocessor systems)

KeSetSystemAffinityThread ((KAFFINITY) (1 << ProcessorNumber));

// Get pointer to KPCR

_asm{
mov eax, fs:[0x1C] // _KPCR.SelfPcr
mov SelfPcr, eax
}

// Get KdVersionBlock ([eax + 34])

KdVersionBlock = (PDBGKD_GET_VERSION64)SelfPcr->KdVersionBlock;

// Restore the previous affinity of the current thread

KeRevertToUserAffinityThread();

return KdVersionBlock; // 0x8054C738
}

/////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////
// GetKdDebuggerDataBlock
//
// Returns the value of the kernel variable KdDebuggerDataBlock
//
// See IG_GET_KERNEL_VERSION
// http://msdn.microsoft.com/en-us/library/cc267894.aspx
//
/////////////////////////////////////////////////////////////////////

PKDDEBUGGER_DATA64 GetKdDebuggerDataBlock()
{

PDBGKD_GET_VERSION64 KdVersionBlock;
ULONG64 KdpDebuggerDataListHead; // LIST_ENTRY
PKDDEBUGGER_DATA64 KdDebuggerDataBlock;

/////////////////////////////////////////////////////

// Get KdVersionBlock
KdVersionBlock = (PDBGKD_GET_VERSION64)GetKdVersionBlock();

KdpDebuggerDataListHead = KdVersionBlock->DebuggerDataList;

KdDebuggerDataBlock = *(PKDDEBUGGER_DATA64*)KdpDebuggerDataListHead;

return KdDebuggerDataBlock; // 0x8054C760
}

/////////////////////////////////////////////////////////////////////


j00ru
January 6th, 2010, 14:39
Hi, thanks for your reply!

Quote:
[Originally Posted by Kayaker;84538]
If I can continue to be annoying though , the PngFile.SetPixel function seems to be based on a system address range that starts at 0x80000000, which is what we're all used to, but a more rigorous method might be as mentioned in

http://ericuday.googlepages.com/EICAR2008_UserMode_Memory_Scanning_3.doc

Haha, the more annoying you are, the more I am learning. You are certainly right at this point; I always forget to add the /3G switch support to kernel-related applications.
However, having the kernel memory address range start at 0xC0000000, the application is expected to use the bottom half of the window, still creating a tighter visualization (tho wasting the other half of user screen). Anyway, I'll fix it in the next version, if one will come

Furthermore, thanks for the GetKdDebuggerDataBlock function - I honestly haven't had any idea of how much usable information is stored in the kernel, in one place.

One more thing I wrote no word about: the KernelMAP application doesn't take the Win32-subsystem (win32k.sys) object addresses into consideration. This will also, hopefully, change in the next version as I get some more information about those
So... stay tuned!