📜 ⬆️ ⬇️

Calling Windows functions in kernel mode

Many of you, dear habrovchane, use the functions of the Windows kernel. However, not everyone is aware of how these functions are called. And knowledge of some of the mechanisms of the kernel can be very useful.

This text is not intended for drivers who (in theory) know this even at a deeper level.

We begin with the fact that in kernel mode there are much more functions than in the well-known WinAPI. This is due to the fact that the core contains a lot of undocumented functions (although the situation has improved with the release of Win7 and Win8, many such functions fall on MSDN). A list of such functions can be found, for example, here.

These functions can be divided into several groups:
')

How is all this caused?

Let's start with a call from user mode.

“First of all, we will turn to NtDll.dll , the“ interlayer ”between the user mode and the kernel mode. It contains the kernel function we need. This function places its number in the EAX register. It is an index in two tables known to the kernel: ServiceTable and ArgumentTable. Characteristically, this number is specific to each OS version. Often it changes not just when moving from, say, WinXP to Vista, but even when moving from Vista to Vista SP1.
“Next, the EDX address of the top of the parameter stack is placed; in most cases, this is the value of the ESP register. It would seem, why copy the existing value? The fact is that after performing an interrupt, all the processor state will be reset to the stack, and ESP will no longer be what we need.
- Finally, switching to kernel mode. On older processors and systems, this is done using the 0x2e interrupt; on modern ones, there is a special processor instruction for this: SysEnter for Intel, SysCall for AMD.
- The result of the call is the execution by the processor of a code whose address is in the global interrupt table in a specific cell. This code calls either KiSystemService (), in the case of an interrupt, or KiFastCallEntry (), in the case of a special instruction to the processor. By the way, the second one is registered in the MSR register, which provides quick access to it.
- Further, the code that runs in the kernel is executed a little differently, depending on where the function call came from, from kernel mode or from user mode. The task of the kernel code: on the internal table of functions to perform a function call from EAX. This table is called KiServiceDescriptorTable . This is a structure with three fields:



When the SysEnter and SysCall functions are called, they need to be dispatched to the OS functions. Each thread has a stack of user mode and kernel mode. The OS takes a cell value in the ArgumentTable table, which shows how many bytes the parameters occupy on the stack (for this we memorized EDX). Then it copies this number of bytes onto the kernel stack. And after that performs a function call via the ServiceTable. All this confusion with two stacks is needed, of course, to ensure that no changes in user mode will harm the function in the kernel.

- After the function is called and executed, and its work is completed, the return from kernel mode is done with the help of iret or SysExit / SysRet.

Calling kernel functions in kernel mode.

In principle, we have all the same, but ...
If you carefully review the list of kernel functions, you can see that there are functions that are completely analogous to the nt functions, but with the prefix zw- . All of them are uniquely mapped to nt functions. However, they work differently in kernel mode.

The difference is that in the zw- functions, the parameters are not validated. In other words, when calling from user mode, the system carefully monitors the parameters passed to the function - God forbid the programmer will miss something, and hello, blue screen. In kernel mode, they mostly work with drivers, and there the system already assumes that you check all the parameters yourself and guarantee their validity, because additional checks will eat up valuable time. It works like this: if zw is called, it loads the number of the function in EAX, puts the pointer to the kernel stack in EDX, and then calls the nt option, which does not validate.

In this connection, the question arises - what if I vyhovu zw-function from user mode? System forgive everything? Not really. If zw is called in usermode, then it will simply call its nt-twin.

Here, in general, and all the basic information about calls to kernel functions. I hope you were interested.

Source: https://habr.com/ru/post/160569/


All Articles