您的位置:首页 > 大数据 > 人工智能

Obtaining KeServiceDescriptorTableShadow address

2008-06-30 23:06 330 查看
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:[code]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.
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐