Rootkits: Subverting the Windows Kernel
< Day Day Up > |
Some of the tables that the CPU uses to keep track of things can contain descriptors. There are several types of descriptors, and they can be inserted or modified by a rootkit. The Global Descriptor Table
A number of interesting tricks may be implemented via the GDT. The GDT can be used to map different address ranges. It can also be used to cause task switches. The base address of the GDT can be found using the SGDT instruction. You can alter the location of the GDT using the LGDT instruction. The Local Descriptor Table
The LDT allows each task to have a set of unique descriptors. A bit known as the table-indicator bit can select between the GDT and the LDT when a segment is specified. The LDT can contain the same types of descriptors as the GDT. Code Segments
When accessing code memory, the CPU uses the segment specified in the code segment (CS) register. A code segment can be specified in the descriptor table. Any program, including a rootkit, can change the CS register by issuing a far call, far jump, or far return, where CS is popped from the top of the stack.[6] It is interesting to note that you can make your code execute only by setting the R bit to zero in the descriptor. [6] An IRET instruction can also be used. Call Gates
A special kind of descriptor, called a call gate, can be placed in the LDT or the GDT. A program can make a far call with the descriptor set to the call gate. When the call occurs, a new ring level can be specified. A call gate could be used to allow a user-mode program to make a function call into kernel mode. This would be an interesting back door for a rootkit program. The same mechanism can be used with a far jump, but only when the call gate is of the same privilege level or lower than process performing the jump.[7] [7] The exception is a far jump to a "conforming" code segment. When a call gate is used, the address is ignored only the descriptor number matters. The call gate data structure tells the CPU where the code for the called function lives. Optionally, arguments can be read from the stack. For example, a call gate could be created such that the caller puts secret command arguments onto the stack. |
< Day Day Up > |