Native
------
by EliCZ
1)
When I read an old computer magazine, there was written: 8086 runs in real mode, 80286 runs in
protected mode and 386 runs in native mode. Perhaps they meant native == 32bit protected mode.
Native mode is also one of two modes of software FPU exception handling.
2)
One possible subsystem in PE header is Native. It marks executables running in kernel mode or
executables - as Quick View says - which don't require a subsystem. So I thought Native
application uses Native API. No, there was a little misunderstanding. Native application -
kernel-mode driver (KD extentions have also Native mark, although they use user-mode API; I
will ignore them here) uses KERNEL-MODE API, not Native API. Native API is API which name
begins with Nt.
It would be good to have description of all KM APIs. MSDN partially describes only few KM APIs.
If there is some book with descriptions it must be a bestseller. Native API is undocummented,
some NtAPIs are ZwAPIs so read docs about Zw routines. For more see Inside the Native API.
3)
Native API is for both modes, but runs in KM in NTOSKRNL. In UM is Native API connected to KM
from NTDLL by following stub:
NtAPI:
MOV EAX, TableFunction
LEA EDX, [ESP+4]
INT 2Eh ;go to KM
RET XX
This is mechanism of syscall - in NT NTcall. I want to write about it now.
------------------------------------------------------------------------------------------------
All below is undocummented (my research):
In whole article: SERVICE = ROUTINE ; not Services as mechanism
NTcalls are used by
A) NTDLL.dll for UM/KM transitions to NTOSKRNL.exe
B) USER32.dll,GDI32.dll,WINSRV.dll for UM/KM transitions to WIN32K.sys
C) NTOSKRNL.exe for KM/KM transitions to NTOSKRNL.exe
Case C) is typically for transitions ZwFunction -> NtFunction
Example:
ZwClose one in NTDLL and one in NTOSKRNL
NtClose one in NTDLL and one in NTOSKRNL too!
Address: NTDLL.ZwClose == NTDLL.NtClose
Stub: NTDLL.ZwClose == NTDLL.NtClose == NTOSKRNL.ZwClose
So these all call NTOSKRNL.NtClose, which is the functional part, all other ??Close are
stubs.
Note that NTcalls 0A0h, resp. 0C2h - NtSetHighWaitLowThread, resp. NtSetLowWaitHighThread -
go not via INT 2Eh but INT 2Bh, resp. INT 2Ch.
NTcalls which use pointers as parameters were security hole and often used for attacks in the
past (see GetAdmin exploit and NT Syscalls insecurity).
In the stub:
------------
MOV EAX, TableFunction
TableFunction is constant comprised from two numbers:
TableFunction = TableNumber SHL 12 + FunctionNumber
where FunctionNumber can be 0..0FFFh
TableNumber can be 0..3 (for NT 4.0)
Table 0 is for NTOSKRNL.exe ONLY (base)
Table 1 is for WIN32K.sys ONLY (graphics)
Table 2 and 3 are for the one who knows
NT 4.0 1381 SP5: Table 0 has 0D3h entries,
table 1 has 20Bh entries.
LEA EDX, [ESP+4] is pointer to parameters
INT 2Eh is the transition
RET xx is return from API + cleanup stack
Table has structure:
ServiceTable STRUCT
PointerToEntries DWORD ?
MinimumService DWORD ?
MaximumService DWORD ?
PointerToParameters DWORD ?
ServiceTable ENDS
PointerToEntries DWORD Entry0, Entry1,...,EntryFFF
MinimumService is ignored (usually 0)
MaximumService is number of services; you can call service < MaximumService only
PointerToParameters DWORD ParamsSizeForEntry0,...,ParamsSizeForEntryFFF
So there are 4 service tables (NT 4.0) pointer to them is NTOSKRNL export:
KeServiceDescriptorTable ServiceTable 4 DUP ({})
There is moreover one nonexported (internal or "shadow") ServiceDescriptorTable in NTOSKRNL.
Of course Entries can be hooked and are hooked. For example in "NTdump/Preserve BPM" I'm
hooking NtContinue (NTcall 13h), in EDump I'm hooking NtSetContextThread (NTcall 99h). So the
problem is not HOW to hook, but to FIND and to KNOW what I'm hooking! Simply trace your
application and hook there where execution flows. Of course NTcalls can be added/changed/
removed among OS versions. See also my DriverSkeleton.
ServiceTable can be added via KeAddSystemServiceTable:
AL := KeAddSystemServiceTable(PointerToEntries, MinimumService, MaximumService,
PointerToParameters, TableNo)
As I already mentioned TableNo can be 2 or 3.
If AL = 1 then your table was successfully added.
KeAdd.. checks if both "visible" and "shadow" table entries are free (=0), then fills "shadow"
table with passed parameters; if TableNo != 1 it fills also "visible" table. Shortly: table 1
is invisible = KeServiceDescriptorTable+10h is always empty (=0).
Has it sense?
Partially. It is FASTER interface than DeviceIoControl (which is btw NTcall (2Dh) too).
INT 2Eh goes to INT 2Eh KM handler, from EAX it extracts TableNo and Function, selects this
ServiceDescriptorTable ("visible"/"shadow") which address is in KTEB at offset 0DCh, compares
if Function < MaximumService, copies parameters from user (=EDX) to kernel stack and calls
Entry. If TableNo is 1 then before copying parameters and calling Entry can be called a routine
which was passed as parameter to PsEstablishWin32Callouts (see WIN32K.sys for more). As you can
see table 1 is something special - ALL FOR GRAPHICS! De facto KeAdd.. and PsEst.. are used by
WIN32K.sys only, so they were created for WIN32K only?
Note:
I think in the future will be INT 2Eh replaced with Pentium II+ instructions SYSENTER/SYSEXIT.
These instructions are designed for NT: SYSENTER requires ring0_SS = ring0_CS + 08h, SYSEXIT
requires ring3_CS = ring0_CS + 10h, ring3_SS = ring0_CS + 18h. In NT is: ring0_CS = 08h,
ring0_SS = 10h, ring3_CS = 1Bh and ring3_SS = 23h ;-) -> Intel made what Microsoft wanted.
From Intel documentation:
The SYSENTER and SYSEXIT instructions do not constitute a call/return pair; therefore, the
system call "stub" routines executed by user code (typically in shared libraries or DLLs) must
perform the required register state save to create a system call/return pair.
I hope this example[Native.zip - MISSING] explains all.
EliCZ, Aug-15-1999