Reversing : The Hacker's Guide to Reverse Engineering

(ff) #1

An interesting aspect of the Windows architecture is that the kernel is pre-
emptiveand interruptible, meaning that a thread can usually be interrupted
while running in kernel mode just as it can be interrupted while running in
user mode. For example, virtually every Win32 API is interruptible, as are
most internal kernel components. Unsurprisingly, there are some components
or code areas that can’t be interrupted (think of what would happen if the
scheduler itself got interrupted.. .), but these are usually very brief passages
of code.


Context Switching


People sometimes find it hard to envision the process of how a multithreaded
kernel achieves concurrency with multiple threads, but it’s really quite simple.
The first step is for the kernel to let a thread run. All this means in reality is to
load its context (this means entering the correct memory address space and ini-
tializing the values of all CPU registers) and let it start running. The thread
then runs normally on the processor (the kernel isn’t doing anything special at
this point), until the time comes to switch to a new thread. Before we discuss
the actual process of switching contexts, let’s talk about how and why a thread
is interrupted.
The truth is that threads frequently just give up the CPU on their own voli-
tion, and the kernel doesn’t even have to actually interrupt them. This hap-
pens whenever a program is waiting for something. In Windows one of the
most common examples is when a program calls the GetMessageWin32 API.
GetMessageis called all the time—it is how applications ask the system if the
user has generated any new input events (such as touching the mouse or key-
board). In most cases, GetMessageaccesses a message queue and just extracts
the next event, but in some cases there just aren’t any messages in the queue.
In such cases, GetMessagejust enters a waiting mode and doesn’t return
until new user input becomes available. Effectively what happens at this point
is that GetMessageis telling the kernel: “I’m all done for now, wake me up
when a new input event comes in.” At this point the kernel saves the entire
processor state and switches to run another thread. This makes a lot of sense
because one wouldn’t want the processor to just stall because a single program
is idling at the moment—perhaps other programs could use the CPU.
Of course, GetMessageis just an example—there are dozens of other cases.
Consider for example what happens when an applications performs a slow
I/O operation such as reading data from the network or from a relatively slow
storage device such as a DVD. Instead of just waiting for the operation to com-
plete, the kernel switches to run another thread while the hardware is per-
forming the operation. The kernel then goes back to running that thread when
the operation is completed.


Windows Fundamentals 85
Free download pdf