Determining the Version of the Operating System

 < Day Day Up > 

Since kernel structures change between major versions of the operating system and, in rare cases, between service packs, a rootkit developer must be aware of the system version on which the rootkit will run. The authors of this book believe it is poor form to use hard-coded addresses, or even offsets. Instead, your code should adapt to its surroundings. The goal: Compile once, or at most twice, but run everywhere!

If your rootkit has a user-mode portion, you can determine the operating system version in a userland process using the Win32 APIs. Alternatively, you can determine the system version in the kernel. Obviously, the former is much easier than the latter.

User-Mode Self-Determination

With the Win32 API, it is very easy to determine what version of the operating system your rootkit is installed upon. The structure used to retrieve this information is called OSVERSIONINFO or OSVERSIONINFOEX. It contains information about the major and minor versions of the operating system. The EX version also specifies the major and minor versions of service-pack level.

OSVERSIONINFO vs. OSVERSIONINFOEX

When planning to use either OSVERSIONINFO or OSVERSIONINFOEX to identify the operating-system version, keep in mind that certain versions of Windows are not able to process the EX version of the OSVERSIONINFO structure. The size member of the OSVERSIONINFO structure indicates which version of the structure you are using. You can make the same call to the GetVersionEx function in either case. In the case of OSVERSIONINFO, you must parse the szCSDVersion element of the structure to determine the service-pack level.


The definition of the OSVERSIONINFOEX structure follows:

 typedef struct _OSVERSIONINFOEX {  DWORD dwOSVersionInfoSize;  DWORD dwMajorVersion;  DWORD dwMinorVersion;  DWORD dwBuildNumber;  DWORD dwPlatformId;  TCHAR szCSDVersion[128];  WORD wServicePackMajor;  WORD wServicePackMinor;  WORD wSuiteMask;  BYTE wProductType;  BYTE wReserved; } OSVERSIONINFOEX, *POSVERSIONINFOEX, *LPOSVERSIONINFOEX; 

Declare a structure of this type in your code and pass a pointer to this structure when you call the GetVersionEx function. Here is the function prototype for GetVersionEx:

 BOOL GetVersionEx( LPOSVERSIONINFO lpVersionInfo ); 

After you have made this call, you should have identified the version of the operating system executing your code.

The following code uses the OSVERSIONINFOEX in the call to GetVersionEx to retrieve the major version of the operating system and its service pack level:

 void DetermineOSVersion() {      OSVERSIONINFOEX osvi;      // Setup the size of the structure      osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);      if (GetVersionEx((OSVERSIONINFO *) &osvi))      {         switch (osvi.dwPlatformId)         {            // Tests for Windows NT product family.            case VER_PLATFORM_WIN32_NT:               // Test for the product.               if ( osvi.dwMajorVersion == 4 && \                    osvi.dwMinorVersion == 0)               {                  fprintf(stderr, "Microsoft Windows NT 4.0 ");                  //...               }               else if ( osvi.dwMajorVersion == 5 && \                         osvi.dwMinorVersion == 0 && \                         osvi.wServicePackMajor == 3)               {                  fprintf(stderr, "Microsoft Windows 2000 SP 3 ");                  //...               }               break;         }      } } 

Once you know the version of the operating system your rootkit is running on, you can adjust the offsets you will use with DKOM. The importance of this will become evident in the next section.

Kernel-Mode Self-Determination

The user-mode APIs discussed in the preceding section are not the only way to find out the operating-system version. The kernel also contains an API that provides access to version information. On older Windows systems, you must call PsGetVersion and parse the UNICODE string to obtain service-pack information. Its function prototype follows:

 BOOLEAN PsGetVersion(           PULONG  MajorVersion  OPTIONAL,           PULONG  MinorVersion  OPTIONAL,           PULONG  BuildNumber  OPTIONAL,           PUNICODE_STRING  CSDVersion  OPTIONAL      ); 

Newer versions of the operating system, such as Windows XP and Windows 2003, support the API function RtlGetVersion. It takes as a parameter a pointer to an OSVERSIONINFOW or OSVERSIONINFOEXW, similar to the user-mode Win32 call discussed in the preceding section. The function prototype of RtlGetVersion is almost exactly the same as the Win32 version. It is defined as:

 NTSTATUS RtlGetVersion( IN OUT PRTL_OSVERSIONINFOW lpVersionInformation ); 

Querying the Operating System Version in the Registry

The Windows Registry holds a great deal of valuable information. In fact, you can use it to find the version of the operating system on which your rootkit is installed. You can do this from user mode, or in the kernel driver itself. Please note that if you decide to query the Registry in your device driver, part of the Registry may not be available if your driver loads and attempts to query the Registry early in the boot process.

Here are the important keys to query:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CSDVersion contains the string for the service pack

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentBuildNumber contains the build number for the operating system

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentVersion contains both the major and minor version of the kernel, separated by a decimal

From user mode, you can query these keys once you have the appropriate handle by calling RegQueryValue or RegQueryValueEx. The following code illustrates how to query these Registry keys from a device driver:

 // Query the Registry to get the operating system version. RTL_QUERY_REGISTRY_TABLE paramTable[3]; UNICODE_STRING ac_csdVersion; UNICODE_STRING ac_currentVersion; // Initialize the variables. RtlZeroMemory(paramTable, sizeof(paramTable)); RtlZeroMemory(&ac_currentVersion, sizeof(ac_currentVersion)); RtlZeroMemory(&ac_csdVersion, sizeof(ac_csdVersion)); paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; paramTable[0].Name = L"CurrentVersion"; paramTable[0].EntryContext = &ac_currentVersion; paramTable[0].DefaultType = REG_SZ; paramTable[0].DefaultData = &ac_currentVersion; paramTable[0].DefaultLength = sizeof(ac_currentVersion); paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; paramTable[1].Name = L"CSDVersion"; paramTable[1].EntryContext = &ac_csdVersion; paramTable[1].DefaultType = REG_SZ; paramTable[1].DefaultData = &ac_csdVersion; paramTable[1].DefaultLength = sizeof(ac_csdVersion); // Query the Registry. RtlQueryRegistryValues( RTL_REGISTRY_WINDOWS_NT,                         NULL,                         paramTable,                         NULL,                         NULL  );       // Do something with the data here if the query is successful.       // This might include initializing some global variables to       // store the service pack number, etc. // Free the UNICODE_STRINGs created by the query. RtlFreeUnicodeString(&ac_currentVersion); RtlFreeUnicodeString(&ac_csdVersion); 

As you can see, you can determine the version of the operating system in many different ways. The method you choose will depend on what type of rootkit you implement.

In the next section, we will show you how to communicate information such as version numbers from a userland process to a driver.

     < Day Day Up > 


    Rootkits(c) Subverting the Windows Kernel
    Rootkits: Subverting the Windows Kernel
    ISBN: 0321294319
    EAN: 2147483647
    Year: 2006
    Pages: 111

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net