Getting windows serial number (MachineGuid) in both x86 and x64 architectures - c++

I´m currently using the following C++ code to get the MachineGuid from the windows registry and use that information for my licensing algorithm:
std::wstring key = L"SOFTWARE\\Microsoft\\Cryptography";
std::wstring name = L"MachineGuid";
HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
throw std::runtime_error("Could not open registry key");
DWORD type;
DWORD cbData;
if (RegQueryValueEx(hKey, name.c_str(), NULL, &type, NULL, &cbData) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
throw std::runtime_error("Could not read registry value");
}
if (type != REG_SZ)
{
RegCloseKey(hKey);
throw "Incorrect registry value type";
}
std::wstring value(cbData/sizeof(wchar_t), L'\0');
if (RegQueryValueEx(hKey, name.c_str(), NULL, NULL, reinterpret_cast<LPBYTE>(&value[0]), &cbData) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
throw "Could not read registry value";
}
RegCloseKey(hKey);
This works pretty well on a x86 system (32 bit). Now I´ve migrated the whole code to x64 (64bit) Windows and the RegQueryValueEx call is returning error.
Among some other posts, this link explains very clearly why this does not work on 64bit machines, and offers an alternative for both 32bit and 64bit using the ManagementObject class from System.Management.dll. The problem is that this solution works on C#, not on C++. I can´t find out a C++ equivalent of the ManagementObject class.
So, what is the correct solution for the problem: Getting the window serial number (MachineGuid) on both x86 and x64 machines using C++.
Thanks for helping.

Add KEY_WOW64_64KEY bit to your RegOpenKeyEx argument. Like this:
RegOpenKeyEx( HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey )
The documentation says it’s ignored on 32-bit OSes, so you don’t even need to detect WOW64.
P.S. I don’t recommend WMI, it’s too slow. I currently have i5-4460 CPU, 16GB RAM, relatively fast SSD, and yet WMI takes 1-2 seconds to initialize and run even a simple query.

Related

C++ read a Registry entry in SOFTWARE\WOW6432 from a 64-bit app

I've got some 32-bit C++ code to read a Key/Value pair from the Registry as follows:
// Get a handle to the required key
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\MyKey", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
// Look up the value for the key
bOK = (RegQueryValueEx(hKey, szKey, NULL, NULL, (PBYTE)szValue, &dwMax) == ERROR_SUCCESS);
// Release the handle
RegCloseKey(hKey);
}
As it's a 32-bit app it reads from SOFTWARE\WOW6432Node\MyKey
This was working fine until I ported the app to 64-bit, so it now reads from SOFTWARE\MyKey.
My installer won't let me put entries into both the 32-bit and 64-bit parts of the Registry, so I need the 64-bit app to go on getting its data from WOW6432Node.
Does anyone know how to do this?
Many thanks
Tony Reynolds
As documented under 32-bit and 64-bit Application Data in the Registry:
The KEY_WOW64_64KEY and KEY_WOW64_32KEY flags enable explicit access to the 64-bit registry view and the 32-bit view, respectively. For more information, see Accessing an Alternate Registry View.
The latter link explains that
These flags can be specified in the samDesired parameter of the following registry functions:
RegCreateKeyEx
RegDeleteKeyEx
RegOpenKeyEx
The following code accomplishes what you are asking for:
// Get a handle to the required key
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\MyKey", 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS)
{
// ...
}

Reading the Windows registry key "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" using RegGetValue() returns error code 2

Reading the Windows registry key "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" using RegGetValue() returns error code 2.
I've been sitting for hours debugging this problem, but haven't found a solution.
Here is the code that I use to retrieve the registry value named "test":
long result = RegGetValue(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), TEXT("test"), RRF_RT_ANY, &dwType, (PVOID)&buff, &size);
Below is a picture that I've added the registry value "test" to the Run key (mentioned above).
The error code I get is 2 which represents an invalid file.
It should be mentioned that the local host is running Windows 10 Pro x64.
What could be the source of this confusion?
Modified code:
I still get the error code 2 after using the KEY_WOW64_64KEY flag.
RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"),
NULL,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS | KEY_WOW64_64KEY,
NULL,
&hKey,
&dwStatus)
long result = RegGetValue(hKey, NULL, TEXT("test"), RRF_RT_ANY, &dwType, (PVOID)&buff, &size);
Problem
You are most probably trying to access the 64-bit registry view from a 32-bit application.
By default, a 32-bit application running on WOW64 accesses the 32-bit
registry view and a 64-bit application accesses the 64-bit registry
view. The following flags enable 32-bit applications to access
redirected keys in the 64-bit registry view and 64-bit applications to
access redirected keys in the 32-bit registry view. These flags have
no effect on shared registry keys.
Solution
You can rebuild your application in x64 mode or you can specify which view of the registry you require.
HKEY key;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key);
long result = RegGetValue(key, nullptr, TEXT("test"), RRF_RT_ANY, &dwType, (PVOID)&buff, &size);
For more info: Accessing an Alternate Registry View

KEY_WOW64_32KEY not redirecting from x64 application

I have an x64 application running on a x64 OS where i'm trying to read from the x86 registry.
This is my code:
RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Idontexist", 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
I want to try to open HKCU\Software\Wow6432Node\Idontexist, but instead it's opening HKCU\Software\Idontexist.
I watched in process monitor and if I use KEY_WOW64_64KEY or KEY_WOW64_32KEY, both try to read HKCU\Software\Idontexist, instead of HKCU\Software\Wow6432Node\Idontexist.
EDIT: OS is Windows 7 if that makes any difference.
What keys are redirected and reflected on Windows 7 is shown in detail in this MSDN page. Too large to reproduce here, but you can clearly see that the HKCU\Software key, other than the Classes subkey, is shared, not redirected.
Wow6432Node implies WOW64 virtualization. A 64-bit process can open a 32-bit virtualized key directly:
RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Wow6432Node\\Idontexist", 0, KEY_READ, &hKey);
If you need the same code to run in both 32-bit and 64-bit and both access the Wow6432Node key, then use IsWow64Process() in the 32-bit code to detect WOW64 and then adust the code accordingly, eg:
#ifdef _WIN64
RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Wow6432Node\\Idontexist", 0, KEY_READ, &hKey);
#else
BOOL bIsWow64 = FALSE;
IsWow64Process(GetCurrentProcess(), &bIsWow64);
DWORD Wow64Flags = (bIsWow64) ? KEY_WOW64_32KEY : 0;
RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Idontexist", 0, KEY_READ | Wow64Flags, &hKey);
#endif
However, you really shouldn't be accessing Wow6432Node directly. KEY_WOW64_32KEY should be working correctly if the target key is properly separated into 32-bit and 64-bit views:
DWORD Wow64Flags;
#ifdef _WIN64
Wow64Flags = KEY_WOW64_32KEY;
#else
BOOL bIsWow64 = FALSE;
IsWow64Process(GetCurrentProcess(), &bIsWow64);
Wow64Flags = (bIsWow64) ? KEY_WOW64_32KEY : 0;
#endif
RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Idontexist", 0, KEY_READ | Wow64Flags, &hKey);
If that is not working, than that implies that Software\\Wow6432Node\\Idontexist should not have existed in the first place, and was probably incorrectly created by a 64-bit process that did not use KEY_WOW64_... flags correctly.

Writing a DWORD value to registry in C++

I am trying to write a DWORD value to the registry programmatically in C++.
I've done a bit of searching and I have found that this question has been asked before. I've tried to follow their solution but have come up with a really frustrating issue which, as far as I know, have not been addressed by their solution.
This is my code:
HKEY hKey;
LPCWSTR sKeyPath;
int iResult;
sKeyPath = L"Software\\ABI\\";
iResult = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyPath, NULL, KEY_ALL_ACCESS, &hKey);
DWORD value = 0x00000003;
iResult = RegSetValueEx(hKey, L"Test", NULL, REG_DWORD, (const BYTE*)value, sizeof(value));
RegCloseKey(hKey);
I've done some basic debugging and found that the value of iResult is 998 after I call RegSetValueEx. I am sure that this key is present in the windows registry because I created it manually with regedit.exe for testing purposes. The value of the DWORD "Test" is initially 0x00000009 and is unchanged after I run my program.
I am not sure where I am wrong.
Any help would be appreciated.
P.S. I've not managed to find any helpful site on the net for error 998. The only reference I found mentions that that's the worst error you can get when handling registry.
P.P.S. By the way, I'm running this program on Windows 8. I don't think that changes anything but I've had experiences with Windows 8 having some weird security issues before.
You need to pass the address of value:
iResult = RegSetValueEx(hKey,
L"Test",
NULL,
REG_DWORD,
(const BYTE*)&value, // Change made here.
sizeof(value));
The error code 998 means:
Invalid access to memory location.
When the address of value is not passed its actual value (3) is being used as a memory address, causing the failure.

Why is RegOpenKeyEx() returning error code 2 on Vista 64bit?

I was making the following call:
result = RegOpenKeyEx(key, s, 0, KEY_READ, &key);
(C++, Visual Studio 5, Vista 64bit).
It is failing with error code 2 ("File not found") even though "regedit" shows that the key exists. This code has always worked on 32bit XP. Why is it "file not found" when it clearly is there?
I discovered that I could solve my problem using the flag: KEY_WOW64_64KEY , as in:
result = RegOpenKeyEx(key, s, 0, KEY_READ|KEY_WOW64_64KEY, &key);
For a full explanation: 32-bit and 64-bit Application Data in the Registry
On a Windows 64-bit system the Registry is actually divided into two parts. One section is used by 64-bit processes, and one part by 32-bit processes.
For example, if a 32-bit application programatically writes to what it believes is HKLM\SOFTWARE\Company\Application, it's actually redirected by the WoW64-layer to HKLM\SOFTWARE\Wow6432Node\Company\Application.
So when you run your 32-bit application and call RegOpenKeyEx it's actually working against the Wow6432Node\ folder, and not the regular \SOFTWARE node.
You have to compile with "Use Multi-Byte Character Set" or cast string in code to (LPWSTR)
I had a similar problem.
I was using:
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
(LPWSTR)"SOFTWARE\\0test",
0,
WRITE_DAC ,
&hKey);
That didn't work. I tried it like this and it worked:
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\0test"),
0,
WRITE_DAC ,
&hKey);
yes,win7 64B,add further flag KEY_WOW64_64KEY ,it will work.
if not work, refer to http://msdn.microsoft.com/en-us/library/ms724897(v=VS.85).aspx