hello_world_logo.gif (12859 bytes) maple_leaf.gif (1004 bytes)

This could be your company's banner advertisement

April 1999

Issue 2, Volume 1

About the Author

Ognen Duzlevski

Ognen Duzlevski
is a computer science student at the University of Saskatchewan.

University of Saskatchewan


Hello World!
Editorial
News
Comics
Events
 
Sponsors
 
Hello World! Teams:
  Editors
  Sponsorship
  Site Design
 
Member Universities
 
Past Issues
 
Contact Us
   
   

Site hosting provided by
smarttbutton.gif (2795 bytes)

   

Microsoft Windows NT (In)security Model

-- Ognen Duzlevski

Don’t get me wrong. No operating system is secure. Thus the "in" before "security model" - it has nothing to do with not liking Microsoft. The same name would have gone nicely with any other OS for the masses. In order to understand NT's security model one needs to understand the underlying structure of this (quite complex) operating system. Before ever working with NT, I was (naturally) a Linux user (well, OK, we wont talk about DOS times now). I say "naturally" because in academic environments (such as Universities) most of the machines are usually (one kind or the other) UNIX boxes. Of course, working with Solaris or Linux or Digital UNIX I brushed off any mention of Windows NT as a serious OS (this usually comes from lack of knowledge, not from excess of it). But, having the time to get deeper into it - I find it to be pretty fascinating. Perhaps a bit to complex – but it is obviously well suited for Microsoft's business model. Not everyone has the luxury of coming out with a new version of their operating system every once in a while. So, I decided to undo the injustice and treat NT in this article. After all, people should know.

Microsoft Windows NT - How It Works

First a bit of OS theory. There are several models of how one goes about building an operating system. A while ago we had the monolithic model where OS code ran pretty much unorganized all over the memory space. One can deduce for oneself that this model gave little to scalability, maintenance and ultimately, security. A nice improvement to this would be the layered model. Here, only code from a higher level can call upon the routines in lower levels. Thus, debugging, maintenance and overall security are much improved. However, this model alone is not used. This comes naturally, because there is a better approach - the client/server model. When one connects layers with client/server model, one gets Windows NT. Layers are a good way to utilize hardware protection that the latest CPU models offer. Intel CPUs themselves define four levels (or rings) where applications (including OSs) can run. Of course, ring0 is reserved exclusively for the OS (and Windows NT is no stranger). However, as NT also runs on Digital's (now Compaq's) Alphas and used to run on MIPS and PowerPC (all of them being RISCs), NT only utilizes two protection levels - one is the user mode and other the kernel mode.  In theory, the client/server model divides the OS clearly into servers - pieces of code that implement the file system, process and memory management and other vital components. User applications and even kernel parts are users of the services provided by these servers. The one responsible for communication between servers and clients is the microkernel - the only part that should be implemented within privileged CPU levels. Also in theory, the kernel should be minimal in order to make it maintainable, scalable, easier to control etc. And the educational Mach kernels (that started all of this) are implemented that way. However, for a commercial OS to be fast and secure, most of it's code will run within the kernel mode, for the simple reason that the context switches between kernel and user mode (when passing messages back and forth) would just eat up to much time. For this reason, even the graphics and controls services provided by NT are running from within kernel level. Some would say that one could implement at least graphics and controls as user-mode servers which would make the OS more stable. However, if we stop and think about it for a moment - what good if user-mode implemented graphics server crashes and it does not crash the whole OS when the whole OS will be unusable without the graphics routines anyway? 

After the main model come(s)...smaller model(s), what else?

Most of the Windows NT OS is implemented in C (with some assembler for time-sensitive and low-level parts) and a bit of C++ for the graphics routines. The OS is not object-oriented in the OOP sense, however it heavily relies on the notion of objects, subsystems and alike. 

The overall structure of NT's implementation is the following -> first off, there are two modes of operation, user and kernel. Within user mode are the system processes, services, subsystems and applications. Within kernel mode are the executive, the kernel, HAL, the device drivers, the GDI (Graphics Device Interface) and user functions. Between user and kernel mode stands NTDLL.DLL - a bridge translating (un)documented user API calls to (un)documented executive calls. 

First off, the subsystem(s)

There are initially three subsystems that ship with NT (and nothing stops you from adding your own fourth one). The subsystems are Win32, Posix and OS/2. For those of you who dont know, IEEE Posix 1003.1-1990 is a standard outlining functions that should be present in an operating system (to support portability). Windows NT only implements the minimal set required for it to earn Posix certification so it is not exactly the ultimate Unix->NT->Unix porting and development environment. The same goes for the OS/2 subsystem which only supports 16-bit OS/2 1.2 character and video based applications. Knowing that OS/2 Warp 3.0 and 4.0 are 32-bit, very powerful operating systems, one can immediately get the notion of the usefulness of NT's OS/2 subsystem. The third and most important piece of these subsystems is the Win32. It is NT's complete API bridge of (un)documented calls to the operating system. It is what applications (and programmers) have at their disposal when programming the NT. The API calls implemented in the NT are the superset of the API calls present in Windows 95 and 98, with exception of some calls dealing with PnP and some others. However, Windows NT 5.0 is supposed to implement the 'real' API superset. Win32 is NT's native interface and is the one that does all the job beneath any other subsystems - Posix and OS/2 calls are translated to Win32 API calls and further passed down to the executive. Of course, when programming Windows (and just to make things sweater) one is not allowed to mix the calls between subsystems in the same application. The Win32 subsystem is implemented in the image CSRSS.EXE and provides basic support for: 

  • Console windows
  • Process and thread creation and deletion
  • some support for 16-bit Virtual DOS machine (VDM)
  • other functions

Win32 subsystem also consists of the WIN32K.SYS, a kernel-mode device driver that provides I/O support, user message passing to applications (and back), the GDI (Graphical Device Interface) - a library of functions dealing with graphics output devices. Within Win32 are also subsystem .DLLs like USER32, ADVAPI32 and KERNEL32 - their job is to translate Win32 API calls to undocumented internal calls to NTOSKRNL.EXE and WIN32K.SYS. Finally, last part of the Win32 subsystem are the graphics device drivers that are hardware dependant and generally provide support for display devices like printers and video cards. The role of GDI becomes obvious here where it provides a set of higher level encapsulation functions that enable transparent communication between the applications and the hardware. For example, an application calls API to draw a circle, this call reaches the GDI which "knows" whether the hardware is capable of drawing this circle or it has to be "spelled out" pixel-by-pixel. The actual drawing is done via commanding the graphical device drivers. All of this is hidden from the programmer and ultimately the user, something we should all thank Microsoft for.  

NTDLL.DLL

This is a support library for all of the subsystems, services and applications. A user processes use this .DLL. NTDLL enables translation interface services between user-mode applications and the kernel-mode executive. Naturally, NTDLL runs in user mode.

The executive

A funny piece of software, runs on top of the "real" kernel and does the overhead policy decisions regarding (virtual) memory management, process and thread management, security checks (Security Reference Monitor), I/O system and cache management. It provides a set of functions that are exported to user-mode apps through NTDLL.DLL, a set of functions callable from user mode but are undocumented, a set of functions documented in the NT DDK (that's NT's development kit) and executable only within kernel mode (mostly for device drivers), a set of undocumented functions callable within kernel mode and a set of functions internal to the kernel components. Besides doing the above (as if it wasn’t enough), the  executive (which is the "politician of the OS") also provides object management (logically, through an object manager), the LPC (Local Procedure Calls - a refined version of Remote Procedure Calls or RPC) facility, a broad set of mathematical, string and other run-time functions and the executive support routines. And besides this it even...naaaah, that is all. 

The Kernel

Low level "part" of NTOSKRNL.EXE, the one that does the "dirty" work - the kernel is the raw object provider for the executive. And just to be on the fair side (if there is one), the executive is not the only one providing policy decisions for the OS, the kernel does this when thread and process scheduling and dispatching is in question. The kernel also indulges itself into trap, interrupt and exception handling and dispatching (something we will talk about in the May article) and multi-CPU synchronization. However, it's the most important function is to provide raw kernel objects to the executive, which then adds the policy overhead (like object names, handles, reference counters etc.). When we say "kernel objects" we usually mean system resources. Two types of these objects are present - control and dispatcher objects. Control objects are the kernel process object (a process is the whole memory space assigned to it, together with this control object and all the threads executing within the process - technically a process does not execute, it is the main thread that is doing this), APC (Asynchronous procedure call interrupts) object, DPC (Dispatched or Deferred Procedure Calls) object, interrupt object etc. The dispatcher objects are involved with thread synchronization (also will be visited in the May article) and among these are the mutex (or the mutant), event, semaphore, timer, waitable timer, event pair etc. 

Hardware support

The job of the kernel (as being low-level) is to provide the architecturally specific routines that (try to) abstract the architectural differences and provide a coherent interface to the outside world. Being a properly written OS, NT implements the kernel this way. Most of the routines within the kernel are written with common code in mind. They heavily rely on a structure closest to the hardware (and the one actually dependant on the architecture) - the HAL (Hardware Abstraction Layer).  It is "the" low-level interface to the system and is there mainly for clarity, maintainability and (most important) portability purposes. You are welcome to sit down and write your own HAL, one that will take your specific architectural differences and exploit them rightly (well, actually, if it was "that" easy, I wouldn’t be sitting here and still taking classes). Other examples of the kinds of services this part of the kernel provides are context switching (threads run part of their time in user-mode and part in kernel-mode), provision of a (lookaside) translation buffer and CPU cache support.  

Device Drivers - commonly known as .SYSes

These are loadable kernel-mode modules (just as HAL.DLL is) and provide the interface between the HAL as the mediator to the hardware (or actually between the naked hardware) and the I/O subsystem within the OS. Their functions are activated mostly as a result of an interrupt request which these drivers are supposed to service (and we will see the exact procedure in the May article when we write such a driver). Device drivers run in one of three contexts - user-mode, kernel-mode or in arbitrary thread context (this is the interrupt servicing part). There are four different kinds of device drivers: 

  • Hardware DDs (manipulate hardware i/o devices)
  • File System Drivers (interception of file-oriented i/o requests and their translation into i/o requests bound to specific device)
  • Filter drivers (or interceptors, usually provide disk mirroring, i/o interception, data-flow encryption etc.)
  • Network redirectors (handling of network traffic, low-level)

 

System processes

Following are main system processes: 

  • idle process
  • system process/thread(s)
  • session manager
  • logon process
  • local security authentication server (lsas)
  • service controller

The idle process is not running a real program image. It is also known as "process ID 2". 

The system process/thread(s) are threads provided by the system process, they have the same attributes as user-mode threads, however, are restricted to execution within the two gigabytes of kernel memory space. System threads are commonly used by such pieces of system software as the file server, cache manager, memory manager etc. to provide for the kinds of services these servers respectively implement. 

The session manager is the first user process that is initiated by the OS. Along with doing system initialization, the session manager is responsible for the communication between applications and debuggers. It is also the parent of the Logon process. 

The logon process is the one that is "always there", responsible for the usual screen answering the activation of the Secure Authentication Sequence (normally ctrl-alt-del keys). This sequence exists to provide untemperable logins to the system (network). The name and password received from the user are sent to the Local Security Authentication Server (LSAS) for verification, and if everything goes okay, a process called USERINIT.EXE is created. USERINIT creates the default user shell and then dies a quick death (no longer needed). The authentication itself is implemented within a .DLL called GINA (stands very imaginatively for Graphical Identification and Authentication).  Of course, if you have an idea how to implement a system better that this one, MSGINA.DLL is replaceable and it is up to you to make it or break it. 

Local Security Authentication Server (LSAS) relies on the Security Account Manager which provides user and account handling for the LSAS. LSAS is responsible for creating a user profile object, the one that will have a say later in "just what an object is supposed to do, and what not". 

Service controller is the process that controls NT services, or pieces of software UNIX people know as daemons. Writing a service is a tricky task and requires great attention with regards to security issues. I guess one could relate the service controller to UNIX inetd daemon. 

Next month I will explain the interrupt and exception mechanisms, LPC, DPC and APC (just a review) and will guide you through writing a simple (but model) NT device driver.  

Enjoy and do not over-read! 

Some useful links: 
Active Matrix Hideaway
Windows NT FAQ
Windows Hacking FAQ
Windows Security FAQ
Windows Systems internals
Microsoft NT Server page(s)

Most of the material in this article is my understanding of a book "Inside Windows NT" 2nd edition by David A. Solomon (Microsoft Press)

This article brought to you by
infinity_banner_small.jpg (4443 bytes)

Columns
  Development
  Security
  Network Security
 
Feature Articles
  The 3D Chipset Wars

Active Server Pages

Dynamic HTML

Help Students Across Canada Go Higher!

The Core of Linux: Hacking the Kernel

An Introduction to PHP

Java's Magic Beans

Mac OS X Server: Unix for the Mac

Mentoring to a Multitude

MPEG-4: A Bird's Eye View

ATAPI Music CD Programming Interface in Linux

Snow Crash

Unified Modeling Language

Rendering Bézier Forms via Forward Differencing

April 1999

Issue 2, Volume 1

This could be your company's banner advertisement

hw_publegal.gif (2694 bytes)