Windows Processes
When learning Windows malware development, it is important to have a basic understanding of Windows architecture, including applications, processes, and threads.
In Windows, an application is made of one or more processes. Each process can be thought of as an executing program, and the process provides the resources needed to execute the program.
Every process has at least one execution thread, which is a unit for which the operating system allocates processor time. A process is actually started with a single thread called the primary thread, but it can create additional threads if needed.
Within a process, all threads share the same system resources and virtual address space.
Processes and threads both utilize handles, which are integer values used to identify them.
User and Kernel Modes
In Windows, a processor can run in User Mode or Kernel Mode and selects between them depending on the type of code being executed by the processor.
Kernel-mode provides unrestricted access to system resources, and is used by the core operating system components. All code that runs in kernel-mode shares one virtual address space called system space. This means that the operating system and kernel-mode drivers aren’t isolated from each other. If a single kernel-mode driver crashes, the entire OS crashes as a result.
User Mode does not provide direct access to system resources. When we start an application, Windows creates a process. The process creates a private virtual address space, called user space, as well as a private handle table.
Any code running in user-mode has access to user space but doesn’t have access to system space. This prevents user-mode code from reading or writing to the core operating system structures. In contrast, code running in kernel-mode has access to both user space and system space.
While this configuration has obvious benefits, it means that an application can’t directly do things that require kernel-mode access, like creating a file. Instead, a series of function calls are made via subsystem DLLs and NTDLL.dll in order to access kernel-mode functions that are capable of performing the required task.
This is covered in the next section below.
For more information about user and kernel modes, check out Microsoft’s official documentation on the topic, as well as this page describing virtual address space including system space and user space.
User Process Function Call Flow
As we saw in the last section, user-mode processes can’t directly perform tasks that require access to the kernel. Instead, they use a series of function calls.
The first step is to access a subsystem DLL that contains an API function needed to perform the task. Kernel32.dll is perhaps the most important such DLL, and contains functions for memory management and resource handling. Other common subsystem DLLs include User32.dll, Ntdll.dll, and GDI32.dll.
Next, a call is made to Ntdll.dll. NTDLL is extremely important, and it serves as the user-mode side of the Windows kernel. It’s the lowest layer that is available in user-mode, and many of the functions in other subsystem DLLs are simply forwards to NTDLL. NTDLL facilitates the transition from user-mode to kernel-mode.
Finally, execution is transferred to the Windows executive kernel. Functions called by the kernel have access to system space, and have the ability to call modules and drivers to complete the task.