原创 Obtaining KeServiceDescriptorTableShadow address

2008-4-29 18:08 4576 7 7 分类: 软件与OS

In Windows NT based operating system every
system call originated in user mode which is to be processed
by the system抯 kernel must go through the gate to the kernel
itself where it would be dispatched and executed. This gate
is an interrupt INT 2Eh. While on the user side library
ntdll.dll handles a system call, after passing the gate
ntoskrnl.exe takes over invoking an internal function KiSystemService()
and passing the original system call into it. Then, KiSystemService
uses a lookup table for the information on which Native
API call to assign the original call to. This lookup table
is called System Service Table (SST), it has the following
structure:


typedef NTSTATUS (NTAPI * NTPROC) ();
typedef NTPROC * PNTPROC;
#define NTPROC_ sizeof (NTPROC)

typedef struct _SYSTEM_SERVICE_TABLE
{
PNTPROC ServiceTable; // array of entry points to the calls
PDWORD CounterTable; // array of usage counters
DWORD ServiceLimit; // number of table entries
PBYTE ArgumentTable; // array of arguments
}
SYSTEM_SERVICE_TABLE,
*PSYSTEM_SERVICE_TABLE,
**PP SYSTEM_SERVICE_TABLE;

System Service Table itself is a member
of another structure called Service Descriptor Table:


typedef struct _SERVICE_DESCRIPTOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnl; //SST used by ntoskrnl.exe - Native API
SYSTEM_SERVICE_TABLE win32k; // SST used by win32k.sys - gdi/user support
SYSTEM_SERVICE_TABLE Table3; // reserved
SYSTEM_SERVICE_TABLE Table4; // reserved
}
SERVICE_DESCRIPTOR_TABLE,
*PSERVICE_DESCRIPTOR_TABLE,
**PPSERVICE_DESCRIPTOR_TABLE;

System Service Table structure is used
by two different handles in the Kernel:




  • KeServiceDescriptorTable()


  • KeServiceDescriptorTableShadow()



点击看大图

While KeServiceDescriptorTable is readily available
for kernel mode drivers to access, KeServiceDescriptorTableShadow
is not. Moreover, KeServiceDescriptorTable does not have the
System Service Table for win32k calls support.


Unfortunately, different versions of Windows
NT have these two tables placed in different order. For
example, on Windows 2000, KeServiceDescriptorTableShadow
follows immediately after KeServiceDescriptorTable, while
on Windows XP it appears right before KeServiceDescriptorTable.



Several different ways have been proposed to
obtain the correct address of the Shadow table. In this example
I shall demonstrate an approach to obtain the KeServiceDescriptorTableShadow
address on Windows 2000 and Windows XP (incl. SP1) operating
systems.


The idea behind this method (originally introduced
in the book Undocumented Windows NT) is to use a function
called KeAddSystemServiceTable as an indicator. This function
is used by win32k.sys and therefore it just has to address
the Shadow table since KeServiceDescriptorTable does not
support win32k calls. Another assumption to be made is that
the first entry in both KeServiceDescriptorTable and KeServiceDescriptorTableShadow
is the same. Since it is relatively simple to obtain the
address of KeServiceDescriptorTable, we may try to compare
its first entry with the one obtained from KeAddSystemServiceTable.
If they match, we consider the corresponding address to
be the correct address of KeServiceDescriptorTableShadow.
There is no guaranty that the very first valid address,
produced by KeAddSystemServiceTable will match, thus we
have to go through several addresses to find the right one.


The following code shows a correct solution
for obtaining a KeServiceDescriptorTableShadow address on
windows XP, it will work for a kernel mode device driver:



/* 
define structure for the system service table
*/

struct SYS_SERVICE_TABLE {
void **ServiceTable;
unsigned long CounterTable;
unsigned long ServiceLimit;
void **ArgumentsTable;
};
/*
Define KeServiceDescriptorTable based on the SST structure
*/

extern struct SYS_SERVICE_TABLE *KeServiceDescriptorTable;
/*
Declare function GetServiceDescriptorShadowTableAddress()
*/

static struct SYS_SERVICE_TABLE * GetServiceDescriptorShadowTableAddress ();
/*
Declare the KeAddSystemServiceTable. This is just a
handle to the call function, it will be used by the function
above to obtain the correct address of the KeServiceDescriptorShadowTable
*/

__declspec(dllimport) KeAddSystemServiceTable (ULONG, ULONG, ULONG, ULONG, ULONG);
static struct SYS_SERVICE_TABLE * GetServiceDescriptorShadowTableAddress ()
{
// First, obtain a pointer to KeAddSystemServiceTable
unsigned char *check = (unsigned char*)KeAddSystemServiceTable;
int i;
//Initialize an instance of System Service Table, will be used to
//obtain an address from KeAddSystemServiceTable
struct SYS_SERVICE_TABLE *rc=0;
// Make 100 attempts to match a valid address with that of KeServiceDescriptorTable
for (i=0; i<=99; i++) {
__try {
// try to obtain an address from KeAddSystemServiceTable
rc = *(struct SYS_SERVICE_TABLE**)check;
// if this address is NOT valid OR it itself is the address of
//KeServiceDescriptorTable OR its first entry is NOT equal
//to the first entry of KeServiceDescriptorTable
if (!MmIsAddressValid (rc) || (rc == KeServiceDescriptorTable)
|| (memcmp (rc, KeServiceDescriptorTable, sizeof (*rc)) != 0)) {
// Proceed with the next address
check++;
// don't forget to reset the old address
rc = 0;
}
} __except (EXCEPTION_EXECUTE_HANDLER) { rc = 0; }
// when the loop is completed, check if it produced a valid address
if (rc)
// because if it didn't, we failed to find the address of KeServiceDescriptorTableShadow
break;
}
// otherwise, there is a valid address! So return it!
return rc;
}

Note, that if you by some reason failed to
find the correct address, your number of iterations (100
in my example) was not enough. Try to increase it slightly,
I would not recommend to have the number of iterations larger
than 4096, if you failed again even with the number that
high, there are definitely other problems, most likely the
assumptions mentioned above are no longer true for the operation
system you use.



To call this function, simply create a new
pointer to System Service Table with the same structure the
function returns its address with, and then assign this address
to it:



/*
define structure for the system service table
*/

struct SYS_SERVICE_TABLE {
void **ServiceTable;
unsigned long CounterTable;
unsigned long ServiceLimit;
void **ArgumentsTable;
};

static struct SYS_SERVICE_TABLE *ShadowTable;
ShadowTable = GetServiceDescriptorShadowTableAddress();

Needless to say, that all these tricks can only be done with administrator rights. More over,
if you plan to continue manipulating KeServiceDescriptorTableShadow, you will also need to enable
Debug Privileges, even for the administrator.


文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条