Hi All,
Is KeServiceDescriptorTableShadow a per-process structure?
How the kernel changes the table when it calls GDI or user function(ie. from KeServiceDescriptorTable to KeServiceDescriptorTableShadow)?
Thanks & Regards,
Amit.
Hi All,
Is KeServiceDescriptorTableShadow a per-process structure?
How the kernel changes the table when it calls GDI or user function(ie. from KeServiceDescriptorTable to KeServiceDescriptorTableShadow)?
Thanks & Regards,
Amit.
Hello,
this might help you:
http://www.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/17-Win32K/Win32K.pdf
> Is KeServiceDescriptorTableShadow a per-process structure?
It is not…
How the kernel changes the table when it calls GDI or user function(ie. from
KeServiceDescriptorTable to KeServiceDescriptorTableShadow)?
It does not change anything - depending on the service index, it looks for a pointer to the service implementation either in KeServiceDescriptorTable or in KeServiceDescriptorTableShadow
Anton Bassov
>
> How the kernel changes the table when it calls GDI or user function(ie.
from
> KeServiceDescriptorTable to KeServiceDescriptorTableShadow)?It does not change anything - depending on the service index, it looks for
a pointer to the service implementation either in KeServiceDescriptorTable
or in KeServiceDescriptorTableShadow
not very accurately,as Microsoft in win32k.pdf said,when the thread is
created,the KTHREAD->ServiceTable initialized to KeServiceDescriptorTable
.when the thread first calls to win32k.sys,KTHREAD->ServiceTable is
replaced by KeServiceDescriptorTableShadow.
KeServiceDescriptorTable and KeServiceDescriptorTableShadow aren’t changed,
but the KTHREAD->ServiceTable is changed.
> not very accurately,as Microsoft in win32k.pdf said,when the thread is
created,the KTHREAD->ServiceTable initialized to KeServiceDescriptorTable
.when the thread first calls to win32k.sys,KTHREAD->ServiceTable is
replaced by KeServiceDescriptorTableShadow.
KeServiceDescriptorTable and KeServiceDescriptorTableShadow aren’t changed,
but the KTHREAD->ServiceTable is changed.
Could you please provide a link to the doc - unfortunately, if you search MSFT site for KeServiceDescriptorTableShadow, it does not return any results (all info about it seems to be available only from non-MSFT sources)…
Apparently, you just misunderstood something that you have heard from the third-party sources.
All you have to do is to disassemble the service dispatcher, so that you will have a chance to see how things are handled. You will see that service index is shifted 8 bits to the right and ANDed with 0x30. It is understandable that if index is below 0x1000 (i.e. service is implemented by ntoskrnl.exe) the resulting value is zero, and if its >= 0x1000 (i.e. service is implemented by win32k.sys) the resulting value is non-zero. By adding this value to KTHREAD->ServiceTable you get a pointer to the array where adresses of functions are stored. As you can see, KeServiceDescriptorTable is *NOT* replaced by KeServiceDescriptorTableShadow on a call to win32k.sys - the system arrives to the correct table right from the service index.
Apparently, you have just confused KeServiceDescriptorTableShadow with the user-mode GDI handle table. Probably, you know that a read-only copy of GDI handle table is saved
in the user address space, and this table, indeed, gets set up only upon the first call to win32k.sys
Therefore, if service index is above 0x1000 ( i.e.the target service is implemented by win32k.sys), the system checks some certain value in value in the *user-mode* TIB structure, and if it is zero, calls win32k.sys before proceeding to the actual call. Apparently, this is what you referred to in your post…
Anton Bassov
>
Could you please provide a link to the doc - unfortunately, if you search
MSFT site for KeServiceDescriptorTableShadow, it does not return any results
(all info about it seems to be available only from non-MSFT sources)…
you don’t see the first reply. i past the link again :
http://www.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/17-Win32K/Win32K.pdf
.
it is from ms.
Apparently, you just misunderstood something that you have heard from the
third-party sources.
All you have to do is to disassemble the service dispatcher, so that you
will have a chance to see how things are handled. You will see that service
index is shifted 8 bits to the right and ANDed with 0x30. It is
understandable that if index is below 0x1000 (i.e. service is implemented
by ntoskrnl.exe) the resulting value is zero, and if its >= 0x1000 (i.e.
service is implemented by win32k.sys) the resulting value is non-zero. By
adding this value to KTHREAD->ServiceTable you get a pointer to the array
where adresses of functions are stored. As you can see,
KeServiceDescriptorTable is *NOT* replaced by
KeServiceDescriptorTableShadow on a call to win32k.sys - the system
arrives to the correct table right from the service index.
perhaps i didn’t said clearly in previous reply. i never say
KeServiceDescriptorTable is replaced by KeServiceDescriptorTableShadow. i
try to depict it more clearly. KTHREAD->ServiceTable is the pointer ,it is
initialized to the addresss of KeServiceDescriptorTable when thread is
created.when the thread first calls to win32k.sys,
as you say, when service index is shifted 8 bits to the right and ANDed with
0x30,if its >= 0x1000,the resulting value is non-zero,By adding this value
to KTHREAD->ServiceTable you get a pointer to the array where adresses of
functions are stored. but stop, there is a problem that in the sentence
“By adding this value to KTHREAD->ServiceTable you get a pointer to the
array where adresses of functions are stored”. in fact,you can’t succeed so
easily. remember ,KTHREAD->Service now is the pointer to
KeServiceDescriptorTable,by add 10h,you get the second item in
KeServiceDescriptorTable, i dump KeServiceDescriptorTable im my machine.
lkd> dd nt!KeServiceDescriptorTable
8055a680 81f75008 00000000 00000129 81f49d30
8055a690 00000000 00000000 00000000 00000000
the second item from 8055a690h is all zero of 4 dwords.
you can see the disassembled code,
cmp eax,dword ptr [edi+8]
jae nt!KiBBTUnexpectedRange (804df4e2)
now eax is 1xxxx, edi is 8055a690, [edi+8] is 0,so the cpu jump to
nt!KiBBTUnexpectedRange , it will call nt!PsConvertToGuiThread, it is in
PsConvertToGuiThread that the KTHREAD->Service is changed to the address of
KeServiceDescriptorTableShadow. you can disassemble iPsConvertToGuiThread to
verify it.I also dump KeServiceDescriptorTableShadow, compared to
KeServiceDescriptorTable
dd nt!KeServiceDescriptorTableShadow
8055a640 81f75008 00000000 00000129 81f49d30
8055a650 bf999280 00000000 0000029b bf999f90
to win32k function,you can’t get a pointer to the array where adresses of
functions are stored until now
i emphasize that KTHREAD->Service is change from the address of
KeServiceDescriptor to that of TableKeServiceDescriptorTableShadow when
thread first calls to win32k.sys.
Anton Bassov,do you agree with me ?
danny
> but stop, there is a problem that in the sentence
“By adding this value to KTHREAD->ServiceTable you get a pointer to the
array where adresses of functions are stored”.
Sure - I should have said “By adding this value to KTHREAD->ServiceTable you get a pointer to the location where a pointer to the array of function addresses is stored”. I realized my typing mistake after having made the post - I just assumed that you would disassemble service dispatcher and understand what I mean, so I could not be bothered to make a new post with a correction . However, it is obvious from your post that you either did not do this part, or just failed to understand what happens there…
Basically, the most relevant parts of the code stand as following:
MOV EBX, FS:[0x1C] ; load a pointer to thread-specific data into EBX
MOV ESI, [EBX+0x124]; load a pointer to KTHREAD into ESI
…
MOV EDI, EAX; load service index to EDI
SHR EDI,8
AND EDI, 0x30;
At this point EDI is zero if index is below 0x1000 and non-zero if it >= 0x1000
AND EAX, 0xFFF
CMP eax, [EDX+8]; check if service index is within the table limit
JAE invalid location;
MOV ECX, EDI; save EDI in ECX for subsequent check;
ADD EDI, [ESI+0xE0] ; add KTHREAD->ServiceTable to processed index in EDI
It is understandable that the current value of EDI depends on whether the service index is >= 0x1000 - if it is not, EDI holds the value of KTHREAD->ServiceTable, and if it is, EDI holds the value of (0x10+ KTHREAD->ServiceTable). At this point EDI holds a pointer to the location where a pointer to the array of function addresses is stored - you will see it shortly.
CMP ECX,0x10
JNE proceed; skip the check if ECX is zero, i.e. service index <0x1000
MOV ECX, FS:[0x18]; load a pointer to user-mode TEB into ECX
XOR EBX, EBX
OR EBX, [ECX+0xF70] ; check TEB whether a call to win32k. sys is needed
JZ proceed
call win32K.sys
Please note that even if a call to win32k is made, EDI, [EDI] and [ESI+0xE0] are still going to stay the same, although [TEB+0xF70] gets changed, for understandable reasons
proceed: MOV EDI, [EDI]; load a pointer to the array of function addresses into EDI
MOV EBX, [EAX*4+EDI]; load the target function address into EBX
CALL EBX
I hope now you understand that nothing gets swapped here even of the first call to win32k.sys, because EDI, [EDI] and [ESI+0xE0] are going to stay the same even if a call to win32k.sys is made. Instead, everyhing depends solely on the service index - if it is >=0x1000, you just arrive to different array of function addresses
you can see the disassembled code,
cmp eax,dword ptr [edi+8]
jae nt!KiBBTUnexpectedRange (804df4e2)
now eax is 1xxxx, edi is 8055a690, [edi+8] is 0,so the cpu jump to
nt!KiBBTUnexpectedRange , it will call nt!PsConvertToGuiThread, it is in
PsConvertToGuiThread that the KTHREAD->Service is changed to the address of
KeServiceDescriptorTableShadow.
The above statement is just one more proof to the fact that you either did not do disassembly, or just unable to understand disassembled code…
In actuality, the code that you mentioned is nothing more than a simple validation - it just checks whether the service index is within the table limits. If it is not, the execution will, indeed, jump to KiBBTUnexpectedRange, so that you will get an error - it has nothing to do with PsConvertToGuiThread.
i emphasize that KTHREAD->Service is change from the address of
KeServiceDescriptor to that of TableKeServiceDescriptorTableShadow when
thread first calls to win32k.sys.
Just do some disassembly, and you will see that you are wrong.
Anton Bassov
CORRECTION!!!
Again, I made a typing mistake - the code below is wrong
[begin quote]
AND EAX, 0xFFF
CMP eax, [EDX+8]; check if service index is within the table limit
JAE invalid location;
MOV ECX, EDI; save EDI in ECX for subsequent check;
ADD EDI, [ESI+0xE0] ; add KTHREAD->ServiceTable to processed index in EDI
[end quote]
In actuality, it should be written as
[begin quote]
MOV ECX, EDI; save EDI in ECX for subsequent check;
ADD EDI, [ESI+0xE0] ; add KTHREAD->ServiceTable to processed index in EDI
AND EAX, 0xFFF
CMP eax, [EDI+8]; check if service index is within the table limit
JAE invalid location;
[end quote]
Anton Bassov
Actually, Anton, Mr. Zhao is entirely correct… The behavior is well documented.
The original service table is used until the thread is converted to a “GUI Thread” on its first Win32 call. After that time, it uses the shadow table.
BTW, the series of slides presented by Dave Probert at Tokyo University (from which the referenced module is taken) contain some of the most detailed documentation of the internals of Windows that I’ve ever seen. Well worth finding and reading.
Peter
OSR
Couldn’t agree more, Peter, particularly about the internals part.
Didn’t really ever expect to see much from an official source on the
user mode callback process, for example.
mm
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@osr.com
Sent: Saturday, June 23, 2007 15:13
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] KeServiceDescriptorTableShadow?
Actually, Anton, Mr. Zhao is entirely correct… The behavior is well
documented.
The original service table is used until the thread is converted to a
“GUI Thread” on its first Win32 call. After that time, it uses the
shadow table.
BTW, the series of slides presented by Dave Probert at Tokyo University
(from which the referenced module is taken) contain some of the most
detailed documentation of the internals of Windows that I’ve ever seen.
Well worth finding and reading.
Peter
OSR
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
Peter,
Actually, Anton, Mr. Zhao is entirely correct…
In fact, this in not the case - he just heard that something happens upon the first call to user/gdi functions, and decided that service tables get swapped.
Let me explain how it actually works.
Both KeServiceDescriptorTable and KeServiceDescriptorTableShadow are service tables, described by the following stucture:
struct SYS_SERVICE_TABLE {
void **ServiceTable;
unsigned long CounterTable;
unsigned long ServiceLimit;
void **ArgumentsTable;
};
KTHREAD->ServiceTable points to the array of these structures that may have either 1 or 2 entries - the first is always KeServiceDescriptorTable, and, in the latter case, the second one is KeServiceDescriptorTableShadow. When thread gets created, its KTHREAD->ServiceTable points to the array with a single entry. When it makes its very first GUI-related call, service index happens to be out of the table limits, which results in an error. After having done all necessary validation, an error handler updates KTHREAD->ServiceTable, so that, from now on, it points to the array of 2 structures.
From now on, whenever a thread makes a system call, EDI points to the beginning of either first or second structure in the array, i.e. to KeServiceDescriptorTable->ServiceTable or KeServiceDescriptorTableShadow-> ServiceTable( earlier on this thread I have explained how it arrives to the right structure via the service index). Please note that service index gets ANDed with 0xFFF before being used for getting the function address from the table. Therefore, service indexes of, say, 0x5 and 0x1005 produce identical results, but in former case the address of service implementation may be found in the fifth entry of KeServiceDescriptorTable, and in the latter one the address of service implementation may be found in the fifth entry of KeServiceDescriptorTableShadow.
As you can see, KeServiceDescriptorTable does not go away even after thread gets converted to GUI one - kernel32 services are still being invoked via it .
Anton Bassov
>
> you can see the disassembled code,
> cmp eax,dword ptr [edi+8]
> jae nt!KiBBTUnexpectedRange (804df4e2)
> now eax is 1xxxx, edi is 8055a690, [edi+8] is 0,so the cpu jump to
> nt!KiBBTUnexpectedRange , it will call nt!PsConvertToGuiThread, it is in
> PsConvertToGuiThread that the KTHREAD->Service is changed to the address
of
> KeServiceDescriptorTableShadow.The above statement is just one more proof to the fact that you either did
not do disassembly, or just unable to understand disassembled code…In actuality, the code that you mentioned is nothing more than a simple
validation - it just checks whether the service index is within the table
limits. If it is not, the execution will, indeed, jump to
KiBBTUnexpectedRange, so that you will get an error - it has nothing to do
with PsConvertToGuiThread.
l past KiBBTUnexpectedRange
nt!KiBBTUnexpectedRange:
804df4e2 83f910 cmp ecx,10h
804df4e5 7539 jne nt!KiBBTUnexpectedRange+0x3e (804df520)
804df4e7 52 push edx
804df4e8 53 push ebx
804df4e9 e8afd90900 call nt!PsConvertToGuiThread (8057ce9d)
804df4ee 0bc0 or eax,eax
804df4f0 58 pop eax
804df4f1 5a pop edx
do you disaasemble this code? do you understand this code?
danny
> Let me explain how it actually works.
Both KeServiceDescriptorTable and KeServiceDescriptorTableShadow are
service tables, described by the following stucture:struct SYS_SERVICE_TABLE {
void **ServiceTable;
unsigned long CounterTable;
unsigned long ServiceLimit;
void **ArgumentsTable;
};KTHREAD->ServiceTable points to the array of these structures that may
have either 1 or 2 entries - the first is always KeServiceDescriptorTable,
and, in the latter case, the second one is
KeServiceDescriptorTableShadow. When thread gets created, its
KTHREAD->ServiceTable points to the array with a single entry. When it makes
its very first GUI-related call, service index happens to be out of the
table limits, which results in an error. After having done all necessary
validation, an error handler updates KTHREAD->ServiceTable, so that, from
now on, it points to the array of 2 structures.From now on, whenever a thread makes a system call, EDI points to the
beginning of either first or second structure in the array, i.e.
to KeServiceDescriptorTable->ServiceTable
or KeServiceDescriptorTableShadow-> ServiceTable( earlier on this thread I
have explained how it arrives to the right structure via the service
index). Please note that service index gets ANDed with 0xFFF before being
used for getting the function address from the table. Therefore, service
indexes of, say, 0x5 and 0x1005 produce identical results, but in former
case the address of service implementation may be found in the fifth entry
of KeServiceDescriptorTable, and in the latter one the address of service
implementation may be found in the fifth entry of
KeServiceDescriptorTableShadow.As you can see, KeServiceDescriptorTable does not go away even after
thread gets converted to GUI one - kernel32 services are still being invoked
via it .
I only want to remind you that:
struct SYS_SERVICE_TABLE KeServiceDescriptorTable[4];
struct SYS_SERVICE_TABLE KeServiceDescriptorTableShadow[4];
i hope when you know this, you will understand the mistake you made.
danny
> I only want to remind you that:
struct SYS_SERVICE_TABLE KeServiceDescriptorTable[4];
struct SYS_SERVICE_TABLE KeServiceDescriptorTableShadow[4];
Actually, you are right…
For this ot that reason, I have always thought of KeServiceDescriptorTable and KeServiceDescriptorTableShadow just of SYS_SERVICE_TABLE entry (probably because,
in practical terms, SYS_SERVICE_TABLE is the only thing that matters, as far as system calls are concerned)…
In any case, thank you for this discussion - I just love “arguments” that make me do some disassembly in order to prove my point, even if in the end of the day it turns out that I was wrong. On this particular occasion I had to disassemble the service dispatcher and analyze all its internal details…
Anton Bassov
if we can learn more from arguments, it is valuable and welcome.
i enjoy disassembling code over 10 years.i like to discuss the question
about disassemble.
danny
On 6/25/07, xxxxx@hotmail.com wrote:
>
> > I only want to remind you that:
> > struct SYS_SERVICE_TABLE KeServiceDescriptorTable[4];
> > struct SYS_SERVICE_TABLE KeServiceDescriptorTableShadow[4];
>
> Actually, you are right…
>
> For this ot that reason, I have always thought of KeServiceDescriptorTable
> and KeServiceDescriptorTableShadow just of SYS_SERVICE_TABLE entry (probably
> because,
> in practical terms, SYS_SERVICE_TABLE is the only thing that matters, as
> far as system calls are concerned)…
>
> In any case, thank you for this discussion - I just love “arguments” that
> make me do some disassembly in order to prove my point, even if in the end
> of the day it turns out that I was wrong. On this particular occasion I had
> to disassemble the service dispatcher and analyze all its internal
> details…
>
> Anton Bassov
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
Very good and knowledgably discussion!
Now, carefully understand my problem.
There are some hidden files. The files are made hidden by software by hooking system service.
But I observed that the files are hidden from GUI threads and not from simple thread. (As the files are hidden from explorer but visible in command prompt.)
This implies that the hook is applied in KeServiceDescriptorTableShadow. ie. the page that contain system services in KeServiceDescriptorTableShadow and KeServiceDescriptorTable are different.
I want to know that, is this page allocated per process or it is system wide?
> This implies that the hook is applied in KeServiceDescriptorTableShadow.
I am afraid no one is going to help you here…
In general, as you must have noticed, hooking service tables is the kind of technique that is normally frowned upon, although there are some cases when hooking SSDT may be needed. However, this is not only the question of the technique in itself, but also of general objectives of those who implement it. As I can see, you are hiding files. The only type of “software” that does it is generally known as *MALWARE*, so that no one here is going to help you with it…
Anton Bassov
Miss understanding!
You are right that software is MALWARE.
But I am not the developer of it.
Actually I am working in a security company and on Anti Rootkit project.
While analyzing rootkit I found this situation.
> This implies that the hook is applied in KeServiceDescriptorTableShadow. ie. the
page that contain system services in KeServiceDescriptorTableShadow and
KeServiceDescriptorTable are different.
Under the normal circumstances it should not happen - the first entry is the same for KeServiceDescriptorTable and KeServiceDescriptorTableShadow. Actually, this is the reason why our discussion with Danny had started, in the first place - I had always (mistakenly) thought of KeServiceDescriptorTable and KeServiceDescriptorTableShadow just as of SYS_SERVICE_TABLE structure, so that I referred to the actual KeServiceDescriptorTable and KeServiceDescriptorTableShadow as “arrays” on this thread.
This is how it *normally*works. However, once rootkit is around, your situation is different - it can do everything it wants. Probably, it just replaced ServiceTable field of KeServiceDescriptorTable with its own array, but did not do it to KeServiceDescriptorTableShadow. Taking into account the fact that KeServiceDescriptorTable is exported and KeServiceDescriptorTableShadow is not, this is the most likely scenario.
Anton Bassov