RegCreateKeyEX returns ERROR_INVALID_FUNCTION - c++

I am writing a program that needs to create/delete a registry key. I am having a problem that the code to create the key returns ERROR_INVALID_FUNCTION.
If you look in the registry the key has been created so I'm not sure what the impact of this error is.
The value of key is "SOFTWARE\\Wow6432Node\\COMPANY\\APPLICATION"
The code is:
int RegistryViewer::CreateRegistryLocation(const char* key)
{
HKEY hkey = 0;
int retVal = RegistryViewer::OpenRegistryLocation(key);
if(retVal != ERROR_SUCCESS)
{
retVal = RegCreateKeyEx(HKEY_LOCAL_MACHINE, CString(key), 0, NULL,REG_OPTION_NON_VOLATILE, KEY_WOW64_32KEY | KEY_WRITE, NULL, &hkey, NULL);
RegCloseKey(hkey);
}
return retVal;
}
Is the problem that although the key is created, it's unable to set the permissions correctly?
Thanks.

Going to answer my own question in case it's helpful to others in future. I think I had two problems that were limiting access to the registry key, firstly I was opening it twice (once to see it existed and then when it was created), secondly I was assigning it KEY_WRITE permissions. Since RegCreateKeyEx opens a key if it already exists the first check was pointless and may have been holding the resource. I'm not sure the second thing was a problem but since it's changed in the code I thought I'd mention it.
Working code looks like this:
//Create a registry location
int RegistryViewer::CreateRegistryLocation(const char* key)
{
HKEY hkey = 0;
int retVal = RegCreateKeyEx(HKEY_LOCAL_MACHINE, CString(key), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkey, NULL);
if(retVal == ERROR_SUCCESS)
RegCloseKey(hkey);
return retVal;
}
The comment by eryksun was useful for another issue though as I was manually checking which part of the registry to use and he enabled me to remove that check.

Related

How to recover the effective rights of a registry key? c++

I would like to retrieve the effective rights of a given registry key as a parameter. I test with an existing registry key under Windows. To do that I use the methods CreateFile, GetSecurityInfo and GetEffectiveRightsFromAclA.
I wanted to know if this is the correct method, because I have an error for the CreateFile method that returns INVALID_HANDLE_VALUE. Moreover for the method GetEffectiveRightsFromAclA, I do not understand which parameter I must put in TRUSTEE_A?
LPCWSTR lpwRegistryKey = L"HKEY_CLASSES_ROOT\\.acc\\OpenWithProgids\\WMP11.AssocFile.ADTS";
HANDLE handleKey;
handleKey = CreateFile(lpwRegistryKey, GENERIC_READ, FILE_SHARED_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if(handleKey == INVALID_HANDLE_VALUE)
{
//qDebug()<<"error";
}
//Here is an user SID
PSID pUserSid;
QString sSid("S-4-5-12");
BOOL resultSidConvert = ConvertStringSidToSidA(sSid.toStdString().c_str(), &pUserSid);
//Here success
if(resultSidConvert != 0)
{
PACL pDacl;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD dwResultSecurity = GetSecurityInfo(handleKey, SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, nullptr, &pUserSid, &pDacl, nullptr, &pSecurityDescritptor);
if(dwResultSecurity == ERROR_SUCCESS)
{
ACCESS_MASK pAccessMask;
TRUSTEE_A pTrustee; //How should I initialize pTrustee?
DWORD dwEffectiveRights = (GetEffectiveRightsFromAclA(pDacl, &pTrustee, &pAccessMask);
if(dwEffectiveRights == ERROR_SUCCESS)
{
if((pAccessMask & DELETE) == DELETE)
{
qDebug()<<"Delete";
}
if((pAccessMask & GENERIC_READ) == GENERIC_READ)
{
qDebug()<<"READ";
}
//etc ..........
}
}
}
A registry key is not a file!
Don't use CreateFile. Use RegOpenKeyEx instead.
First, you must run the application as admin.
Then, you can open the key successfully. After that, take a look at RegGetKeySecurity function.

How to write a 32 Bit D-Word to Windows registry in C++

I am trying to disable the Windows Defender using a C++ Win32API application.
To do that I need to write a D Word into the registry (DisableAntiSpyware = 1).
I always do that manually after installing a new Windows.
So here is my code, but its not working.
Maybe someone could tell me why or what is wrong with it. Thank you!
OK I've changed the code a bit, still not working...
case 1:
//::MessageBeep(MB_ICONERROR);
::MessageBox(hWnd, L"Button was Pressed",L"Button was clicked?",MB_OK);
LONG
SetRegValue
(
const wchar_t* path
, const wchar_t *name
, const BYTE *value
);
{
LONG status;
HKEY hKey;
DWORD value = 0x00000001;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\Policies\\Microsoft\\Windows Defender", 0, KEY_ALL_ACCESS, &hKey);
if ((status == ERROR_SUCCESS) && (hKey != NULL))
{
status = RegSetValueEx(hKey, L"test", 0, REG_DWORD, (const BYTE*)&value,sizeof(value));
RegCloseKey(hKey);
}
return status;
::MessageBeep(MB_ICONERROR);
}
}
}
break;
When opening a Registry key, you should request only the rights you actually need. So replace KEY_ALL_ACCESS with KEY_SET_VALUE instead, since all you are doing is writing a value. But even then, you might still need to run your app with elevated permissions in order to write to HKEY_LOCAL_MAHCINE, unless you give your user account write access to the Windows Defender key beforehand.
Also, if your code is compiled as 32bit and runs on a 64bit system, and it needs to write to the 64bit Registry, then you have to include the KEY_WOW64_64KEY flag otherwise you may be subject to Registry Reflection/Registry Redirection.
Try something more like this instead:
case 1:
{
::MessageBox(hWnd, L"Button was Pressed", L"Button was clicked?", MB_OK);
DWORD value = 1;
DWORD flags = KEY_SET_VALUE;
#if !defined(_WIN64)
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
flags |= KEY_WOW64_64KEY;
#endif
HKEY hKey;
LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\Policies\\Microsoft\\Windows Defender", 0, flags, &hKey);
if ((status == ERROR_SUCCESS) && (hKey != NULL))
{
status = RegSetValueEx(hKey, L"DisableAntiSpyware", 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
RegCloseKey(hKey);
}
::MessageBeep(MB_ICONERROR);
}
break;
You can't write to any key under HKEY_LOCAL_MACHINE unless the program is running with elevated privileges, i.e. administrator mode. The call to RegOpenKeyEx or RegSetValueEx will fail.

Weird behavior when getting registry value via RegQueryValueEx and RegGetValue [duplicate]

This question already has answers here:
I added a registry key, but I cannot find it programmatically
(3 answers)
What is 32 & 64 bit c++ code?
(1 answer)
Closed 6 years ago.
I am having some issues in c++ with the aforementioned functions. Both are behaving in the exact same way. Here is the process I am seeing:
run code to get registry value. Double check that it found 10000, which it should have (10000 is the default windows limit on GDI objects per process), and it does.
change the registry using regedit to something other than 10000
run the code again, but this time it again finds 10000, when it should have found the new value.
No matter what I try, it will always only find the original value and not
the updated value of the registry.
Things i've noticed/tried:
It does this for every value i've looked at, not just GDIProcessHandleQuota. (it doesn't always return 10000 since that's specific to the GDI value, it just always returns the pre-modify value for any given value)
It does this even if i reboot the computer and open regedit to verify the key
actually changed before running step 3.
all the results values in the code below (results, results2, results3) are 0, indicating ERROR_SUCCESS (lol), meaning they experienced no issues.
finally, here is the code snippet in which i'm experiencing the problems:
HKEY hKey;
//open the key for viewing in RegQueryValueEx, store opened handle in hkey
LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
0,
KEY_ALL_ACCESS,
&hKey);
DWORD dwReturn;
DWORD dwBufSize = sizeof(DWORD);
//after this line executes, dwReturn should have the DWORD data of the specified registry key/valuename
LONG result2 = RegQueryValueEx(hKey,
"GDIProcessHandleQuota",
0,
0,
reinterpret_cast<LPBYTE>(&dwReturn),
&dwBufSize);
DWORD value;
DWORD size = sizeof(DWORD);
//after this executes, value should contain the DWORD data of the specified registry key/valuename
LONG result3 = RegGetValue(hKey,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
"GDIProcessHandleQuota",
RRF_RT_ANY,
NULL,
&value,
&size
);
Your issue is most likely caused by the WOW64 emulator when running a 32-bit app on a 64bit machine. Refer to the MSDN documentation for more details:
Registry Redirector
Registry Keys Affected by WOW64
32-bit and 64-bit Application Data in the Registry
Accessing an Alternate Registry View
To open a 64bit key in a 32bit app, you need to include the KEY_WOW64_64KEY flag when opening the key with RegOpenKeyEx(), or the RRF_SUBKEY_WOW6464KEY flag when opening the key with RegGetValue().
You are also opening the key with too many permissions (which could kick in Registry Virtualization under UAC, but that is disabled on the particular key you are accessing in this example, but you should be aware of it). KEY_ALL_ACCESS will only work for admin users. Most users do not have write access to HKLM, only read-only access, so opening the key with KEY_ALL_ACCESS will fail for non-admins. Always request the minimum permissions you actually need. In this case, open the key for KEY_QUERY_VALUE access.
You are also calling RegGetValue() with the wrong parameter values.
Try something more like this instead:
HKEY hKey;
//open the key for viewing in RegQueryValueEx, store opened handle in hkey
LONG result = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
0,
KEY_QUERY_VALUE | KEY_WOW64_64KEY,
&hKey);
if (result != ERROR_SUCCESS)
{
...
}
else
{
DWORD value;
DWORD size = sizeof(DWORD);
//after this line executes, value should have the DWORD data of the specified registry key/valuename
result = RegQueryValueEx(
hKey,
"GDIProcessHandleQuota",
0,
0,
reinterpret_cast<LPBYTE>(&value),
&size);
if (result != ERROR_SUCCESS)
{
...
}
size = sizeof(DWORD);
//after this executes, value should contain the DWORD data of the specified registry key/valuename
result = RegGetValue(
hKey,
NULL,
"GDIProcessHandleQuota",
RRF_RT_REG_DWORD,
NULL,
&value,
&size);
if (result != ERROR_SUCCESS)
{
...
}
RegCloseKey(hKey);
}
Alternatively:
DWORD value;
DWORD size = sizeof(DWORD);
//after this executes, value should contain the DWORD data of the specified registry key/valuename
LONG result = RegGetValue(
HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
"GDIProcessHandleQuota",
RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,
NULL,
&value,
&size);
if (result != ERROR_SUCCESS)
{
...
}

Trying to find the path to excel by searching the registry

I'm trying to find the path to Excel using the registry, and have tried to adapt some code I've found on the internet. I'm using 64-bit Win7 and have confirmed the key is there using regedit.
#include <windows.h>
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
HKEY hKey = 0;
char buf[255] = {0};
DWORD dwType = 0;
DWORD dwBufSize = sizeof(buf);
const char* subkey = "SOFTWARE\\Classes\\Excel.Application\\CLSID";
if( RegOpenKey(HKEY_LOCAL_MACHINE,subkey,&hKey) == ERROR_SUCCESS)
{
dwType = REG_SZ;
if( RegQueryValueEx(hKey,"default",0, &dwType, (BYTE*)buf, &dwBufSize) == ERROR_SUCCESS)
{
cout << "key value is '" << buf << "'\n";
}
else
cout << "can not query for key value\n";
RegCloseKey(hKey);
}
else
cout << "Can not open key\n";
cin.ignore();
return 0;
}
Does anyone know why this isn't working?
Thanks
James
Try changing the
RegQueryValueEx(hKey,"default",0, &dwType, (BYTE*)buf, &dwBufSize) == ERROR_SUCCESS)
with
RegQueryValueEx(hKey, NULL, 0, &dwType, (BYTE*)buf, &dwBufSize) == ERROR_SUCCESS)
If you want the "default" value, you should pass NULL or a empty string in the lpValueName field.
Also if your application is not 64-bit and you are running in a 64-bit OS, you should check the KEY_WOW64_64KEY flag on the RegOpenKeyEx function, to have access to the key you want.
Almost all Windows API functions, when the fail, set a more detailed error code that you can get by calling GetLastError() for more details. You should call that after a call to RegOpenKey() fails.
In your example, the RegOpenKey() is probably failing with an access denied error. RegOpenKey() open a registry key with full read/write/delete access. A standard user on Windows 7 doesn't have write or delete access on HKLM so RegOpenKey() will fail.
You should instead use RegOpenKeyEx() which will let you specify read-only access, as below.
RegOpenKeyEx(HKEY_LOCAL_MACHINE, subkey, 0, KEY_READ, &hKey)
PS. When asking a question like the one above you should be more descriptive on how the code is failing. In your example above you should include which line/function call is failing. For example "When I use this code, the call to RegOpenKey is failing.

Create new data in registry key?

I just create new registry key called MyTestApp, and want to add new data in it, but don't know how. So I have following code.
bool CreateSectionDataRegistry(CString sectionData, CString sectionValue)
{
HKEY hKey; //registry key handle
LONG lResult; //result of registry operations
DWORD dwType, dwSize=0;
//try to open the key that we are currently pointing at with rootPath
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, rootPath + "\\" + "MyTestApp", NULL, KEY_ALL_ACCESS, &hKey);
if (lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
{
//we have successfully opened the registry key. Now try to access the data
lResult = RegQueryValueEx(HKEY_LOCAL_MACHINE, sectionData, 0, &dwType, NULL, &dwSize);
if(lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
{
//data already exists, so just return
RegCloseKey(hKey);
return true;
}
else//section data does not exist, so create new data
{
DWORD dwDisposition;
lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, sectionData, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisposition);
RegCloseKey(hKey);
return true;
}
}
return false;
}
But when I trace down to the RegCreateKeyEx() call, it returns success but data is not created under the MyTestApp registry key or anywhere in the registry. Am I using the correct function to create new data under MyTestApp. Also from the argument above, I have CString sectionValue, so how do I check if I need to create data for REG_SZ or REG_DWORD?
Thanks!
It seems I just need to call RegSetValueEx() to create registry value under MyTestApp. Probably just me but when I look at the RegSetValueEx() definition in Microsoft website, it says set the value, but it does not say if value does not exist, it will create the value.
LPTSTR lpszData = new TCHAR[sectionValue.GetLength() + 1];
_tcscpy(lpszData, sectionValue);
lResult = RegSetValueEx(hKey, sectionData, 0, REG_SZ, (LPBYTE)lpszData, sectionValue.GetLength());
So now it creates the registry value, however I cannot still tell if sectionValue is REG_SZ or REG_DWORD.