Читаем Windows® Internals, Sixth Edition, Part 1 полностью

To see the handler on 32-bit systems for the interrupt 2E version of the system call dispatcher, type !idt 2e in the kernel debugger.lkd> !idt 2e Dumping IDT: 2e: 8208c8ee nt!KiSystemService

To see the handler for the sysenter version, use the rdmsr debugger command to read from the MSR register 0x176, which stores the handler:lkd> rdmsr 176 msr[176] = 00000000'8208c9c0 lkd> ln 00000000'8208c9c0 (8208c9c0) nt!KiFastCallEntry

If you have a 64-bit machine, you can look at the 64-bit service call dispatcher by repeating this step, but using the 0xC0000082 MSR instead, which is used by the syscall version for 64-bit code. You will see it corresponds to nt!KiSystemCall64:lkd> rdmsr c0000082 msr[c0000082] = fffff800'01a71ec0 lkd> ln fffff800'01a71ec0 (fffff800'01a71ec0) nt!KiSystemCall64

You can disassemble the KiSystemService or KiSystemCall64 routine with the u command. On a 32-bit system, you’ll eventually notice the following instructions:nt!KiSystemService+0x7b: 8208c969 897d04 mov dword ptr [ebp+4],edi 8208c96c fb sti 8208c96d e9dd000000 jmp nt!KiFastCallEntry+0x8f (8208ca4f)

Because the actual system call dispatching operations are common regardless of the mechanism used to reach the handler, the older interrupt-based handler simply calls into the middle of the newer sysenter-based handler to perform the same generic tasks. The only parts of the handlers that are different are related to the generation of the trap frame and the setup of certain registers.

At boot time, 32-bit Windows detects the type of processor on which it’s executing and sets up the appropriate system call code to use by storing a pointer to the correct code in the SharedUserData structure. The system service code for NtReadFile in user mode looks like this:0:000> u ntdll!NtReadFile ntdll!ZwReadFile: 77020074 b802010000 mov eax,102h 77020079 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300) 7702007e ff12 call dword ptr [edx] 77020080 c22400 ret 24h 77020083 90 nop

The system service number is 0x102 (258 in decimal), and the call instruction executes the system service dispatch code set up by the kernel, whose pointer is at address 0x7ffe0300. (This corresponds to the SystemCallStub member of the KUSER_SHARED_DATA structure, which starts at 0x7FFE0000.) Because the following output was taken from an Intel Core 2 Duo, it contains a pointer to sysenter:0:000> dd SharedUserData!SystemCallStub l 1 7ffe0300 77020f30 0:000> u 77020f30 ntdll!KiFastSystemCall: 77020f30 8bd4 mov edx,esp 77020f32 0f34 sysenter

Because 64-bit systems have only one mechanism for performing system calls, the system service entry points in Ntdll.dll use the syscall instruction directly, as shown here:ntdll!NtReadFile: 00000000'77f9fc60 4c8bd1 mov r10,rcx 00000000'77f9fc63 b810200000 mov eax,0x102 00000000'77f9fc68 0f05 syscall 00000000'77f9fc6a c3 ret Kernel-Mode System Service Dispatching

As Figure 3-15 illustrates, the kernel uses the system call number to locate the system service information in the system service dispatch table. On 32-bit systems, this table is similar to the interrupt dispatch table described earlier in the chapter except that each entry contains a pointer to a system service rather than to an interrupt-handling routine. On 64-bit systems, the table is implemented slightly differently—instead of containing pointers to the system service, it contains offsets relative to the table itself. This addressing mechanism is more suited to the x64 application binary interface (ABI) and instruction-encoding format.

Note

System service numbers can change between service packs—Microsoft occasionally adds or removes system services, and the system service numbers are generated automatically as part of a kernel compile.

Figure 3-15. System service exceptions

Перейти на страницу:

Похожие книги