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 explains all. EliCZ, Aug-15-1999