|< Windows Registry Tutorial 2 | Main | Windows Registry Tutorial 4 >| Site Index | Download | Disclaimer | Privacy |
MODULE P
WINDOWS OS
.:: REGISTRY: EXAMPLES AND EXPLOITS::.
PART 3
|
|
My Training Period: hours
Note: This is a continuation from previous Windows Registry Tutorial 2. Program examples compiled using Visual C++ .Net (Visual studio .Net 2003) except whenever mentioned. It is low-level programming and the .Net used is Unmanaged (/clr is not set: Project menu → your_project_name Properties… sub menu → Configuration Properties folder → General subfolder → Used Managed Extension setting set to No). This also applied to other program examples in other Modules of tenouk.com Tutorial that mentioned “compiled using Visual C++ .Net”. Other settings are default. Machine’s OS is standalone Win Xp SP2 except whenever mentioned. Beware the codes that span more than one line. Program examples have been tested for Non Destructive Test :o). All information recomposed for Win 2000 (NT5.0) above.
WARNING
Wrongly modified and run the program examples presented here might collapse your Windows machine or disturb its integrity. So for your Windows machine safety, make sure you fulfill the following conditions:
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 Registry Subkeys
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;
}
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

Figure 1: Enumerate Registry keys and values.
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.

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;
}
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>
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