|< Windows Registry Tutorial 2 | Main | Windows Registry Tutorial 4 >| Site Index | Download | Disclaimer | Privacy |


 

 

 

 

MODULE P

WINDOWS OS

.:: REGISTRY:  EXAMPLES AND EXPLOITS::.

PART 3

 

 

 

 

What do we have in this Module?

  1. Enumerating Registry Subkeys Program Example

  2. Determining the Registry Size Program Example

  3. Getting the System Version Program Example

 

 

 

 

 

 

 

 

 

My Training Period: xx hours. Before you begin, read some instruction here. This is a continuation from previous Windows Registry Tutorial 2.

 

The expected abilities:

  • Able to understand and use functions to manipulate Windows Registry.

  • Able to gather and understand the required information in order to use those functions.

  • Able to understand the Registry and automatic programs startup.

  • Able to understand and aware the misuse of the automatic programs startup.

  • Able to understand the Registry execution order during the Windows bootup.

Enumerating The Registry Subkeys Program Example

 

The following example demonstrates the use of the RegQueryInfoKey(), RegEnumKeyEx(), and RegEnumValue() functions.  The hKey parameter passed to each function is a handle to an open key.  This key must be opened before the function call and closed afterward.

 

// QueryKey() - Enumerates the subkeys of key and its associated values.

//     hKey   - Key whose subkeys and values are to be enumerated.

 

// #define _WIN32_WINNT 0x0502   // Windows Server 2003 family

// For Win Xp, change accordingly...

#define _WIN32_WINNT 0x0501

// #define _WIN32_WINNT 0x0500   // Windows 2000

// #define _WIN32_WINNT 0x0400   // Windows NT 4.0

// #define _WIN32_WINDOWS 0x0500 // Windows ME

// #define _WIN32_WINDOWS 0x0410 // Windows 98

// #define _WIN32_WINDOWS 0x0400 // Windows 95

 

#include <windows.h>

#include <stdio.h>

 

#define MAX_KEY_LENGTH 255

#define MAX_VALUE_NAME 16383

 

void QueryKey(HKEY hKey)

{

    CHAR         achKey[MAX_KEY_LENGTH];   // buffer for subkey name

    DWORD    cbName;                                        // size of name string

    CHAR        achClass[MAX_PATH] = "";        // buffer for class name

    DWORD    cchClassName = MAX_PATH;  // size of class string

    DWORD    cSubKeys=0;                               // number of subkeys

    DWORD    cbMaxSubKey;                            // longest subkey size

    DWORD    cchMaxClass;                              // longest class string

    DWORD    cValues;                                       // number of values for key

    DWORD    cchMaxValue;                             // longest value name

    DWORD    cbMaxValueData;                      // longest value data

    DWORD    cbSecurityDescriptor;               // size of security descriptor

    FILETIME ftLastWriteTime;                         // last write time

    DWORD i, retCode;

    CHAR  achValue[MAX_VALUE_NAME];

    DWORD cchValue = MAX_VALUE_NAME;

    // Get the class name and the value count.

    retCode = RegQueryInfoKey(

        hKey,                                 // key handle

        achClass,                         // buffer for class name

        &cchClassName,           // size of class string

        NULL,                              // reserved

        &cSubKeys,                   // number of subkeys

        &cbMaxSubKey,            // longest subkey size

        &cchMaxClass,            // longest class string

        &cValues,                     // number of values for this key

        &cchMaxValue,                 // longest value name

        &cbMaxValueData,         // longest value data

        &cbSecurityDescriptor,   // security descriptor

        &ftLastWriteTime);          // last write time

   // Enumerate the subkeys, until RegEnumKeyEx() fails.

   if(cSubKeys)

    {

       printf("Subkey Names:\n");

       for(i=0; i<cSubKeys; i++)

        {

            cbName = MAX_KEY_LENGTH;

            retCode = RegEnumKeyEx(

                    hKey,                          // Handle to an open/predefined key

                    i,                                 // Index of the subkey to retrieve.

                     achKey,                    // buffer that receives the name of the subkey

                     &cbName,               // size of the buffer specified by the achKey

                     NULL,                      // Reserved; must be NULL

                     NULL,                      // buffer that receives the class string of the enumerated subkey

                     NULL,                      // size of the buffer specified by the previous parameter

                     &ftLastWriteTime  // variable that receives the time at which  the enumerated subkey was last written

            );

            if(retCode == ERROR_SUCCESS)

            { printf("(%d) %s\n", i+1, achKey); }

       }

       printf("Number of subkeys: %d\n\n", cSubKeys);

    }

    else

       printf("RegEnumKeyEx(), there is no subkey.\n");

   // Enumerate the key values if any.

   if(cValues)

    {

        for(i=0, retCode=ERROR_SUCCESS; i<cValues; i++)

        {

            cchValue = MAX_VALUE_NAME;

            achValue[0] = '\0';

           retCode = RegEnumValue(

                hKey,              // Handle to an open key

                i,                     // Index of value

                achValue,      // Value name

                &cchValue,   // Buffer for value name

                NULL,           // Reserved

                NULL,           // Value type

                NULL,          // Value data

                NULL);         // Buffer for value data

            if(retCode == ERROR_SUCCESS)

            { printf("(%d) Value Name: %s.\n", i+1, achValue); }

       }

       printf("Number of values: %d\n", cValues);

    }

    else

       printf("No value under this key/subkey...\n");   

}

 

int main(int argc, char *argv[ ])

{

       // Change the key and subkey accordingly...

       // Predefined registry keys:

       // HKEY_CLASSES_ROOT

       // HKEY_CURRENT_CONFIG

       // HKEY_CURRENT_USER

       // HKEY_LOCAL_MACHINE

       // HKEY_PERFORMANCE_DATA

       // HKEY_USERS

       //*************** open key (and subkey) ******************

       HKEY theKey = HKEY_LOCAL_MACHINE;  // Key, change accordingly...

       HKEY hKey;                                                       // Key and subkey

       LONG lRet = RegOpenKeyEx(

              theKey,                                                     // Key

              "SYSTEM\\ControlSet001\\Control",    // Subkey, change accordingly

              0,                                                              // Reserved

              KEY_ALL_ACCESS,                            // desired access rights to the key

              &hKey);                                                    // variable that receives a handle to the opened key

       if(lRet == ERROR_SUCCESS)

            printf("RegOpenKeyEx() is OK.\n");

       else

            printf("RegOpenKeyEx() is not OK.\n");

       QueryKey(hKey);

       RegCloseKey(hKey);

       return 0;

}

 

A sample output:

RegOpenKeyEx() is OK.

Subkey Names:

(1) AGP

(2) Arbiters

(3) BackupRestore

(4) Biosinfo

(5) BootVerificationProgram

(6) Class

(7) CoDeviceInstallers

...

[trimmed]

...

(29) NetworkProvider

(30) Nls

(31) NTMS

(32) PnP

...

[trimmed]

...

(53) Watchdog

(54) Windows

(55) WMI

(56) WOW

(57) hivelist

(58) ServiceCurrent

Number of subkeys: 58

 

(1) Value Name: CurrentUser.

(2) Value Name: WaitToKillServiceTimeout.

(3) Value Name: SystemStartOptions.

(4) Value Name: SystemBootDevice.

Number of values: 4

Press any key to continue

 

Enumerating registry keys and values

 

Figure 1: Enumerate Registry keys and values.

 

Determining the Registry Size Program Example

 

On Windows 2000 and earlier, it is common for an installation utility to check the current and maximum size of the registry to determine whether there is enough available space for the new data it will be adding. This sample demonstrates how to do this programmatically using the "% Registry Quota In Use" performance counter within the System object.  The following sample uses Performance Data Helper (PDH) to obtain the counter value; it must be linked with pdh.lib.  PDH is a high-level set of APIs used to obtain performance data.  Note that it is not necessary to implement this registry size-check on Windows XP or Windows Me/98/95, because they do not have a registry quota limit. Don’t forget to include the pdh.lib into your project as shown below. 

 

Adding pdh.lib (dependency/library) to Visual C++ .Net project

 

Figure 2: Adding pdh.lib library to the Visual C++ .Net project.

 

// ************ regsize.cpp ******************

// Determines the current and maximum registry size

// For Win XP, run on Win Xp...Change accordingly

// but it is useless here, Win Xp don’t have quota limit :o)

// Just for fun...

 

// #define _WIN32_WINNT 0x0502   // Windows Server 2003 family

// For Win Xp, change accordingly...

#define _WIN32_WINNT 0x0501

// #define _WIN32_WINNT 0x0500   // Windows 2000

// #define _WIN32_WINNT 0x0400   // Windows NT 4.0

// #define _WIN32_WINDOWS 0x0500 // Windows ME

// #define _WIN32_WINDOWS 0x0410 // Windows 98

// #define _WIN32_WINDOWS 0x0400 // Windows 95

 

// This is wide character/UNICODE based program

#ifndef UNICODE

#define UNICODE

#endif

 

#include <windows.h>

#include <stdio.h>

#include <pdh.h>

// And don't forget to include the pdh.lib into

// this project...

 

// Function prototype

PDH_STATUS GetRegistrySize(LPTSTR szMachineName, LPDWORD lpdwCurrentSize, LPDWORD lpdwMaximumSize);

 

//  Entry point for the program. This function demonstrates how to

//  use the GetRegistrySize() function implemented below.

//  It will use the first argument, if present, as the name of the

//  computer whose registry you wish to determine. If unspecified,

//  it will use the local computer.

int wmain(int argc, TCHAR *argv[])

{

    LPTSTR      szMachineName  = NULL;

    PDH_STATUS  pdhStatus      = 0;

    DWORD       dwCurrent      = 0;

    DWORD       dwMaximum      = 0;

 

    // Allow a computer name to be specified on the command line.

    if(argc > 1)

        szMachineName = argv[1];

       wprintf(TEXT("Usage: %s <computer_name> else default to local computer.\n\n"), argv[0]);

    // Get the registry size.

    pdhStatus = GetRegistrySize(szMachineName, &dwCurrent, &dwMaximum);

    // Print the results.

    if(pdhStatus == ERROR_SUCCESS)

    {

          printf("GetRegistrySize() is OK.\n");

          wprintf(TEXT("\nCurrent registry size: %ld bytes\n"), dwCurrent);

          wprintf(TEXT("Maximum registry size: %ld bytes\n"), dwMaximum);

    }

    else

    {

        // If the operation failed, print the PDH error message.

        LPTSTR szMessage = NULL;

        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,

            GetModuleHandle(TEXT("PDH.DLL")), pdhStatus, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szMessage, 0, NULL);

 

        wprintf(TEXT("GetRegistrySize() failed:  %s"), szMessage);

        LocalFree(szMessage);

    }

 

    return 0;

}

 

// Retrieves the current and maximum registry size. It gets this

// information from the raw counter values for the "% Registry Quota

// In Use" performance counter within the System object.

// PARAMETERS:

//      szMachineName - Null-terminated string that specifies the

//          name of the computer whose registry you wish to query.

//          If this parameter is NULL, the local computer is used.

//      lpdwCurrentSize - Receives the current registry size.

//      lpdwMaximumSize - Receives the maximum registry size.

// RETURN VALUE:

//      ERROR_SUCCESS if successful. Otherwise, the function

//      returns a PDH error code. These error codes can be

//      found in PDHMSG.H. A textual error message can be

//      retrieved from PDH.DLL using the FormatMessage function.

//******************************************************************

 

PDH_STATUS GetRegistrySize(LPTSTR szMachineName, LPDWORD lpdwCurrentSize, LPDWORD lpdwMaximumSize)

{

    PDH_STATUS  pdhResult   = 0;

    TCHAR       szCounterPath[1024];

    DWORD       dwPathSize  = 1024;

    PDH_COUNTER_PATH_ELEMENTS pe;

    PDH_RAW_COUNTER pdhRawValues;

    HQUERY      hQuery      = NULL;

    HCOUNTER    hCounter    = NULL;

    DWORD       dwType      = 0;

 

    // Open PDH query

    pdhResult = PdhOpenQuery(NULL, 0, &hQuery);

    if(pdhResult != ERROR_SUCCESS)

        // Just return the error...

       return pdhResult;

    else

       printf("PdhOpenQuery() is OK.\n");

 

        // Create counter path

        pe.szMachineName     = szMachineName;

        pe.szObjectName      = TEXT("System");

        pe.szInstanceName    = NULL;

        pe.szParentInstance  = NULL;

        pe.dwInstanceIndex   = 1;

        pe.szCounterName     = TEXT("% Registry Quota In Use");

 

        pdhResult = PdhMakeCounterPath(&pe, szCounterPath, &dwPathSize, 0);

        if(pdhResult != ERROR_SUCCESS)

        {

           printf("PdhMakeCounterPath() is not OK.\n");

           exit(1);

         }

         else

            printf("PdhMakeCounterPath() is OK.\n");

 

        // Add the counter to the query

        pdhResult = PdhAddCounter(hQuery, szCounterPath, 0, &hCounter);

        if(pdhResult != ERROR_SUCCESS)

          // Here we just exit, better to retrieve and return the error code...

          // same for the following...

          exit(1);

         else

          printf("PdhAddCounter() is OK.\n");

        // Run the query to collect the performance data

        pdhResult = PdhCollectQueryData(hQuery);

        if(pdhResult != ERROR_SUCCESS)

           exit(1);

        else

           printf("PdhCollectQueryData() is OK.\n");

        // Retrieve the raw counter data:

        //    The dividend (FirstValue) is the current registry size

        //    The divisor (SecondValue) is the maximum registry size

        ZeroMemory(&pdhRawValues, sizeof(pdhRawValues));

        pdhResult = PdhGetRawCounterValue(hCounter, &dwType, &pdhRawValues);

        if(pdhResult != ERROR_SUCCESS)

            exit (1);

        else

            printf("PdhGetRawCounterValue() is OK\n");

        // Store the sizes in variables.

        if(lpdwCurrentSize)

            *lpdwCurrentSize = (DWORD) pdhRawValues.FirstValue;

        if(lpdwMaximumSize)

            *lpdwMaximumSize = (DWORD) pdhRawValues.SecondValue;

        // Close the query

        PdhCloseQuery(hQuery);

 

    return 0;

}

 

A sample output:

F:\myproject\win32prog\Debug>regsize

Usage: regsize <computer_name> else default to local computer.

 

PdhOpenQuery() is OK.

PdhMakeCounterPath() is OK.

PdhAddCounter() is OK.

PdhCollectQueryData() is OK.

PdhGetRawCounterValue() is OK

GetRegistrySize() is OK.

 

Current registry size: 3886596 bytes

Maximum registry size: 58720256 bytes

 

F:\myproject\win32prog\Debug>regsize mypersonal

Usage: regsize <computer_name> else default to local computer.

 

PdhOpenQuery() is OK.

PdhMakeCounterPath() is OK.

PdhAddCounter() is OK.

PdhCollectQueryData() is OK.

PdhGetRawCounterValue() is OK

GetRegistrySize() is OK.

 

Current registry size: 3886596 bytes

Maximum registry size: 58720256 bytes

 

F:\myproject\win32prog\Debug>

Getting the System Version Program Example

 

The following example uses the GetVersionEx() function to display the version of the currently running operating system.  Relying on version information is not the best way to test for a feature.  Instead, refer to the documentation for the feature of interest.  If you must require a particular operating system, be sure to use it as a minimum supported version, rather than design the test for the one operating system.  This way, your detection code will continue to work on future versions of Windows.

 

// #define _WIN32_WINNT 0x0502   // Windows Server 2003 family

// For Win Xp, change accordingly...

#define _WIN32_WINNT 0x0501

// #define _WIN32_WINNT 0x0500   // Windows 2000

// #define _WIN32_WINNT 0x0400   // Windows NT 4.0

// #define _WIN32_WINDOWS 0x0500 // Windows ME

// #define _WIN32_WINDOWS 0x0410 // Windows 98

// #define _WIN32_WINDOWS 0x0400 // Windows 95

#include <windows.h>

#include <stdio.h>

 

#define BUFSIZE 80

 

int main(int argc, char *argv[])

{

   OSVERSIONINFOEX osver;

   BOOL bOsVersionInfoEx;

   // Try calling GetVersionEx() using the OSVERSIONINFOEX structure.

   // If that fails, try using the OSVERSIONINFO structure.

   ZeroMemory(&osver, sizeof(OSVERSIONINFOEX));

   osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

 

   if(!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osver)))

   {

      osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

      if(!GetVersionEx((OSVERSIONINFO *) &osver))

        return FALSE;

      else

       printf("Buffer for the structure size is OK.\n");

   }

   else

       printf("GetVersionEx() is OK.\n");

   switch (osver.dwPlatformId)

   {

      //Test for the Windows NT product family.

      case VER_PLATFORM_WIN32_NT:

         // Test for the specific product family.

         if(osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2)

            printf("Microsoft Windows Server 2003 family, ");

         if(osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1)

            printf("Microsoft Windows XP ");

         if(osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0)

            printf("Microsoft Windows 2000 ");

         if(osver.dwMajorVersion <= 4)

            printf("Microsoft Windows NT ");

         // Test for specific product on Windows NT 4.0 SP6 and later.

         if(bOsVersionInfoEx)

         {

            // Test for the workstation type.

            if(osver.wProductType == VER_NT_WORKSTATION)

            {

               if(osver.dwMajorVersion == 4)

                  printf("Workstation 4.0 ");

               else if(osver.wSuiteMask & VER_SUITE_PERSONAL)

                  printf("Home Edition ");

               else

                  printf("Professional ");

            }

            // Test for the server type.

            else if(osver.wProductType == VER_NT_SERVER || osver.wProductType == VER_NT_DOMAIN_CONTROLLER)

            {

               if((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 2))

               {

                  if(osver.wSuiteMask & VER_SUITE_DATACENTER)

                     printf("Datacenter Edition ");

                  else if(osver.wSuiteMask & VER_SUITE_ENTERPRISE)

                     printf("Enterprise Edition ");

                  else if(osver.wSuiteMask == VER_SUITE_BLADE)

                     printf("Web Edition ");

                  else

                     printf("Standard Edition ");

               }

               else if((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 0))

               {

                  if(osver.wSuiteMask & VER_SUITE_DATACENTER)

                     printf("Datacenter Server ");

                  else if(osver.wSuiteMask & VER_SUITE_ENTERPRISE)

                     printf("Advanced Server ");

                  else

                     printf("Server ");

               }

               // Windows NT 4.0

               else

               {

                  if(osver.wSuiteMask & VER_SUITE_ENTERPRISE)

                     printf("Server 4.0, Enterprise Edition ");

                  else

                     printf("Server 4.0 ");

               }

            }

         }

         // Test for specific product on Windows NT 4.0 SP5 and earlier

         else

         {

            HKEY hKey;

            char szProductType[BUFSIZE];

            DWORD dwBufLen=BUFSIZE;

            LONG lRet;

            lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);

            if(lRet != ERROR_SUCCESS)

               return FALSE;

            else

              printf("RegOpenKeyEx() is OK.\n");

            lRet = RegQueryValueEx(hKey, "ProductType", NULL, NULL, (LPBYTE)szProductType, &dwBufLen);

            if((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE))

               return FALSE;

            else

              printf("RegQueryValueEx() is OK.\n");

            RegCloseKey(hKey);

            if(lstrcmpi("WINNT", szProductType) == 0)

               printf("Workstation ");

            if(lstrcmpi("LANMANNT", szProductType) == 0)

               printf("Server ");

            if(lstrcmpi("SERVERNT", szProductType) == 0)

               printf("Advanced Server ");

            printf("%d.%d ", osver.dwMajorVersion, osver.dwMinorVersion);

         }

         // Display service pack (if any) and build number.

         if(osver.dwMajorVersion == 4 && lstrcmpi(osver.szCSDVersion, "Service Pack 6") == 0)

         {

            HKEY hKey;

            LONG lRet;

            // Test for SP6 versus SP6a.

            lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows

               NT\\CurrentVersion\\Hotfix\\Q246009", 0, KEY_QUERY_VALUE, &hKey);

            if(lRet == ERROR_SUCCESS)

            {

              printf("RegOpenKeyEx() is OK.\n");

              printf("Service Pack 6a (Build %d)\n", osver.dwBuildNumber & 0xFFFF);

            }

            // Windows NT 4.0 prior to SP6a

            else

            {

               printf("%s (Build %d)\n", osver.szCSDVersion, osver.dwBuildNumber & 0xFFFF);

            }

             RegCloseKey(hKey);

         }

        // Windows NT 3.51 and earlier or Windows 2000 and later

         else

         {

            printf("%s (Build %d)\n", osver.szCSDVersion, osver.dwBuildNumber & 0xFFFF);

         }

         break;

      // Test for the Windows 95 product family.

      case VER_PLATFORM_WIN32_WINDOWS:

         if(osver.dwMajorVersion == 4 && osver.dwMinorVersion == 0)

         {

             printf("Microsoft Windows 95 ");

             if(osver.szCSDVersion[1] == 'C' || osver.szCSDVersion[1] == 'B')

                printf("OSR2 ");

         }

         if(osver.dwMajorVersion == 4 && osver.dwMinorVersion == 10)

         {

             printf("Microsoft Windows 98 ");

             if(osver.szCSDVersion[1] == 'A')

                printf("SE ");

         }

         if((osver.dwMajorVersion == 4) && (osver.dwMinorVersion == 90))

         {

             printf("Microsoft Windows Millennium Edition\n");

         }

         break;

      case VER_PLATFORM_WIN32s:

         printf("Microsoft Win32s\n");

         break;

   }

   return TRUE;

}

 

A sample output:

GetVersionEx() is OK.

Microsoft Windows XP Professional Service Pack 2 (Build 2600)

Press any key to continue

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Windows data type information is in Windows data types used in Win32 programming.
  2. Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussed Windows programming notations.
  3. Check the best selling C, C++ and Windows books at Amazon.com.
  4. Microsoft C references, online MSDN.

  5. Microsoft Visual C++, online MSDN.

  6. ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.

  7. Linux Access Control Lists (ACL) info can be found atAccess Control Lists.

  8. For Multi-bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
  9. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

 

 

 

 

 

 

|< Windows Registry Tutorial 2 | Main | Windows Registry Tutorial 4 >| Site Index | Download | Disclaimer | Privacy |