By sunwear [E.S. T]
2004/10/02
Shellcoder@163.com
This article can only be said to be a note about the local API, except for Win32 API, which is another basic interface opened on the NT platform. The local API is also familiar to many people because the kernel mode module is at a lower system level and the Environment subsystem is invisible at that level. However, you do not need to access this interface at the driver level. A common Win32 program can call the local API at any time. There are no technical restrictions, but Microsoft does not support this application development method.
User32.dll, kernel32.dll, shell32.dll, gdi32.dll, rpcrt4.dll, comctl32.dll, advapi32.dll, and version. dll represent the basic providers of Win32 APIs. All the calls in Win32 apiare directed to ntdll.dllat the end, and then forwarded from callback to ntoskrnl.exe. Ntdll. dll is a terminal in the local API user mode. The real interface is completed in ntoskrnl.exe. In fact, kernel-mode drivers call this module most of the time if they request system services. The main function of Ntdll. dll is to allow a specific subset of kernel functions to be called by programs running in user mode. Ntdll. dll interrupts int 2ehto ntoskrnl.exe through software, that is, switches the CPU privilege level through the interrupt door. For example, the DeviceIoControl () function exported by kernel32.dll actually calls ntdll. ntDeviceIoControlFile () exported in dll. After disassembly, we can see that the number of magic 0x38 loaded by EAX is actually the system call number, and EDX points to the stack. The target address is the current stack pointer ESP + 4, so EDX points to the next address, that is, to the thing that is stored in the stack before it enters NtDeviceIoControlFile. It is actually a function parameter. The next instruction is int 2Eh, which is forwarded to the interrupt handler at the IDT position 0x2E In the Interrupt Descriptor Table.
Decompile this function to get:
Mov eax, 38 h
Lea edx, [esp + 4]
Int 2Eh
Ret 28 h
Of course, the int 2E interface is not only a simple API call dispatcher, but also a main gate from user mode to kernel mode.
W2k Native APIs consist of 248 such processing functions, 37 more than NT 4.0. It can be easily recognized from the ntdll. dll export column table: the prefix Nt. Ntdll. dll exports 249, because NtCurrentTeb () is a pure user mode function, so it does not need to be passed to the kernel. Surprisingly, only a subset of Native APIs can be called in kernel mode. In addition, ntoskrnl.exe exports two Nt * symbols, which do not exist in ntdll. dll: NtBuildNumber and NtGlobalFlag. These variables are not directed to the ntoskrnl.exe variable. They can be imported by the driver module that uses the extern keyword of the C compiler. Both ntdll.dlland ntoskrnl.exe have two prefixes: Nt * and Zw *. In fact, the disassembly results in ntdll. dll are the same. In ntoskrnl.exe, the nt prefix points to the real code, while zw is still a stub of int 2Eh. That is to say, the zw * function set is passed through the kernel mode through the user mode, while the Nt * symbol directly points to the code after the mode switch. NtCurrentTeb () in Ntdll. dll does not have the corresponding zw function. Ntoskrnl does not export the paired Nt/zw function. Some functions only appear in one way.
The 2Eh interrupt handler uses the value in EAX as the index in the search table to find the final target function. This table is the system service table SST. The C structure SYSTEM_SERVICE_TABLE is defined as follows: the list also contains the definition in the structure SERVICE_DESCRIPTOR_TABLE, which is the fourth member of the SST array. The first two have special purposes.
Typedef NTSTATUS (NTAPI * NTPROC )();
Typedef NTPROC * PNTPROC;
# Define NTPROC _ sizeof (NTPROC)
Typedef struct _ SYSTEM_SERVICE_TABLE
{PNTPROC ServiceTable; // here is the entry pointer Array
PDWORD CounterTable; // The call Count Array
DWORD ServiceLimit; // number of service entries
PBYTE ArgumentTable; // an array of the number of nodes for the service
) SYSTEM_SERVICE_TABLE,
* PSYSTEM_SERVICE_TABLE,
** PPSYSTEM_SERVICE_TABLE;
//____________
Typedef struct _ SERVICE_DESCRIPTOR_TABLE
{SYSTEM_SERVICE_TABLE ntoskrnl; // System Service implemented by ntoskrnl, local API}
SYSTEM_SERVICE_TABLE win32k; // System Service implemented by win32k
SYSTEM_SERVICE_TABLE Table3; // not used
SYSTEM_SERVICE_TABLE Table4; // not used
} SERVICE_DESCRIPTOR_TABLE,
* PSERVICE_DESCRIPTOR_TABLE,
* PPSERVICE_DESCRIPTOR_TABLE;
Ntoskrnl uses the KeServiceDescriptorTable symbol to capture a pointer to the short‑forward DT. Another SDT for Kernel maintenance is KeServiceDescriptorTableShadow. However, this symbol is not exported. To access the main SDT in the kernel mode component, you only need two lines of C code:
Extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
PSERVICE_DESCRIPTOR_TABLE psdt = KeServiceDescriptorTable;
NTPROC is a convenient placeholder for local APIs. It is similar to PROC in Win32 programming. Native API normally returns an NTSTATUS code, which uses the NTAPI call convention. It is the same as _ stdcall. The ServiceLimit member has the number of entries found in the ServiceTable array. Under 2000, the default value is 248. ArgumentTable is an array of BYTEs. Each parameter corresponds to the position of ServiceTable and shows the number of parameter bits in the caller stack. This information is combined with EDX, which is required by the kernel from the caller stack copy parameter to its own stack. CounterTable members are not used in 2000 of free buid. In debug build, this member points to the DWORDS array representing the Count used by all functions. This information can be used for performance analysis.
You can use this command to display: dd KeServiceDescriptorTable. The debugger resolves this symbol to 0x8046e0c0. Only the first four lines are the most important, corresponding to the four SDT members.
Run this command: ln 8046e100. The display symbol is KeServiceDescriptorTableShadow, indicating that the fifth SDK is indeed maintained by the kernel. The main difference is that the last entry contains win32k. sys, but the first one does not. In both tables, Table3 and Table4 are empty. Ntoskrnl.exe provides a convenient API function. The name of this function is:
KeAddSystemServiceTable
This function fills in these locations.
The 2Eh interrupt handling mark is KisystemService (). This is also the internal symbol that ntoskrnl.exe does not export, but is contained in the 2 k symbol file. The operations on KisystemService are as follows:
1. Retrieve the SDT pointer from the current thread control block
2. It is decided to use one of the four sst sdt. It is determined by testing the delivery ID 12th and 13 BITs in EAX. ID ing in 0x0000-0x0fff to the ntoskrnl table, ID in
0x1000 and 0x1ffff are allocated to the win32k table. The remaining 0x2000-0x2ffff and
0x3000-0x3ffff is reserved for Table3 and Table4.
3. Check the 0-11 bits of EAX by selecting the ServiceLimit member in the SST. If the ID exceeds the range, the error code STATUS_INVALID_SYSTEM_SERVICE is returned.
4. Check the parameter Stack pointer and MmUserProbeAddress in EAX. This is a global variable exported by ntoskrnl. It is usually equal to 0x7FFF0000. If the parameter pointer is not under this address, STATUS_ACCESS_VIOLATION is returned.
5. Find the number of bytes of the parameter stack in ArgumentTable, from the caller's stack copy all parameters to the current Kernel Mode stack.
6. Search for the service function pointer in serviceTable and call this function.
7. Control the conversion to the internal function KiserviceExit after this service call returns.
From the discussion on SDT, we can see that there is a second kernel mode interface with the local API. This interface connects the graphic device interface of the Win32 subsystem with the window manager and the kernel mode component Win32k. The Win32k interface is also based on int 2eh. The service number of the local API is from 0x0000 to 0x0fff, and the service number of win32k is from 0x1000 to 0x1fff. (DdW32pServiceTable determines that the win32k. sys symbol is available .) Win32k contains a total of 639 system services.
The 2Eh processing process does not use the global SDT KeServiceDescriptorTable.
It is a thread-related pointer. Obviously, threads can have different SDT related to themselves. When the thread is initially optimized, KeInitializeThread () writes the KeServiceDescriptorTable to the thread's control block. In this case, the default value may be changed to another value, for example, KeServiceDescriptorTableShadow.
Windows 2000 Runtime Library
Ntdll. dll exports at least 1179 characters. Among them, 249/248 belongs to the Nt */zw * set. Therefore, another 682 functions are not transferred through the int 2eh gate. Obviously, so many functions do not rely on 2 k kernel.
Some of these functions are almost the same as the c Runtime Library. In fact, ntoskrnl also implements some functions similar to the C Runtime Library. You can use ntdll. lib in ddk to link and use these functions. At the runtime of ntdll.dlland ntoskrnl.exe, we can find that ntdll.dllis not dependent on ntoskrnl.exe. These two modules implement these functions respectively.
In addition to the C Runtime Library, 2000 also provides an extended runtime function set. Then, ntdll.dlland ntoskrnl.exe implement them respectively. Similarly, the implementation set is repeated but not completely matched. All functions in this set start with Rtl. 2000 The Runtime Library contains some auxiliary functions used for tasks that cannot be completed during C running. For example, some of them handle security transactions, others manipulate 2000 dedicated data structures, and some support memory management. Microsoft only records 406 of the 115 most useful functions in DDK.
Ntdll. dll also provides another function set starting with _ e. They are actually used in floating point simulators.
There are also many function sets. The prefixes of all these functions are as follows:
_ E (floating point simulation), Cc (Cache Management), Csr (c/s Runtime Library), Dbg (debugging supported), Ex (Execution supported ), fsRtl (File System runtime), Hal (Hardware Abstraction Layer), Inbv (initial system trial/vga boot driver bootvid. dll), Init (initial system trial), Interlocked (thread-safe variable operations), Io (IO Manager), Kd (supported by the kernel debugger), Ke (kernel routine ), ki (kernel interrupt processing), Ldr (image loader), Lpc (local process call), Lsa (local security authorization), Mm (memory management ), nls (supported by international languages), Nt (NNT native API), Ob (Object Manager), Pfx (prefix processing), Po (Power Management), Ps (process support ), READ_REGISTER _ (read from register address), Rtl (2 k runtime database), Se (secure processing), WRITE_REGISTER _ (write Register address), Zw (replace of local API ), <others> (Auxiliary Functions and C Runtime libraries ).
When writing from user mode through nt