Talk about Windows NT2000 Environment Switch (http:webcrazy.yeah.net)

xiaoxiao2021-03-06  37

Talk about Windows NT / 2000 Environment Switching

Webcrazy

TSU00@263.net)

The thread is the most basic unit of Windows NT / 2000 environment. In <<

Analysis of Windows NT / 2000 Environment Switch >>

NSFOCUS MAGAZINE 12) One article, I only discussed the process CR3 switching, but did not involve the contents of thread scheduling, this article will try to talk about these parts. Before this, let's take a look at the following code:

// -----------------------------------------------

//

// Enumthreads-Information from KPEB and KTEB

// ONLY TEST ON Windows 2000 Server Chinese Edition

// build 2195 (free)! Programmed by Webcrazy

//

TSU00@263.net) on 5-23-2000!

//

// -----------------------------------------------

#define kteblistoffsetkpeb 0x50

#define pidoffset 0x9c

#define kpeblistoffset 0xA0

#define processnameoffset 0x1fc

#define stacktopoffset 0x18

#define stackbtmoffset 0x1c

#define userteboffset 0x20

#define stackptroffset 0x28

#define kteblistoffset 0x1a4

#define ktebpidoffset 0x1e0

#define tidoffset 0x1e4

Void DisplaythreadFromkpeb (Void * KPEB)

{

Char processname [16];

Ulong PID;

Ulong TID;

Ulong StackBTM, StackTop, StackPtr, UseERTEB

PLIST_ENTRY KTEBLISTHEAD, KTEBListptr;

Kteblisthead = kteblistptr = (PLIST_ENTRY) ((int) kpeb kteblistoffsetkpeb);

DO

{

Void * kteb;

KTEB = (void *) ((* (Ulong *) kteblistptr) -kteblistoffset;

TID = * (ulong *) ((char *) kteb) Tidoffset;

Stackbtm = * (Ulong *) ((char *) kteb) stackbtmoffset;

Stacktop = * (ulong *) ((char *) kteb) stacktopoffset;

StackPtr = * (Ulong *) ((char *) KTEB) StackPtroffset;

Userteb = * (ulong *) ((char *) kteb) userteboffset;

MEMSET (ProcessName, 0, Sizeof (ProcessName);

Memcpy (ProcessName, ((char *) KPEB) ProcessNameOffset, 16);

PID = * (ulong *) ((char *) KPEB) PIDOFFSET); // or pid = * (ulong *) ((char *) KTEB) KTEBPIDOffset;

DBGPRINT ("% 04x% 08x% 08x% 08x% 08x% 08x% s (% x) / N",

TID, KTEB, StackBTM, Stacktop, StackPTR, UserTeb, ProcessName, PIDs;

Kteblistptr = kteblistptr-> flink;

} while (kteblistptr-> flink! = kteblisthead);

}

Void enumthreads ()

{

PLIST_ENTRY KPEBLISTHEAD, KPEBListptr;

IF ((USHORT) NTBUILDNUMBER! = 2195) {

DBGPRINT ("Only Test On Windows 2000 Server Build 2195! / N");

Return;

}

DBGPRINT ("/ N Tid Kteb Addr StackBTM StackTop StackPtr User Teb Process

Name (PID) ");

DBGPRINT ("/ N ---- ------------------------------------ --------

----- ----- / n ");

Kpeblisthead = kpeblistptr = (pLIST_ENTRY) ((char *) psinitialsystemprocess kpeblistoffset);

While (Kpeblistptr-> Flink! = kpeblisthead) {

Void * KPEB;

KPEB = (void *) ((char *) kpeblistptr) - kpeblistoffset;

DisplaythreadFromkpeb (KPEB);

DBGPRINT ("/ n");

Kpeblistptr = kpeblistptr-> flink;

}

}

The results listed in this code listed in Windows 2000 Server Build 2195 are as follows:

TID KTEB AddR StackBTM StackTop StackPtr User Teb Process Name (PID)

---- -------- ---------------------------------- -----------

0004 Fe4e19e0 F9019000 F901C000 F901B9C4 00000000 System (8)

000c fe4e0c80 F9021000 F9024000 F9023D34 00000000 System (8)

0010 Fe4e0a00 F9025000 F9028000 F9027D34 00000000 System (8)

0014 Fe4E0780 F9029000 F902C000 F902BD34 00000000 System (8)

0018 Fe4e0500 F902D000 F9030000 F902FD34 00000000 System (8)

001c fe4e0280 F9031000 F9034000 F9033D34 000000 System (8)

.

.(slightly)

.

From the operational results, you can see that EnumThreads is mainly to implement all the current threads currently, the above output format is consistent with the Softice's thread command. Some undocumented KPEB / KTEB data items are used in the code: 1. Procedure of the process

This is an item of a list_entry structure (occupying two 32-bit pointers, 8 bytes), located at 50 hours after KPEB, the above code is represented by KteblistoffSetkpeb.

2. Thread chain table offset relative to KTEB

Located 1A4H after KTEB (KteblistoffSet Definition).

In the output, please refer to << Softice Command Reference >> in the output results, and in the kteb position, please see the definition before the code.

After understanding the underlying code of the EnumThreads program with the realization of EnumProcesses, I also understood how Windows NT / 2000 organizes, manages process and threads, which is critical to understanding threads. Although so but want to discuss the schedule, then look at several important data (I no longer specify how to get the specific location of these data, if you want to know or suggest you look at <<

Analysis of Windows NT / 2000 Environment Switching >>):

1. Process status // kpeb 65h uchar

Typical processes are: Running, Ready and IDLE.

It should be noted that there is only one process in the running state in the machine of a single processor, and it is not subject to this value in the KPEB, and the system is obtained by calling the IOGETCURRENTPROCESS kernel routine. I am in <<

That talk about Windows NT / 2000 internal data structure >> More detailed introductions for IOGETCurrentProcess.

When the Status value is 0 in the KPEB, the process status is Ready; 1 when the process status is IDLE; 2, the process status is transition, and so on.

The thread as mentioned above is the basic unit of Windows NT / 2000 environment. It actually does not executes the process, the process status and the process priority will be mentioned below is very abstract, but the system is called when the system is called. Scope limit, Microsoft proposes these concepts. I want to hide the internal Thread scheduling behavior of the system. However, if there is a thread state, it is not said that it will be included. Once I once changed the status of the System process from Ready to Transition, I could only look at the program code on the screen. Because the system has become lazy, it is no longer responsive to me.

2. Thread status // kteb 2DH Uchar

A member State in KTEB is mainly to point out the current thread state, which is located at KTEB 2D (single byte). It mainly has the following values ​​(value from Softice output):

0 - INITIALIZED (indicating that the value of State is 0, indicating the thread status is initialized, the following class is the same)

1 - Ready

2 - Running

3 - Standby

4 - Terminated

5 - waiting

6 - Transition

So described in David Solomon and Mark Russinovich << Inside Microsoft Windows 2000, Third Edition >>:

To quote:

------------

The Thread State Is Are As Follows:

Ready

When loops for a thread to execute, the dispatcher considers only the pool of threads in the

Ready State. These Threads Are Simply Waiting to Execute.

STANDBY

A Thread in The Standby State Has Been Selected To Run Next ON A Particular Processor. By

.

Running

Once the dispatcher performs a context switch to a thread, The Thread Enters the Running, THEAD

State and Executes. The Thread's Execution Continues Until The Kernel Preempts It To Run A Higher Priority Thread, ITS Quantum Ends, IT Terminates, or It Voluntarily Enters The Wait State.

Waiting

A thread can enter the wait state in several ways: a thread can voluntarily wait on an object to synchronize its execution, the operating system (the I / O system, for example) can wait on the thread's behalf, or an environment subsystem can direct THREAD To Suspend Itself. When the Thread's Wait Ends, Depending on The Priority, The Thread Either Begins Running Immediately or Is

Moved Back to the Ready State.

Transition

A Thread Entes the Transition State if IT ITY for Execution But ITS Kernel Stack IS

Paged Out of Memory. for Example, The Thread's Keernel Stack Might Be Paged Out of Memory. Once

ITS Kernel Stack Is Brought Back Into Memory, The Thread Enters The Ready State.

Terminated

When a Thread Finishes Executing, It Enters The Terminated State. Once Terminated, A Thread

Object Might or Might Not Be deleted. (The Object Manager Sets Policy Regarding When To Delete

The object.) IF The Executive Has A Pointer To The Thread Object, IT CAN Reinitialize The Thread

Object and use it..

Initialized

Used ISALLY WHILE A THREAD IS Being Created.

------------

I mainly analyze the status of Waiting below:

In Windows NT / 2000, the line can call KewaitForsingleObject, KewaitFormultiPleObjects, etc., automatically abandon its total amount of execution time (Quantum). The currently executed thread is specified by the Processor Control Block (PRCB, Note to the Processor Control Region) in the system. Remember how I introduced how to get the current thread (Take the DWord value in the fs: 124h)? It is actually a member of this CurrentThread. The definition of PRCB kprcb is in NTDDK.H. The system obtains the KPRCB pointer through the following functions: _kegetCurrentPRCB

0008: 80465310 MOV EAX, [FFDFF020] Take KPCR (Processor Control Region member PRCB

0008: 80465315 RET

The current thread state of the system is Running. Other thread status is made (usually the maximum THREAD_WAIT_Objects 1, otherwise the BSOD will appear, but Microsoft also defines a maximum_wait_objects, which is to see the parameters you pass to the system) The Kwait_Block structure represents these values, and below Talking about Kwait_reason that thread wait reasons can also be found from NTDDK.H. The thread kwait_block structure data is at KTEB 6CH. Last time I mentioned two cases of CONTEXT SWITCH, either use Event, Semphore and other synchronous objects, or you can use the Timer kernel object, which can form a thread waiting for the column to indicate the current state of the thread.

Due to kwait_block, kwait_reason, there is a few DocuMENTED members in Windows NT / 2000, you can read the thread waiting queue after knowing the specific location of kwait_block. But Softice has presented all of these internal structures.

From the above analysis, for thread state, involve more content, I will copy some of the analytical CDs as follows:

: u_kereadstatethread

_KereadStatethread

0008: 8042F029 MOV EAX, [ESP 04]

0008: 8042F02D MOV Al, [EAX 04]

0008: 8042F030 RET 0004

: bpx_kereadstatethreadiffness (tid == _ TID)

: BL // This command is exited after the debugger

00) BPX _kereadStateThread IF (TID == 0x3bc)

Break due to bpx _kereadstatethread if (tid == 0x3bc) (et = 22.28 seconds)

// Analyze the first parameter of _kereadStateThread (also the only parameter)

: What dword (@ (ESP 04)) / / You should understand each thread, each thread state is determined by which kernel object is not fixed.

The value ff6811e0 is (a) kernel Timer Object (Handle = 0230) for Explorer (398)

| | |

| _Timer kernel object | _ This object is in the handle of the Explorer process

: Timer DWORD (@ (ESP 04)))

Timer Object At ff6811e0

Dispatcher Type: 08

Dispatcher Size: 000A

Signal State: SIGNALED

.

.(slightly)

.

// Softice's Timer command is just to read Timer object data

// So you can directly read the signage member (see NTDDK.H) // below DISPATCHER_HEADER (see ntddk.h) // below

:? #BYTE (@ (@ (ESP 04) 4)))

00000001 0000000001 "" // 1 represents SIGNALED, do you try it from 1 to 0? (Change from Signaled to Not Signaled)

This thread of the above analysis is the current state of the Timer object (Object Pointer: 0xFF6811E0) (Jeffrey Richter said signaled represents the When Time Comes DUE). I have been analyzed from the easiest way, many threads current state often depends not only on an object, but the Thread Wait List in Softice is the concept.

Talking about the object that allows the thread waiting, now kwait_reason, there is a member of Thread Wait Reason, which is located at the KTEB offset 57h, occupying a char space, strictly said that this is true It is said that the thread is in the WAIT state. The above discussion is only explained what kernel objects have caused this Wait Reason. DDK Documentation is this definition Wait Reason

Waitreason

Specifies the reason for the wait. A driver should set this value to Executive, unless it is doing work on behalf of a user and is running in the context of a user thread, in which case it should set this value to UserRequest.

Whether the user thread is a single-character member located at another 55h offset by KTEB, which represents the kernel mode, 1 represents user mode. The above mentioned that WAIT REASON is most common in driver programming (not the most common in the system's core code): Executive and UserRequest, as for other values, see NTDDK.H.

3. Process priority (KPEB 62H), thread basic priority (BasePriority, KTEB 68H), thread dynamic priority (Dyn Priority, KTEB 33H)

These three values ​​each take up one byte. The Thread Dyn Priority is displayed as Current Priority in Spy , while some gadgets in Microsoft's Windbg and Windows 2000 Server Resource Kit are represented by PRIORITY, but in Softice is displayed as Dyn Priority. . Since it is directly used in priority, it is not easy to express so much priority. In view of all the contents of my text, I will use the name in Softice in this article. In fact, Microsoft also provides priorityDecrement in the KTEB structure to make the system to dynamically change the current priority, which is one of the reasons I prefer to use Dyn Priority. For more detailed discussion of these priorities, see << Windows NT Device Driver Development >> in the reference, which is more description of these values ​​of the core state.

4. Thread relatives (Affinity)

Since I have no conditional testing machines, I am not good to say, and I hope you can talk about it.

5. Thread QUANTUM

Single bytes, located at KTEB 6B. It is pointed out that the CPU can make the total amount of time (quantum). There are three _kthread (kteb) structures in Processor Control Block, NexTthread and IDLethread, which represent threads that are executing with the system current processor, will be called, the iDle thread usually Just simply call kiidleloop until the new interruption is coming to call other threads. Windows NT / 2000 calls kiquantumend to determine if the current thread is used in the total amount of time, if the current thread has already executed QUANTUM, then returns nextthread in KPRCB, NEXTTHREAD, as the next thread as the system call. The system is looking for the next READY state by calling KifIndReadythread. _Kiquantumend

0008: 804315B9 PUSH EBP

0008: 804315BA MOV EBP, ESP

0008: 804315BC PUSH ECX

0008: 804315BD PUSH EBX

0008: 804315BE PUSH ESI

0008: 804315BF Push EDI

0008: 804315C0 MOV EAX, DS: [ffdff020]; kprcb-> eax

0008: 804315C6 MOV EDI, EAX; KPRCB-> EDI

0008: 804315C8 MOV EAX, FS: [00000124]; Current Thread's Kteb-> EAX

0008: 804315CE MOV ESI, Eax; Current Thread's Kteb-> ESI

0008: 804315d0 call [__imp__keraiseirqltodpclevel]; upgrade IRQL to Dispatch_level,

DDK friends should be more familiar

0008: 804315D6 XOR EBX, EBX

0008: 804315D8 MOV [EBP-01], Al; Save OLD IRQL

0008: 804315dB CMP [ESI 6B], BL; Judging the Quantum of the current thread

0008: 804315DE JG 804315F2; get NextThread at Quantum less than or equal to 0

0008: 804315E0 MOV EAX, [ESI 44]

0008: 804315E3 CMP [EAX 69], BL

0008: 804315E6 JZ 80431608

0008: 804315E8 CMP BYTE PTR [ESI 33], 10

0008: 804315EC JL 80431608

0008: 804315EE MOV BYTE PTR [ESI 6B], 7F

0008: 804315F2 MOV ESI, [EDI 08]; KPRCB's Nextthread-> ESI

0008: 804315F5 CMP ESI, EBX; KPRCB's nextthread is empty

0008: 804315F7 JNZ 804316010008: 804315F9 MOV CL, [EBP-01]

@ 504315FC Call @KiunlockdispatcherDatabase

0008: 80431601 MOV EAX, ESI; return NextTHREAD

0008: 80431603 POP EDI

0008: 80431604 POP ESI

0008: 80431605 POP EBX

0008: 80431606 Leave

0008: 80431607 RET

0008: 80431608 Movsx EDX, Byte Ptr [ESI 33]

.

(The code is very long, involving the scheduling algorithm, it seems that you can only take care of yourself)

.

6. KPEB (Kteb 22ch) of the process belonging to the thread

It is mainly easier to exchange some data exchange between KTEB and KPEB.

In fact, the above-mentioned internal data can also find the implementation of the corresponding function in Linux, such as the Thread Quantum in Windows NT / 2000 corresponding to Counter members in Linux Task_struct. I am in <<

Analysis of Windows NT / 2000 Environment Switching >> In the case of the case where the WINDOWS NT / 2000 actually occurs, there are only two cases. I also give some code for time interrupt, give SwapContext (mainly CR3 switching) code. Each process in Windows has a private memory space, and private kernel objects (handle table handle table), etc., all implemented on environmental switching, and is also the basis of an operating system Robustness and reliability.

Many articles in http://www.research.microsoft.com/ have verified this, and you can go through it. About this part of the implementation you can also look at some of the routines (limited to space I no longer list code):

⊙ kifindreadythread

⊙ kireadythread

⊙ KiswaPthread

⊙ SwapContext

Where SwapContext and KiswaPthread are the code that is really switched, is it often seen in Stack Trace, which you should be easier to understand. (For Stack TRACE See the Anatomy of A Stack TRACE segment in DDK Documentation or Softice Command Reference explains the explanation of Stack and thread commands)

Another thread automatically waives the implementation, tracking KeWaitForsingleObject, KESETEVENT, etc., take Event Object to give an example, because you know the EVENT structure, you can change your DISPATCHER_HEADER in your experiment machine. Members change the Object status, see if it is CLEAR or Signalled (I gave it to how to implement it with Softice). Even the code you got up (in fact, it is only read out the data in a two-way linked list. If it is in Linux, I believe that you have not patiently see this), and understand the kwait_block office After defining the Thread Wait List, just give you a kernel debugger, I believe which thread you want to block which thread is, plus it to understand the thread priority, you want to use which threads can use the CPU time. But I don't guarantee whether you have Robustness and Reliability at this time.

Or by the By, the Scheduled Code is running on the Dispatch_level IRQL in Dispatch_level IRQL, which has been prevented from being interrupted in the ordinary code of Passive_level.

Jeffrey Richter I have pointed out in << Programming Applications for Microsoft Windows, Four Edition >>:

Microsoft Doesn't Fully Document The Behavior of The Scheduler.⊙ Microsoft Doesn't Let Applications Take Full Advantage of The Scheduler's Features.

Microsoft Tells You That The Scheduler's Algorithm Is Subject To change so this you

CAN code Defensively.

From these points, Microsoft did not fix the scheduling behavior, in fact, Windows NT 4.0 and Windows 2000 have different in the scheduling algorithm, and all the code mentioned in this article is taken from or only in Windows 2000 Server Build 2195. Over.

My friends who have learned to DDK should all know that PSSetCreateProcessNotifyRoutine and PSSetCreatethreadNotifyRoutine These Fully Documented routines that call the callback function when the user registration system is built with the delete process or thread, know that they are the most important thing for Mark Russinovich's NTPMON implementation. Two functions. In fact, in Windows 2000, Microsoft also provides functions related to environmental switches, KESETSWAPCONTEXTNOTIFYROUTINE, but these two functions are undocumented, and they can only run on a specific version of Windows 2000 (please check MSDN Magazine) ).

All the code in Linux is open, but it is really difficult to understand the dispatching code, let alone complicated than Linux (I haven't already browsed Linux 2.4.x source code, I said that purely personal feelings) and only Windows NT / 2000 can be searched in a large pile of assembly code, the difficulty of its analysis is really imagined. So I hope you can tell me the wrong or missing instructions in the text (

Tsu00@263.net), thank you!

Reference:

1.jeffrey richter

<< Programming Applications for Microsoft Windows, Fourth Edition >>

2.peter Viscola And Anthony Mason << Windows NT Device Driver Developments >>

3.Numega << Softice Command Reference >>

4.Windows 2000 DDK Documentation

5. David Solomon and Mark Russinovich << Inside Microsoft Windows 2000, Third Edition >>

转载请注明原文地址:https://www.9cbs.com/read-62240.html

New Post(0)