PDA

View Full Version : Preserving Undocumented Kernel Information - KeServiceDescriptorTableShadow


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:

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

=================================================================================

Kayaker
May 4th, 2004, 02:21
Attachment 1

Kayaker
May 4th, 2004, 02:22
Attachment 2

Kayaker
May 4th, 2004, 02:23
=================================================================================

Posted by Metro_Mystery

I know, more or less- this post goes goes back a few months; but I have a question that relates directly to it.

Just a few quick structure definitions...

typedef struct tag_SYSTEM_SERVICE_TABLE {
PULONG ServiceTable; // array of entry points
PULONG CounterTable; // array of usage counters
ULONG ServiceLimit; // number of table entries
PCHAR ArgumentTable; // array of argument counts
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE, **PPSYSTEM_SERVICE_TABLE;

typedef struct tag_SERVICE_DESCRIPTOR_TABLE {
SYSTEM_SERVICE_TABLE ntoskrnl; // main native API table
SYSTEM_SERVICE_TABLE win32k; // win subsystem, in shadow table
SYSTEM_SERVICE_TABLE sst3;
SYSTEM_SERVICE_TABLE sst4;
} SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE, **PPSERVICE_DESCRIPTOR_TABLE;

Now in Windows XP, [KTHREAD+e0] always points to the PSERVICE_DESCRIPTOR_TABLE at address 0x80544BC0.

Using Softice- I read the data at this address ->

PSERVICE_DESCRIPTOR_TABLE->ntoskrnl = 0x80544BC0

And found that ->

PSERVICE_DESCRIPTOR_TABLE->ntoskrnl->ServiceTable = 0x804FC624;
PSERVICE_DESCRIPTOR_TABLE->ntoskrnl.ServiceLimit = 0x0000011C;
...

PSYSTEM_SERVICE_TABLE->win32k = 0xBF995BA8

Obviously, the ntoskrnl SYSTEM_SERVICE_TABLE has be filled in with the correct addresses of all the System Service Functions etc...

However, if I then read the address at PSYSTEM_SERVICE_TABLE->win32k; although it has been assigned a pointer to 0xBF995BA8 [Address of the KeServiceDescriptorTableShadow], upon reading this address I get ->

PSERVICE_DESCRIPTOR_TABLE->win32k->ServiceTable = ?;
PSERVICE_DESCRIPTOR_TABLE->win32k.ServiceLimit = ?;

The SYSTEM_SERVICE_TABLE for the GUI/Graphical win32k functions hasn't yet been assigned the address of the functions etc. This makes sense; as my driver can't run as a GUI application [I don't think it can, anyway].

So, as pointed out by almost everyone who replied in this post; I learnt that the KeSystemServiceTableShadow isn't appended to the SERVICE_DESCRIPTOR_TABLE unless it calls a GUI/Graphical Function [i.e. User32.DLL].

But the problem, and my question is... how do I get the KeSystemServiceTableShadow appended to the SERVICE_DESCRIPTOR_TABLE in KernelMode- I can't call a Graphical/GUI function in my driver- and I can't get the KernelMode address in UserMode... A few of you talked about creating system threads and calling usermode Graphical/GUI functions to convert them- but I didn't really understand how I could use this to get the KeSystemServiceTableShadow appended to the SERVICE_DESCRIPTOR_TABLE pointed to in my KernelMode driver.

Any ideas?

Thanks,

Adam

=================================================================================

Opcode
May 4th, 2004, 07:34
Hi Kayaker,

I appreciate your decision.
Its good to see that I have a place to
make good questions and to help.
Now I will just use this forum,
I leaved the other forum.

Thanks,
Opcode

nikolatesla20
May 4th, 2004, 09:06
Um, why is this info so "dangerous" in some forum admin's mind..

-nt20

upb
May 6th, 2004, 07:27
Quote:
[Originally Posted by nikolatesla20]Um, why is this info so "dangerous" in some forum admin's mind..

-nt20


o_O coding rootkits O_o

Opcode
May 6th, 2004, 07:56
Quote:
[Originally Posted by upb]o_O coding rootkits O_o


By the rootkit definition, I don't see any reason to code
a rootkit that will use the KeServiceDescriptorShadow
because this table maps the kernel version of the
functions exported by GDI32, USER32 and some
DirectX functions.

The most important table for rootkit is the KeServiceDescriptor
which is exported by ntoskrnl.

Maybe I'm wrong

rijnahts
June 21st, 2008, 12:16
Hi All,
As per this thread i have tried to point to the PSERVICE_DESCRIPTOR_TABLE using [TEB+e0]. But i am getting NULL values. Could you please help me on this.

My structure Details are :

typedef struct ServiceDescriptorEntry
{
PDWORD KiServiceTable;
PDWORD CounterTableBase;
DWORD ServiceLimit;
PBYTE ArgumentTable;
}SDE;

typedef struct ServiceDescriptorTable
{
SDE ServiceDescriptor [4];
}SDT, *PSDT;

typedef struct _TEB {
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID Cid;
PVOID ActiveRpcInfo;
PVOID ThreadLocalStoragePointer;
PPEB Peb;
unsigned int LastErrorValue;
unsigned int CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo;
unsigned int User32Reserved[26];
unsigned int UserReserved[5];
PVOID WOW32Reserved;
unsigned int CurrentLocale;
unsigned int FPSoftwareStatusRegister;
PVOID temp[6];
//for 0xe0 (224 - decimal) location
PSDT ServiceDescriptorTable;


Code :

FuncNtCurrentTeb ngt = (FuncNtCurrentTeb)GetProcAddress( GetModuleHandle( _T("ntdll.dll" ), "NtCurrentTeb" );
PTEB pTeb = ngt();

Thanks in advance....

Kayaker
June 22nd, 2008, 16:09
Hi

I'm sorry, I think you got some bad directions there. In the original post the word TEB had crept in there in a few places instead of the proper KTHREAD. I had mentioned the error but I guess it got missed, I have now edited the post to make it clearer.

What you need is KTHREAD.ServiceTable (_KTHREAD + 0xE0) for XP, TEB is the wrong structure.

Code:


WinDbg > dt -v nt!_KTHREAD
ntdll!_KTHREAD
struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x000 Header : struct _DISPATCHER_HEADER, 6 elements, 0x10 bytes
+0x010 MutantListHead : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x018 InitialStack : Ptr32 to Void
+0x01c StackLimit : Ptr32 to Void
+0x020 Teb : Ptr32 to Void
...
+0x0e0 ServiceTable : Ptr32 to Void



Normally you need/want driver code to work with the ServiceTable. Are you trying to do anything in particular?

Kayaker

rijnahts
June 22nd, 2008, 18:04
Hi Kayaker,
Thanks for your response. As of my knowledge i can use FS register to find out the TEB and PEB. Do you have any idea to find out the KTHREAD.

I am investigating to find out the start and end address of the servicetable.

Please response me how to find out the KTHREAD using any of the register.....


Waiting for response....


Thanks

Kayaker
June 22nd, 2008, 18:42
Quote:
[Originally Posted by rijnahts;75337]Do you have any idea to find out the KTHREAD.


fs:[0x124] = KTHREAD/ETHREAD
but I forget what happens if you try to access it from usermode, Access Violation probably.

rijnahts
June 22nd, 2008, 18:52
Hi kayaker,
I have used the folllowing code to get the KTHREAD/ETHREAD pointer, but EAX values is showing as 0.

Do you mean from user mode we dont get permission to access KTHREAD/ETHREAD....

void *ETHREAD;
__asm {
mov EAX, fs:[0x124];
mov [ETHREAD], EAX;
}

please help me on this.

Thanks

rijnahts
June 22nd, 2008, 21:30
Hi kayaker, Can you help me on this.....

Thanks

Kayaker
June 22nd, 2008, 22:34
Quote:
[Originally Posted by rijnahts;75341]Do you mean from user mode we dont get permission to access KTHREAD/ETHREAD....


That's right, the EPROCESS and ETHREAD structures are only accessible from kernel mode. The PEB and TEB are readable from user mode.

Your last code snippet works fine when written in a driver.

rijnahts
June 22nd, 2008, 23:03
Do we have any other option to find out the address of ServiceDecriptorTable from user mode (without using ntoskrnl.exe)....

rijnahts
June 23rd, 2008, 19:50
Hi kayaker,
As per your information the FS:[0x124] points to ETHREAD/KTHREAD.
KTHREAD[0xe0] points to SerivceTable.
When i dumped the KTHREAD data structure using windows debugger it shows the ServiceTable is located at 0xe0, but if you notice the structure you will see 0x060 multiple times.


lkd> dt nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListHead : _LIST_ENTRY
+0x018 InitialStack : Ptr32 Void
+0x01c StackLimit : Ptr32 Void
+0x020 Teb : Ptr32 Void
+0x024 TlsArray : Ptr32 Void
+0x028 KernelStack : Ptr32 Void
+0x02c DebugActive : UChar
+0x02d State : UChar
+0x02e Alerted : [2] UChar
+0x030 Iopl : UChar
+0x031 NpxState : UChar
+0x032 Saturation : Char
+0x033 Priority : Char
+0x034 ApcState : _KAPC_STATE
+0x04c ContextSwitches : Uint4B
+0x050 IdleSwapBlock : UChar
+0x051 Spare0 : [3] UChar
+0x054 WaitStatus : Int4B
+0x058 WaitIrql : UChar
+0x059 WaitMode : Char
+0x05a WaitNext : UChar
+0x05b WaitReason : UChar
+0x05c WaitBlockList : Ptr32 _KWAIT_BLOCK
-----------------------------------------------------------------------------------------------------------------------
+0x060 WaitListEntry : _LIST_ENTRY
+0x060 SwapListEntry : _SINGLE_LIST_ENTRY
------------------------------------------------------------------------------------------------------------------------
+0x068 WaitTime : Uint4B
+0x06c BasePriority : Char
+0x06d DecrementCount : UChar
+0x06e PriorityDecrement : Char
+0x06f Quantum : Char
+0x070 WaitBlock : [4] _KWAIT_BLOCK
+0x0d0 LegoData : Ptr32 Void
+0x0d4 KernelApcDisable : Uint4B
+0x0d8 UserAffinity : Uint4B
+0x0dc SystemAffinityActive : UChar
+0x0dd PowerState : UChar
+0x0de NpxIrql : UChar
+0x0df InitialNode : UChar
+0x0e0 ServiceTable : Ptr32 Void
+0x0e4 Queue : Ptr32 _KQUEUE
+0x0e8 ApcQueueLock : Uint4B
+0x0f0 Timer : _KTIMER
+0x118 QueueListEntry : _LIST_ENTRY
+0x120 SoftAffinity : Uint4B
+0x124 Affinity : Uint4B
+0x128 Preempted : UChar
+0x129 ProcessReadyQueue : UChar
+0x12a KernelStackResident : UChar
+0x12b NextProcessor : UChar
+0x12c CallbackStack : Ptr32 Void
+0x130 Win32Thread : Ptr32 Void
+0x134 TrapFrame : Ptr32 _KTRAP_FRAME
+0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE
+0x140 PreviousMode : Char
+0x141 EnableStackSwap : UChar
+0x142 LargeStack : UChar
+0x143 ResourceIndex : UChar
+0x144 KernelTime : Uint4B
+0x148 UserTime : Uint4B
+0x14c SavedApcState : _KAPC_STATE
+0x164 Alertable : UChar
+0x165 ApcStateIndex : UChar
+0x166 ApcQueueable : UChar
+0x167 AutoAlignment : UChar
+0x168 StackBase : Ptr32 Void
+0x16c SuspendApc : _KAPC
+0x19c SuspendSemaphore : _KSEMAPHORE
+0x1b0 ThreadListEntry : _LIST_ENTRY
+0x1b8 FreezeCount : Char
+0x1b9 SuspendCount : Char
+0x1ba IdealProcessor : UChar
+0x1bb DisableBoost : UChar


I am still having doubt that how you got the ServiceTable Address at 0xe0. I think it should be 0xe4.

Please correct me if i am wrong.

Thanks

darawk
June 23rd, 2008, 20:45
You are probably just using a slightly different version of ntoskrnl. The appearance of 0x60 twice is the result of a 'union' construct in the structure. Since members of a union occupy the same space, they share the same offset in the structure, and are basically aliases for the same data.

Kayaker
June 23rd, 2008, 20:50
See if this makes sense..

Code:

> dt -v nt!_KTHREAD

+0x05c WaitBlockList : Ptr32 to struct _KWAIT_BLOCK, 6 elements, 0x18 bytes

union {
+0x060 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x060 SwapListEntry : struct _SINGLE_LIST_ENTRY, 1 elements, 0x4 bytes
};

+0x068 WaitTime : Uint4B

rijnahts
June 24th, 2008, 09:16
Hi Kayaker, darawk,
Thanks for the information. This fixed my issue.

still dt -v nt!_KTHREAD command does not show the union definition. To get a latest ntoskrnl, please let me know what i should do.

Kayaker
June 24th, 2008, 09:48
Quote:
[Originally Posted by rijnahts;75375]still dt -v nt!_KTHREAD command does not show the union definition.


No, I added the union{ definition to make it clearer to you. What the -v(erbose) argument does though is detail the field sizes.

Notice the first field LIST_ENTRY is 8 bytes, and overlaps (and shares) the second field SINGLE_LIST_ENTRY of 4 bytes. It's this (and the presence of two +0x060 entries by WinDbg) that should tell you automatically that you're dealing with a union construct.

Don't worry about the ntoskrnl version, the WinDbg output is correct for your version if you're working on the same computer.

rijnahts
June 24th, 2008, 10:02
Kayaker, Thanks a lot for your help.

rijnahts
June 24th, 2008, 10:07
kayaker,
I am able to point to KiServiceTable and also able to dump the full information from that page... If you have full system call function addresses please post here, so that i can compare with my results....


Thanks

blabberer
June 25th, 2008, 05:29
there is no thing called latest ntoskrnl if you have a computer thats running windows you have a ntoskrnl thats latest for your computer's os
if you want several versions of ntoskrnl install several versions of os
win2000
win2000 sp1 , sp2 ,sp3,sp4
winxp home , pro , sp1 , sp2 , sp3
multiprocessor machines &/| pae enabled blah blah versions have ntkrpamp
win2k3
all have thier own latest ntoskrnl.exe

and learn to spend hours together in front of windbgs help file and windbg
its quite quite powerful when it comes to windows system spleunking

here is your union or whatever you term it
basic struct defs

Code:

lkd> dt -r1 -v nt!_kthread
struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x000 Header : struct _DISPATCHER_HEADER, 6 elements, 0x10 bytes
+0x000 Type : UChar
+0x001 Absolute : UChar
+0x002 Size : UChar
+0x003 Inserted : UChar
+0x004 SignalState : Int4B
+0x008 WaitListHead : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x010 MutantListHead : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x000 Flink : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x004 Blink : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x018 InitialStack : Ptr32 to Void
+0x01c StackLimit : Ptr32 to Void
+0x020 Teb : Ptr32 to Void
+0x024 TlsArray : Ptr32 to Void
+0x028 KernelStack : Ptr32 to Void
+0x02c DebugActive : UChar
+0x02d State : UChar
+0x02e Alerted : [2] UChar
+0x030 Iopl : UChar
+0x031 NpxState : UChar
+0x032 Saturation : Char
+0x033 Priority : Char
+0x034 ApcState : struct _KAPC_STATE, 5 elements, 0x18 bytes
+0x000 ApcListHead : [2] struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x010 Process : Ptr32 to struct _KPROCESS, 29 elements, 0x6c bytes
+0x014 KernelApcInProgress : UChar
+0x015 KernelApcPending : UChar
+0x016 UserApcPending : UChar
+0x04c ContextSwitches : Uint4B
+0x050 IdleSwapBlock : UChar
+0x051 Spare0 : [3] UChar
+0x054 WaitStatus : Int4B
+0x058 WaitIrql : UChar
+0x059 WaitMode : Char
+0x05a WaitNext : UChar
+0x05b WaitReason : UChar
+0x05c WaitBlockList : Ptr32 to struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x000 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x008 Thread : Ptr32 to struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x00c Object : Ptr32 to Void
+0x010 NextWaitBlock : Ptr32 to struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x014 WaitKey : Uint2B
+0x016 WaitType : Uint2B
+0x060 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x000 Flink : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x004 Blink : Ptr32 to struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x060 SwapListEntry : struct _SINGLE_LIST_ENTRY, 1 elements, 0x4 bytes
+0x000 Next : Ptr32 to struct _SINGLE_LIST_ENTRY, 1 elements, 0x4 bytes
+0x068 WaitTime : Uint4B
+0x06c BasePriority : Char
+0x06d DecrementCount : UChar
+0x06e PriorityDecrement : Char
+0x06f Quantum : Char
+0x070 WaitBlock : [4] struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x000 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
+0x008 Thread : Ptr32 to struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x00c Object : Ptr32 to Void
+0x010 NextWaitBlock : Ptr32 to struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x014 WaitKey : Uint2B
+0x016 WaitType : Uint2B


with details

Code:

lkd> !thread
THREAD 86229898 Cid 01e4.0604 Teb: 7ffde000 Win32Thread: e1087230 RUNNING on processor 0
Not impersonating
DeviceMap e2864ee0
Owning Process 864ee358 Image: windbg.exe
Attached Process N/A Image: N/A
Wait Start TickCount 276314 Ticks: 12 (0:00:00:00.187)
Context Switch Count 1056 LargeStack
UserTime 00:00:00.203
KernelTime 00:00:00.062
Win32 Start Address 0x0102a9a0
Start Address 0x7c810856
Stack Init a8bcd000 Current a8bccb84 Base a8bcd000 Limit a8bca000 Call 0
Priority 8 BasePriority 8 PriorityDecrement 0 DecrementCount 16
Unable to get context for thread running on processor 0, HRESULT 0x80004001

lkd> dt -r1 -v nt!_kthread 86229898
struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x000 Header : struct _DISPATCHER_HEADER, 6 elements, 0x10 bytes
+0x000 Type : 0x6 ''
+0x001 Absolute : 0 ''
+0x002 Size : 0x70 'p'
+0x003 Inserted : 0 ''
+0x004 SignalState : 0
+0x008 WaitListHead : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x862298a0 - 0x862298a0 ]
+0x010 MutantListHead : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x862298a8 - 0x862298a8 ]
+0x000 Flink : 0x862298a8 struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x862298a8 - 0x862298a8 ]
+0x004 Blink : 0x862298a8 struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x862298a8 - 0x862298a8 ]
+0x018 InitialStack : 0xa8bcd000
+0x01c StackLimit : 0xa8bca000
+0x020 Teb : 0x7ffde000
+0x024 TlsArray : (null)
+0x028 KernelStack : 0xa8bccca0
+0x02c DebugActive : 0 ''
+0x02d State : 0x2 ''
+0x02e Alerted : [2] ""
+0x030 Iopl : 0 ''
+0x031 NpxState : 0xa ''
+0x032 Saturation : 0 ''
+0x033 Priority : 11 ''
+0x034 ApcState : struct _KAPC_STATE, 5 elements, 0x18 bytes
+0x000 ApcListHead : [2] struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x862298cc - 0x862298cc ]
+0x010 Process : 0x864ee358 struct _KPROCESS, 29 elements, 0x6c bytes
+0x014 KernelApcInProgress : 0 ''
+0x015 KernelApcPending : 0 ''
+0x016 UserApcPending : 0 ''
+0x04c ContextSwitches : 0x44a
+0x050 IdleSwapBlock : 0 ''
+0x051 Spare0 : [3] ""
+0x054 WaitStatus : 0
+0x058 WaitIrql : 0 ''
+0x059 WaitMode : 1 ''
+0x05a WaitNext : 0 ''
+0x05b WaitReason : 0x6 ''
+0x05c WaitBlockList : 0x86229908 struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x000 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x85c660e0 - 0x85c660e0 ]
+0x008 Thread : 0x86229898 struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x00c Object : 0x85c660d8
+0x010 NextWaitBlock : 0x86229908 struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x014 WaitKey : 0
+0x016 WaitType : 1
+0x060 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0xa8b9ccd4 - 0xa8b9ccd4 ]
+0x000 Flink : 0xa8b9ccd4 struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x8054097f - 0xa8b9ccfc ]
+0x004 Blink : 0xa8b9ccd4 struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x8054097f - 0xa8b9ccfc ]
+0x060 SwapListEntry : struct _SINGLE_LIST_ENTRY, 1 elements, 0x4 bytes
+0x000 Next : 0xa8b9ccd4 struct _SINGLE_LIST_ENTRY, 1 elements, 0x4 bytes
+0x068 WaitTime : 0x43da0
+0x06c BasePriority : 8 ''
+0x06d DecrementCount : 0x10 ''
+0x06e PriorityDecrement : 2 ''
+0x06f Quantum : 2 ''
+0x070 WaitBlock : [4] struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x000 WaitListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x85c660e0 - 0x85c660e0 ]
+0x008 Thread : 0x86229898 struct _KTHREAD, 73 elements, 0x1c0 bytes
+0x00c Object : 0x85c660d8
+0x010 NextWaitBlock : 0x86229908 struct _KWAIT_BLOCK, 6 elements, 0x18 bytes
+0x014 WaitKey : 0
+0x016 WaitType : 1
+0x0d0 LegoData : (null)
+0x0d4 KernelApcDisable : 0
+0x0d8 UserAffinity : 1
+0x0dc SystemAffinityActive : 0 ''
+0x0dd PowerState : 0 ''
+0x0de NpxIrql : 0 ''
+0x0df InitialNode : 0 ''
+0x0e0 ServiceTable : 0x80552140
+0x0e4 Queue : (null)
+0x0e8 ApcQueueLock : 0
+0x0f0 Timer : struct _KTIMER, 5 elements, 0x28 bytes
+0x000 Header : struct _DISPATCHER_HEADER, 6 elements, 0x10 bytes
+0x010 DueTime : union _ULARGE_INTEGER, 4 elements, 0x8 bytes
0x7`f3ad6c40
+0x018 TimerListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x86256ae8 - 0x80548e1c ]
+0x020 Dpc : (null)
+0x024 Period : 0
+0x118 QueueListEntry : struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x0 - 0x0 ]
+0x000 Flink : (null)
+0x004 Blink : (null)
+0x120 SoftAffinity : 1
+0x124 Affinity : 1
+0x128 Preempted : 0 ''
+0x129 ProcessReadyQueue : 0 ''
+0x12a KernelStackResident : 0x1 ''
+0x12b NextProcessor : 0 ''
+0x12c CallbackStack : (null)
+0x130 Win32Thread : 0xe1087230
+0x134 TrapFrame : 0xa8bccd64 struct _KTRAP_FRAME, 35 elements, 0x8c bytes
+0x000 DbgEbp : 0xa07410
+0x004 DbgEip : 0x7c90eb94
+0x008 DbgArgMark : 0xbadb0d00
+0x00c DbgArgPointer : 0xa073d8
+0x010 TempSegCs : 0xa8d20d98
+0x014 TempEsp : 0xa8d20dcc
+0x018 Dr0 : 0
+0x01c Dr1 : 0
+0x020 Dr2 : 0
+0x024 Dr3 : 0
+0x028 Dr6 : 0
+0x02c Dr7 : 0
+0x030 SegGs : 0
+0x034 SegEs : 0x23
+0x038 SegDs : 0x23
+0x03c Edx : 0x804d7000
+0x040 Ecx : 0x7ffde000
+0x044 Eax : 0xffffffff
+0x048 PreviousPreviousMode : 1
+0x04c ExceptionList : 0xffffffff struct _EXCEPTION_REGISTRATION_RECORD, 2 elements, 0x8 bytes
+0x050 SegFs : 0x3b
+0x054 Edi : 0x6cf38
+0x058 Esi : 0x5ad74daf
+0x05c Ebx : 0
+0x060 Ebp : 0xa07410
+0x064 ErrCode : 0
+0x068 Eip : 0x7c90eb94
+0x06c SegCs : 0x1b
+0x070 EFlags : 0x246
+0x074 HardwareEsp : 0xa073d0
+0x078 HardwareSegSs : 0x23
+0x07c V86Es : 0x80540fa2
+0x080 V86Ds : 0xf7357b85
+0x084 V86Fs : 0x864cfd60
+0x088 V86Gs : 0
+0x138 ApcStatePointer : [2] 0x862298cc struct _KAPC_STATE, 5 elements, 0x18 bytes
+0x000 ApcListHead : [2] struct _LIST_ENTRY, 2 elements, 0x8 bytes
[ 0x862298cc - 0x862298cc ]


in the r2 you can ask it enumerate upto 9 deep structs ie you can go upto -r9

and the linked list
Code:

lkd> dl 0xa8b9ccd4
a8b9ccd4 8054097f a8b9ccfc 00000001 85c660d8
8054097f 4e8ac00a 8b187558 7c8b242c 748b0424

another way
Code:

lkd> !list 0xa8b9ccd4
a8b9ccd4 85b106a8 804f99be 000024ff e58d3888
a8b9cce4 00000000 a8b9cd24 00000140 bf8034d0
a8b9ccf4 000024ff 00000000 a8b9cd38 bf802ec4
a8b9cd04 00000001 0000000d 00000001 00000000
a8b9cd14 00000000 a8b9cd64 0006df44 bf8036d3
a8b9cd24 000d0148 0000000f 00000000 00000000
a8b9cd34 00000000 a8b9cd4c bf8036ca 000024ff
a8b9cd44 00000000 00000001 a8b9cd64 bf8036e7

85b106a8 00700006 00000000 85b106b0 85b106b0
85b106b8 85b106b8 85b106b8 a8b9d000 a8b98000
85b106c8 7ffdf000 00000000 a8b9ccb0 00000500
85b106d8 0c000a00 85b106dc 85b106dc 85b106e4
85b106e8 85b106e4 864ee358 00000000 000055c5
85b106f8 00000000 00000000 0d000100 85b10718
85b10708 80551f68 85ba96a8 0004e374 0c021008
85b10718 85b124c0 85b124c0 85b106a8 85b124b8

00700006 ???????? ???????? ???????? ????????
00700016 ???????? ???????? ???????? ????????
00700026 ???????? ???????? ???????? ????????
00700036 ???????? ???????? ???????? ????????
00700046 ???????? ???????? ???????? ????????
00700056 ???????? ???????? ???????? ????????
00700066 ???????? ???????? ???????? ????????
00700076 ???????? ???????? ???????? ????????

Cannot read next element at 00700006


yet another ways <--- notice s not right inglish but right emphasis

Code:

lkd> !DFLINK 0xa8b9ccd4
a8b9ccd4 8054097f a8b9ccfc 00000001 85c660d8
Can't Read Memory at 00000000
0x1 entries dumped
lkd> !DbLINK 0xa8b9ccd4
a8b9ccd4 8054097f a8b9ccfc 00000001 85c660d8
Can't Read Memory at 00000000
0x1 entries dumped