Kayaker
May 4th, 2004, 02:19
Hi All
I am going to do something I truly hope no one takes offense to. A few months back, on another forum, there was an interesting discussion concerning the KeServiceDescriptorTableShadow. Recently someone asked another question on the subject, and due to apparent policy changes on that forum, the thread was deleted.
I have absolutely no argument with this decision, they have their rules and regulations designed to protect their board, we have ours. However, I like to encourage these types of discussions on this board, and in the interest of keeping undocumented kernel programming knowledge freely available to all, I would like to resurrect the bulk of that thread and its attachments.
Understand that I'm not trying to play one-upmanship on another forum that I respect and enjoy participating in, my only desire is to preserve and encourage discussions on undocumented system programming issues. If anyone objects they are free to PM me. Here are the relevant posts from that thread for posterity.
Regards,
Kayaker
=================================================================================
Posted by Opcode:
In WindowsXP I found the KeServiceDescriptorTable pointer in a member of the KTHREAD Structure.
In the file Ntundoc.inc written by Four-F , I found it at offset 0xdc, but in XP it is in the offset 0xe0.
Appears to me that KTHREAD structure changed from windows2k to XP.
How can I find the KeServiceDescriptorTableShadow that is exported by Win32K.sys ?
=================================================================================
Posted by Kayaker:
Hi
>KeServiceDescriptorTable .. I found it at offset 0xdc, but in XP it is in the offset 0xe0.
>Appears to me that KTHREAD structure changed from windows2k to XP.
>How can I find the KeServiceDescriptorTableShadow that is exported by Win32K.sys
I think you just did. I had read that there was a change between Win2K sp1 and sp3 and the KeServiceDescriptorTable is now a per-process one. The first time a thread calls a Win32 GUI service, its system service table is changed to one that includes the GDI and USER services in Win32k.sys. This new service table contains pointers to both the ntoskrnl call table and to the win32k table. I've played with this to add new Int2E services to the ntoskrnl table, as far as I know the win32k.sys portion is what is used for any of the user services as well (Service ID > 1000), so I think there's no need to 'hunt' for the KeServiceDescriptorTableShadow.
Here's some code I've used for Win2K, things might be slightly different for XP.
ServiceDescriptorTable structure:
--------------------------
;typedef struct ServiceDescriptorTable {
;PVOID ServiceTableBase;
;PVOID ServiceCounterTable(O); • j •
;unsigned int NumberOfServices;
;PVOID ParamTableBase;
ServiceTableBase (SSDT) - points to a table of pointers to each ntoskrnl (or win32k.sys) function starting address
ServiceCounterTable - only used in debug builds, for us contains 0
NumberOfServices - 0F8h for Win2K sp3
ParamTableBase (SSPT) - points to a table containing the number of parameter *bytes* for each matching SSDT entry
---------------------------
To start with, there is an exported ntoskrnl.exe function that retrieves the KeServiceDescriptorTable. This table however ONLY contains the ServiceDescriptorTable for the ntoskrnl calls.
; Use internal system KeServiceDescriptorTable
mov edi, offset KeServiceDescriptorTable ; exported ntoskrnl.exe function
mov edi, [edi]
EDI is now the ntoskrnl.exe ServiceDescriptorTable as decribed in the above structure definition. In Win2K on my system this is at 80482E20.
This doesn't really do us much good though since we really want the "Shadow" table which is per- process and also contains the win32k.sys ServiceDescriptorTable.
As you mentioned Opcode, the KeServiceDescriptorTable is at offset 0xDC of fs:[124h] for Win2K, I guess you found it at 0xE0 in XP. I might be wrong, but I think this is all you need to find the Win32k.sys function addresses, again, the KeServiceDescriptorTable should be updated to include pointers to both the Service Tables.
If I use the following code in a driver, I see the ServiceDescriptorTable for both ntoskrnl and win32k.sys (a total of 8 dwords). In Win2K on my system this is at address 80482F60.
; Use KeServiceDescriptorTable for current process
mov edi, fs:[124h] ; pointer to KTHREAD for main thread
add edi, 0DCh ; [_KTHREAD+DCh] is KeServiceDescriptorTable // ServiceTable
mov edi, [edi]
mov pKeServiceDescriptorTable, edi ; save it for restoring later
assume edi : ptr ServiceDescriptorTable
Now you can access the SSDT, NumberOfServices and SSPT for either the ntoskrnl services (Service ID < 1000) or the win32k.sys services (Service ID > 1000)
[edi].ServiceTableBase
[edi].NumberOfServices
[edi].ParamTableBase
I hope this helped a bit. If anyone is interested I could post my test program which gives an example of adding user-defined NTOSKRNL Services in Win2K. You simply make a copy of the original SSDT and SSPT, increase their size, and add new SSDT (your function addresses) and SSPT (how many parameter bytes they use) entries to the end of each table, then update the KeServiceDescriptorTable. These new services can now be called via Int2E from either user mode or kernel mode. I don't think you can do this in XP without modifying the permissions of the Service Table addresses in memory. I'm not sure if such a posting would be against the Board's policy, but it is a fairly innocuous example.
Regards,
Kayaker
=================================================================================
Posted by Opcode:
Hi, Kayaker
I'm trying to hook the function 0x1225 of
KeServiceDescriptorTable.
Using the SoftICE I did the following:
bpint 2e if (eax==1225)
When the breakpoint fired, I perceived in
the int 2eh interrupt handler, that the
XP kernel find the KeServiceDescriptorTableShadow
in this way:
push 00 ;eax=0x1225 (win32k.sys)
... (resumed)
mov esi, [FFDFF124] ;esi=KTHREAD pointer
...
mov edi, eax ;edi = 0x1225
shr edi, 08
and edi, 30h ;edi = 0x10
add edi, [esi+e0] ;EDI is now the KeServiceDescriptorTableShadow pointer !!!
...
and eax, 0FFFh ;eax=225h
mov edi, [edi]
mov ebx, [eax*4+edi]
...
call [ebx] ;<-- Call the 0x1225 function of Win32k.sys !!!
...
But doing this im my DriverEntry procedure , i got the BSOD!!!
mov eax, [ffdff124]
add eax, 0e0h ;eax point to KeServiceDescriptorTable
add eax, 0x10 ;eax point to KeServiceDescriptorTableShadow
mov eax, [eax] ; <<<<<<<<--- Blue Screen of Death
Using the DbgPrint function I discovered that mov eax, [eax] was mov eax, [00000000] !!!
But debugging with the help of w2k_mem.exe http://www.orgon.com/w2k_internals/ ("http://www.orgon.com/w2k_internals/") w2k_internals.zip
for seeing the kernel memory, and doing
w2k_mem #0x200 0xffdff000 +p 0x124 +0xe0
// w2k_mem.exe
// SBS Windows 2000 Memory Spy V1.00
// 08-27-2000 Sven B. Schreiber
Loading "SBS Windows 2000 Spy Device" (w2k_spy) ...
Driver: "w2k_spy.sys"
Opening "\\.\w2k_spy ("file://\.w2k_spy")" ...
SBS Windows 2000 Spy Device V1.00 ready
FFDFF000..FFDFF1FF: 512 valid bytes
Address | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
FFDFF000 | F0 BC E6 F5-F0 BD E6 F5 : 00 80 E6 F5-00 00 00 00 | _+ตง_ขตง.?ตง....
FFDFF010 | 00 00 00 00-00 00 00 00 : 00 E0 FD 7F-00 F0 DF FF | .........ำฒ.._ฏ_
FFDFF020 | 20 F1 DF FF-00 00 00 00 : 00 00 00 00-00 00 00 00 | ฑฏ_............
FFDFF030 | C0 20 FF FF-B8 DD 53 80 : 00 F4 03 80-00 F0 03 80 | + __ฉฆS?.ถ.?._.?
FFDFF040 | 00 20 04 80-01 00 01 00 : 01 00 00 00-64 00 00 00 | . .?........d...
FFDFF050 | 00 00 00 08-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF060 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF070 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF080 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF090 | 00 00 04 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0A0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0B0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0C0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0D0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0E0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0F0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF100 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF110 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF120 | 01 00 01 00-D0 87 58 FF <<<<-- _KTHREAD POINTER
FF5887D0..FF5889CF: 512 valid bytes
Address | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
FF5887D0 | 06 00 70 00-00 00 00 00 : D8 87 58 FF-D8 87 58 FF | ..p.....ฯ?X_ฯ?X_
FF5887E0 | F8 D0 1C FF-F8 D0 1C FF : 00 C0 E6 F5-00 80 E6 F5 | ฐ๐._ฐ๐._.+ตง.?ตง
FF5887F0 | 00 E0 FD 7F-00 00 00 00 : 6C BC E6 F5-00 02 00 00 | .ำฒ.....l+ตง....
FF588800 | 00 0A 00 08-04 88 58 FF : 04 88 58 FF-0C 88 58 FF | .....?X_.?X_.?X_
FF588810 | 0C 88 58 FF-A8 81 58 FF : 00 00 00 00-51 00 00 00 | .?X_ฟ�X_....Q...
FF588820 | 00 00 00 00-00 00 00 00 : 00 00 00 00-40 88 58 FF | ............@?X ("............@?X")_
FF588830 | 00 00 00 00-80 B7 54 80 : FA 09 05 00-08 10 00 02 | ....?ภT?ท.......
FF588840 | 18 BA E6 F5-18 BA E6 F5 : D0 87 58 FF-E8 D0 1C FF | .ฆตง.ฆตง๐?X_�๐._
FF588850 | 40 88 58 FF-00 00 01 00 : 00 00 00 00-00 00 00 00 | @?X_............
FF588860 | D0 87 58 FF-00 00 00 00 : 00 00 00 00-00 00 00 00 | ๐?X_............
FF588870 | 00 00 00 00-00 00 00 00 : D0 87 58 FF-00 00 00 00 | ........๐?X_....
FF588880 | 00 00 00 00-00 00 00 00 : C8 88 58 FF-C8 88 58 FF | ........+?X_+?X_
FF588890 | D0 87 58 FF-C0 88 58 FF : 40 88 58 FF-02 01 01 00 | ๐?X_+?X_@?X ("๐?X_+?X_@?X")_....
FF5888A0 | 00 00 00 00-FF FF FF FF : 01 00 00 00-00 00 00 00 | ....____........
FF5888B0 | 80 AE 54 80- <---- [_KTHREAD+e0] !!!
8054AE80..8054B07F: 512 valid bytes
Address | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
8054AE80 | 88 25 50 80-00 00 00 00 : 1C 01 00 00-A4 2B 50 80 | <-- KeServiceDescriptorTable
8054AE90 | 40 8C 99 BF-00 00 00 00 : 9B 02 00 00-A0 27 99 BF | <-- KeServiceDescriptorTableShadow
8054AEA0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
8054AEB0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
8054AEC0 | 88 25 50 80-00 00 00 00 : 1C 01 00 00-A4 2B 50 80 | <-- KeServiceDescriptorTable
8054AED0 | 00 00 00 00-00 <--------------------------------------- My BSOD!!!!
8054AEE0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
8054AEF0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
When I load my driver with the KmdManager of Four-F KMDKIT, and using DebugView of
Mark Russinovich, I discovered that
mov eax, [eax+e0] or mov eax, [_KTHREAD+e0] results in eax = 8054aec0 and not 8054ae80 !!!!
Why w2k_mem have the currect address and I my driver don't ????
My theory:
"When a thread first calls a Win32 GUI Service, its system service table is changed to one that
includes the GDI and USER services in Win32k.sys" - Mark Russinovich in "Inside Windows 2000"
More debbuging and I founded in KTHREAD that the owner process is "SYSTEM" in my driver
when loaded by KmdManager and in the w2k_mem, the owner process is "w2k_mem.exe".
I suppose that "SYSTEM" is a kernel process and donดt use Win32 GUI Services, therefore don't
have the KeServiceDescriptorTableShadow pointer!
Then, I'm doing the following to skip the BSOD:
mov eax, 0ffdff124h
mov eax, [eax]
add eax, 0e0h
mov eax, [eax]
mov eax, [eax - 030h]
and until now, it's working !!!
If anyone have another theory, please tell me !!!
And, Kayaker, thanks for the help and please send me your testing program.
Sorry again for my bad english and for this post size!!!
Regards,
Opcode
=================================================================================
Posted by Kayaker:
You seem to be right Opcode that the Service Table your driver sees is not the updated "shadow" table. Your diagnosis of the Int2E function is more or less correct I believe, [_KTHREAD+E0h] should be the *ntoskrnl* portion of the Service Table for the process, [_KTHREAD+E0h]+10h should be the *win32k.sys* portion if it is being used (the next 4 dwords). (This is why the Service ID's for win32k.sys are > 1000, the 'shr edi, 08' forces the "+10h"
.
For me with the GUI+driver setup, that is essentially what I see at [_KTHREAD+DCh], 2 sets of 4 dwords describing each ServiceDescriptorTable. I *thought* that in most cases a regular app using a driver IOCTL DispatchControl routine would have already had a call to win32k.sys, which according to theory would have initialized the Service Table to include this "shadow" table.
Perhaps you could take your code out of DriverEntry and instead use DeviceIoControl to set it up. Are you using any GUI interface at all?
Anyway, here's the example of adding user-defined NTOSKRNL Services for Win2K, an implementation of the idea from Undocumented Windows NT by Prasad Dabak et al. The driver is loaded and 2 blank services added when you click on the button, information is returned to the edit box, then the new service can be tested. The original service table is restored and the driver unloaded on exit. It's not meant to be a treatise on the subject, just my own playings. Let me know if there are any problems.
Regards,
Kayaker
Attachment: addntservices.zip
=================================================================================
Posted by Four-F:
While dispatching system service request, KiSystemService (int2Eh/sysenter handler) fetches ServiceDescriptorTable address from the KTHREAD.ServiceTable of calling thread itself. Wherever it points, KiSystemService will use it for dispatching system service request.
There is two thread types: non-GUI & GUI.
For non-GUI thread its KTHREAD.ServiceTable points to KeServiceDescriptorTable. This pointer is exported by ntoskrnl.exe.
For GUI thread its KTHREAD.ServiceTable points to KeServiceDescriptorTableShadow. This pointer is not exported.
KeServiceDescriptorTable and KeServiceDescriptorTableShadow are basically the same with only one exception and consist of four structures (see above definition of ServiceDescriptorTable by Kayaker). First ServiceDescriptorTable is for Native API (exports from ntoskrnl.exe), third ServiceDescriptorTable is for Internet Information Services (if installed) (exports from Spud.sys), fourth ServiceDescriptorTable is reserved.
The exception is the second ServiceDescriptorTable. In KeServiceDescriptorTable it is unused but in KeServiceDescriptorTableShadow it is for Win32 USER and GDI services (exports from Win32k.sys).
All threads in System or Idle process are non-GUI ones. So, they KTHREAD.ServiceTable points to KeServiceDescriptorTable. Any just created thread is also non-GUI one and its KTHREAD.ServiceTable also points to KeServiceDescriptorTable. But if thread does first call to any service from user32.dll or gdi32.dll the system converts such thread to GUI-thread. It looks like this:
The common way to find KeServiceDescriptorTableShadow address is to scan memory ~one page up and down around KeServiceDescriptorTable, which address can be easily obtained. You have to find the match with first ServiceDescriptorTable of KeServiceDescriptorTable. If this match found, its first ServiceDescriptorTable of KeServiceDescriptorTableShadow. Some drivers I've seen (Invisibility by Y0da, for ex, etc...) do basically the same.
I can suggest another method. It's more generic one, IMHO.
Thirst thing you have to do is to find ServiceTable field offset in KTHREAD structure. It's easy. You create thread and call your driver with DeviceIoControl. In driver you will be in that thread context. So you obtain KeServiceDescriptorTable and scan KTHREAD of calling thread for match. This way you have KTHREAD.ServiceTable offset.
Second thing you have to do is to convert you thread to GUI one. It's also easy. Just call any user32 API. Then do another DeviceIoControl. The calling thread is now GUI one, so its KTHREAD.ServiceTable points to KeServiceDescriptorTableShadow and I'm sure you just have figured out what you have to do next :-)
Or slightly more easy implementation (see attachment). I just enumerate threads whith ID = 80h-400h, trying to find a thread which KTHREAD.ServiceTable not equal to KeServiceDescriptorTable. Just use GetServiceDescriptorTableShadowAddress in your driver and throw DbgPrint call away.
Tested under 2000, XP and Server 2003. Please test it under NT4.
Attachment: findshadowtable.zip
=================================================================================
I am going to do something I truly hope no one takes offense to. A few months back, on another forum, there was an interesting discussion concerning the KeServiceDescriptorTableShadow. Recently someone asked another question on the subject, and due to apparent policy changes on that forum, the thread was deleted.
I have absolutely no argument with this decision, they have their rules and regulations designed to protect their board, we have ours. However, I like to encourage these types of discussions on this board, and in the interest of keeping undocumented kernel programming knowledge freely available to all, I would like to resurrect the bulk of that thread and its attachments.
Understand that I'm not trying to play one-upmanship on another forum that I respect and enjoy participating in, my only desire is to preserve and encourage discussions on undocumented system programming issues. If anyone objects they are free to PM me. Here are the relevant posts from that thread for posterity.
Regards,
Kayaker
=================================================================================
Posted by Opcode:
In WindowsXP I found the KeServiceDescriptorTable pointer in a member of the KTHREAD Structure.
In the file Ntundoc.inc written by Four-F , I found it at offset 0xdc, but in XP it is in the offset 0xe0.
Appears to me that KTHREAD structure changed from windows2k to XP.
How can I find the KeServiceDescriptorTableShadow that is exported by Win32K.sys ?
=================================================================================
Posted by Kayaker:
Hi
>KeServiceDescriptorTable .. I found it at offset 0xdc, but in XP it is in the offset 0xe0.
>Appears to me that KTHREAD structure changed from windows2k to XP.
>How can I find the KeServiceDescriptorTableShadow that is exported by Win32K.sys
I think you just did. I had read that there was a change between Win2K sp1 and sp3 and the KeServiceDescriptorTable is now a per-process one. The first time a thread calls a Win32 GUI service, its system service table is changed to one that includes the GDI and USER services in Win32k.sys. This new service table contains pointers to both the ntoskrnl call table and to the win32k table. I've played with this to add new Int2E services to the ntoskrnl table, as far as I know the win32k.sys portion is what is used for any of the user services as well (Service ID > 1000), so I think there's no need to 'hunt' for the KeServiceDescriptorTableShadow.
Here's some code I've used for Win2K, things might be slightly different for XP.
ServiceDescriptorTable structure:
--------------------------
;typedef struct ServiceDescriptorTable {
;PVOID ServiceTableBase;
;PVOID ServiceCounterTable(O); • j •
;unsigned int NumberOfServices;
;PVOID ParamTableBase;
ServiceTableBase (SSDT) - points to a table of pointers to each ntoskrnl (or win32k.sys) function starting address
ServiceCounterTable - only used in debug builds, for us contains 0
NumberOfServices - 0F8h for Win2K sp3
ParamTableBase (SSPT) - points to a table containing the number of parameter *bytes* for each matching SSDT entry
---------------------------
To start with, there is an exported ntoskrnl.exe function that retrieves the KeServiceDescriptorTable. This table however ONLY contains the ServiceDescriptorTable for the ntoskrnl calls.
; Use internal system KeServiceDescriptorTable
mov edi, offset KeServiceDescriptorTable ; exported ntoskrnl.exe function
mov edi, [edi]
EDI is now the ntoskrnl.exe ServiceDescriptorTable as decribed in the above structure definition. In Win2K on my system this is at 80482E20.
This doesn't really do us much good though since we really want the "Shadow" table which is per- process and also contains the win32k.sys ServiceDescriptorTable.
As you mentioned Opcode, the KeServiceDescriptorTable is at offset 0xDC of fs:[124h] for Win2K, I guess you found it at 0xE0 in XP. I might be wrong, but I think this is all you need to find the Win32k.sys function addresses, again, the KeServiceDescriptorTable should be updated to include pointers to both the Service Tables.
If I use the following code in a driver, I see the ServiceDescriptorTable for both ntoskrnl and win32k.sys (a total of 8 dwords). In Win2K on my system this is at address 80482F60.
; Use KeServiceDescriptorTable for current process
mov edi, fs:[124h] ; pointer to KTHREAD for main thread
add edi, 0DCh ; [_KTHREAD+DCh] is KeServiceDescriptorTable // ServiceTable
mov edi, [edi]
mov pKeServiceDescriptorTable, edi ; save it for restoring later
assume edi : ptr ServiceDescriptorTable
Now you can access the SSDT, NumberOfServices and SSPT for either the ntoskrnl services (Service ID < 1000) or the win32k.sys services (Service ID > 1000)
[edi].ServiceTableBase
[edi].NumberOfServices
[edi].ParamTableBase
I hope this helped a bit. If anyone is interested I could post my test program which gives an example of adding user-defined NTOSKRNL Services in Win2K. You simply make a copy of the original SSDT and SSPT, increase their size, and add new SSDT (your function addresses) and SSPT (how many parameter bytes they use) entries to the end of each table, then update the KeServiceDescriptorTable. These new services can now be called via Int2E from either user mode or kernel mode. I don't think you can do this in XP without modifying the permissions of the Service Table addresses in memory. I'm not sure if such a posting would be against the Board's policy, but it is a fairly innocuous example.
Regards,
Kayaker
=================================================================================
Posted by Opcode:
Hi, Kayaker
I'm trying to hook the function 0x1225 of
KeServiceDescriptorTable.
Using the SoftICE I did the following:
bpint 2e if (eax==1225)
When the breakpoint fired, I perceived in
the int 2eh interrupt handler, that the
XP kernel find the KeServiceDescriptorTableShadow
in this way:
push 00 ;eax=0x1225 (win32k.sys)
... (resumed)
mov esi, [FFDFF124] ;esi=KTHREAD pointer
...
mov edi, eax ;edi = 0x1225
shr edi, 08
and edi, 30h ;edi = 0x10
add edi, [esi+e0] ;EDI is now the KeServiceDescriptorTableShadow pointer !!!
...
and eax, 0FFFh ;eax=225h
mov edi, [edi]
mov ebx, [eax*4+edi]
...
call [ebx] ;<-- Call the 0x1225 function of Win32k.sys !!!
...
But doing this im my DriverEntry procedure , i got the BSOD!!!
mov eax, [ffdff124]
add eax, 0e0h ;eax point to KeServiceDescriptorTable
add eax, 0x10 ;eax point to KeServiceDescriptorTableShadow
mov eax, [eax] ; <<<<<<<<--- Blue Screen of Death
Using the DbgPrint function I discovered that mov eax, [eax] was mov eax, [00000000] !!!
But debugging with the help of w2k_mem.exe http://www.orgon.com/w2k_internals/ ("http://www.orgon.com/w2k_internals/") w2k_internals.zip
for seeing the kernel memory, and doing
w2k_mem #0x200 0xffdff000 +p 0x124 +0xe0
// w2k_mem.exe
// SBS Windows 2000 Memory Spy V1.00
// 08-27-2000 Sven B. Schreiber
Loading "SBS Windows 2000 Spy Device" (w2k_spy) ...
Driver: "w2k_spy.sys"
Opening "\\.\w2k_spy ("file://\.w2k_spy")" ...
SBS Windows 2000 Spy Device V1.00 ready
FFDFF000..FFDFF1FF: 512 valid bytes
Address | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
FFDFF000 | F0 BC E6 F5-F0 BD E6 F5 : 00 80 E6 F5-00 00 00 00 | _+ตง_ขตง.?ตง....
FFDFF010 | 00 00 00 00-00 00 00 00 : 00 E0 FD 7F-00 F0 DF FF | .........ำฒ.._ฏ_
FFDFF020 | 20 F1 DF FF-00 00 00 00 : 00 00 00 00-00 00 00 00 | ฑฏ_............
FFDFF030 | C0 20 FF FF-B8 DD 53 80 : 00 F4 03 80-00 F0 03 80 | + __ฉฆS?.ถ.?._.?
FFDFF040 | 00 20 04 80-01 00 01 00 : 01 00 00 00-64 00 00 00 | . .?........d...
FFDFF050 | 00 00 00 08-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF060 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF070 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF080 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF090 | 00 00 04 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0A0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0B0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0C0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0D0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0E0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF0F0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF100 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF110 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
FFDFF120 | 01 00 01 00-D0 87 58 FF <<<<-- _KTHREAD POINTER
FF5887D0..FF5889CF: 512 valid bytes
Address | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
FF5887D0 | 06 00 70 00-00 00 00 00 : D8 87 58 FF-D8 87 58 FF | ..p.....ฯ?X_ฯ?X_
FF5887E0 | F8 D0 1C FF-F8 D0 1C FF : 00 C0 E6 F5-00 80 E6 F5 | ฐ๐._ฐ๐._.+ตง.?ตง
FF5887F0 | 00 E0 FD 7F-00 00 00 00 : 6C BC E6 F5-00 02 00 00 | .ำฒ.....l+ตง....
FF588800 | 00 0A 00 08-04 88 58 FF : 04 88 58 FF-0C 88 58 FF | .....?X_.?X_.?X_
FF588810 | 0C 88 58 FF-A8 81 58 FF : 00 00 00 00-51 00 00 00 | .?X_ฟ�X_....Q...
FF588820 | 00 00 00 00-00 00 00 00 : 00 00 00 00-40 88 58 FF | ............@?X ("............@?X")_
FF588830 | 00 00 00 00-80 B7 54 80 : FA 09 05 00-08 10 00 02 | ....?ภT?ท.......
FF588840 | 18 BA E6 F5-18 BA E6 F5 : D0 87 58 FF-E8 D0 1C FF | .ฆตง.ฆตง๐?X_�๐._
FF588850 | 40 88 58 FF-00 00 01 00 : 00 00 00 00-00 00 00 00 | @?X_............
FF588860 | D0 87 58 FF-00 00 00 00 : 00 00 00 00-00 00 00 00 | ๐?X_............
FF588870 | 00 00 00 00-00 00 00 00 : D0 87 58 FF-00 00 00 00 | ........๐?X_....
FF588880 | 00 00 00 00-00 00 00 00 : C8 88 58 FF-C8 88 58 FF | ........+?X_+?X_
FF588890 | D0 87 58 FF-C0 88 58 FF : 40 88 58 FF-02 01 01 00 | ๐?X_+?X_@?X ("๐?X_+?X_@?X")_....
FF5888A0 | 00 00 00 00-FF FF FF FF : 01 00 00 00-00 00 00 00 | ....____........
FF5888B0 | 80 AE 54 80- <---- [_KTHREAD+e0] !!!
8054AE80..8054B07F: 512 valid bytes
Address | 00 01 02 03-04 05 06 07 : 08 09 0A 0B-0C 0D 0E 0F | 0123456789ABCDEF
---------|-------------------------:-------------------------|-----------------
8054AE80 | 88 25 50 80-00 00 00 00 : 1C 01 00 00-A4 2B 50 80 | <-- KeServiceDescriptorTable
8054AE90 | 40 8C 99 BF-00 00 00 00 : 9B 02 00 00-A0 27 99 BF | <-- KeServiceDescriptorTableShadow
8054AEA0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
8054AEB0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
8054AEC0 | 88 25 50 80-00 00 00 00 : 1C 01 00 00-A4 2B 50 80 | <-- KeServiceDescriptorTable
8054AED0 | 00 00 00 00-00 <--------------------------------------- My BSOD!!!!
8054AEE0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
8054AEF0 | 00 00 00 00-00 00 00 00 : 00 00 00 00-00 00 00 00 | ................
When I load my driver with the KmdManager of Four-F KMDKIT, and using DebugView of
Mark Russinovich, I discovered that
mov eax, [eax+e0] or mov eax, [_KTHREAD+e0] results in eax = 8054aec0 and not 8054ae80 !!!!
Why w2k_mem have the currect address and I my driver don't ????
My theory:
"When a thread first calls a Win32 GUI Service, its system service table is changed to one that
includes the GDI and USER services in Win32k.sys" - Mark Russinovich in "Inside Windows 2000"
More debbuging and I founded in KTHREAD that the owner process is "SYSTEM" in my driver
when loaded by KmdManager and in the w2k_mem, the owner process is "w2k_mem.exe".
I suppose that "SYSTEM" is a kernel process and donดt use Win32 GUI Services, therefore don't
have the KeServiceDescriptorTableShadow pointer!
Then, I'm doing the following to skip the BSOD:
mov eax, 0ffdff124h
mov eax, [eax]
add eax, 0e0h
mov eax, [eax]
mov eax, [eax - 030h]
and until now, it's working !!!
If anyone have another theory, please tell me !!!
And, Kayaker, thanks for the help and please send me your testing program.
Sorry again for my bad english and for this post size!!!
Regards,
Opcode
=================================================================================
Posted by Kayaker:
You seem to be right Opcode that the Service Table your driver sees is not the updated "shadow" table. Your diagnosis of the Int2E function is more or less correct I believe, [_KTHREAD+E0h] should be the *ntoskrnl* portion of the Service Table for the process, [_KTHREAD+E0h]+10h should be the *win32k.sys* portion if it is being used (the next 4 dwords). (This is why the Service ID's for win32k.sys are > 1000, the 'shr edi, 08' forces the "+10h"

For me with the GUI+driver setup, that is essentially what I see at [_KTHREAD+DCh], 2 sets of 4 dwords describing each ServiceDescriptorTable. I *thought* that in most cases a regular app using a driver IOCTL DispatchControl routine would have already had a call to win32k.sys, which according to theory would have initialized the Service Table to include this "shadow" table.
Perhaps you could take your code out of DriverEntry and instead use DeviceIoControl to set it up. Are you using any GUI interface at all?
Anyway, here's the example of adding user-defined NTOSKRNL Services for Win2K, an implementation of the idea from Undocumented Windows NT by Prasad Dabak et al. The driver is loaded and 2 blank services added when you click on the button, information is returned to the edit box, then the new service can be tested. The original service table is restored and the driver unloaded on exit. It's not meant to be a treatise on the subject, just my own playings. Let me know if there are any problems.
Regards,
Kayaker
Attachment: addntservices.zip
=================================================================================
Posted by Four-F:
While dispatching system service request, KiSystemService (int2Eh/sysenter handler) fetches ServiceDescriptorTable address from the KTHREAD.ServiceTable of calling thread itself. Wherever it points, KiSystemService will use it for dispatching system service request.
There is two thread types: non-GUI & GUI.
For non-GUI thread its KTHREAD.ServiceTable points to KeServiceDescriptorTable. This pointer is exported by ntoskrnl.exe.
For GUI thread its KTHREAD.ServiceTable points to KeServiceDescriptorTableShadow. This pointer is not exported.
KeServiceDescriptorTable and KeServiceDescriptorTableShadow are basically the same with only one exception and consist of four structures (see above definition of ServiceDescriptorTable by Kayaker). First ServiceDescriptorTable is for Native API (exports from ntoskrnl.exe), third ServiceDescriptorTable is for Internet Information Services (if installed) (exports from Spud.sys), fourth ServiceDescriptorTable is reserved.
The exception is the second ServiceDescriptorTable. In KeServiceDescriptorTable it is unused but in KeServiceDescriptorTableShadow it is for Win32 USER and GDI services (exports from Win32k.sys).
All threads in System or Idle process are non-GUI ones. So, they KTHREAD.ServiceTable points to KeServiceDescriptorTable. Any just created thread is also non-GUI one and its KTHREAD.ServiceTable also points to KeServiceDescriptorTable. But if thread does first call to any service from user32.dll or gdi32.dll the system converts such thread to GUI-thread. It looks like this:
Code:
:004B9627 _PsConvertToGuiThread@0 ("_PsConvertToGuiThread@0") proc
. . .
:004B964A mov eax, large fs:124h
:004B9650 mov esi, eax
. . .
:004B96A5 mov [esi+KTHREAD.ServiceTable], offset _KeServiceDescriptorTableShadow
. . .
:004B96C0 retn
:004B96C0 _PsConvertToGuiThread@0 ("_PsConvertToGuiThread@0") endp
The common way to find KeServiceDescriptorTableShadow address is to scan memory ~one page up and down around KeServiceDescriptorTable, which address can be easily obtained. You have to find the match with first ServiceDescriptorTable of KeServiceDescriptorTable. If this match found, its first ServiceDescriptorTable of KeServiceDescriptorTableShadow. Some drivers I've seen (Invisibility by Y0da, for ex, etc...) do basically the same.
I can suggest another method. It's more generic one, IMHO.
Thirst thing you have to do is to find ServiceTable field offset in KTHREAD structure. It's easy. You create thread and call your driver with DeviceIoControl. In driver you will be in that thread context. So you obtain KeServiceDescriptorTable and scan KTHREAD of calling thread for match. This way you have KTHREAD.ServiceTable offset.
Second thing you have to do is to convert you thread to GUI one. It's also easy. Just call any user32 API. Then do another DeviceIoControl. The calling thread is now GUI one, so its KTHREAD.ServiceTable points to KeServiceDescriptorTableShadow and I'm sure you just have figured out what you have to do next :-)
Or slightly more easy implementation (see attachment). I just enumerate threads whith ID = 80h-400h, trying to find a thread which KTHREAD.ServiceTable not equal to KeServiceDescriptorTable. Just use GetServiceDescriptorTableShadowAddress in your driver and throw DbgPrint call away.
Tested under 2000, XP and Server 2003. Please test it under NT4.
Attachment: findshadowtable.zip
=================================================================================