|Informative Information for the Uninformed
The Windows NT kernel uses an object-oriented approach to representing resources such as files, drivers, devices, processes, threads, and so on. Each object is categorized by an object type. This object type categorization provides a way for the kernel to support common actions that should be applied to objects of the same type, among other things. Under this design, each object is associated with only one object type. For example, process objects are associated with the nt!PsProcessType object type. The structure used to represent an object type is the OBJECT_TYPE structure which contains a nested structure named OBJECT_TYPE_INITIALIZER. It's this second structure that provides some particularly interesting fields that can be used in a backdoor.
As one might expect, the fields of most interest are function pointers. These function pointers, if non-null, are called by the kernel at certain points during the lifetime of an object that is associated with a particular object type. The following debugger output shows the function pointer fields:
kd> dt nt!_OBJECT_TYPE_INITIALIZER ... +0x02c DumpProcedure : Ptr32 +0x030 OpenProcedure : Ptr32 +0x034 CloseProcedure : Ptr32 +0x038 DeleteProcedure : Ptr32 +0x03c ParseProcedure : Ptr32 +0x040 SecurityProcedure : Ptr32 +0x044 QueryNameProcedure : Ptr32 +0x048 OkayToCloseProcedure : Ptr32
Two fairly easy to understand procedures are OpenProcedure and CloseProcedure. These function pointers are called when an object of a given type is opened and closed, respectively. This gives the object type initializer a chance to perform some common operation on an instance of an object type. In the case of a backdoor, this exposes a mechanism through which arbitrary code could be executed in kernel-mode whenever an object of a given type is opened or closed.
Category: Type IIa
Origin: Matt Conover gave an excellent presentation on how object type initializers can be used to detect rootkits at XCon 2005. Conversely, they can also be used to backdoor the system. The authors are not aware of public examples prior to Conover's presentation. Greg Hoglund also mentions this type of approach in June, 2006.
Capabilities: Kernel-mode code execution.
Considerations: There are no unique considerations involved in the use of this technique.
Covertness: This technique can be detected by tools designed to validate the state of object type initializers against a known-good state. Currently, the authors are not aware of any tools that perform this type of check.