GetNamedSecurityInfo fails for registry key where GetSecurityInfo succeeds - c

I have a registry key ACL reading request like this:
PACL dacl = NULL;
PSECURITY_DESCRIPTOR secDesc = NULL;
if (GetNamedSecurityInfoW(L"HKEY_CURRENT_USER\\SOFTWARE\\SomeSoftware\\SomeKey", SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &secDesc) != ERROR_SUCCESS)
{ /*... */ }
And it fails with error 87, invalid parameter. However, if I use
HKEY handle;
DWORD Ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\SomeSoftware\\SomeKey", 0, KEY_ALL_ACCESS, &handle);
if (Ret != ERROR_SUCCESS) { /* ... */ }
DWORD secDescSize = 4096;
secDesc = LocalAlloc(LMEM_FIXED, secDescSize);
Ret = (DWORD)RegGetKeySecurity(handle, DACL_SECURITY_INFORMATION, secDesc, &secDescSize);
if (Ret != ERROR_SUCCESS) { /* ... */ }
RegOpenKey() and RegGetKeySecurity() succeed, and running GetSecurityDescriptorDacl() on the result of RegGetKeySecurity() also works.
This code works fine for SE_FILE_OBJECT and reading a directory's ACL.
This code is inside a 32-bit DLL in a 32-bit app in Windows 10 Pro 64-bit. I'm targeting XP and above, using Visual Studio 2019 Preview.
Anything I could have missed in parameter validation?

L"HKEY_CURRENT_USER\\SOFTWARE\\SomeSoftware\\SomeKey" is not a valid object name for GetNamedSecurityInfoW(). Read the SE_OBJECT_TYPE documentation for the proper format to use for a registry key:
SE_REGISTRY_KEY
Indicates a registry key. A registry key object can be in the local registry, such as CLASSES_ROOT\SomePath or in a remote registry, such as \\ComputerName\CLASSES_ROOT\SomePath.
The names of registry keys must use the following literal strings to identify the predefined registry keys: "CLASSES_ROOT", "CURRENT_USER", "MACHINE", and "USERS".
Try L"CURRENT_USER\\SOFTWARE\\SomeSoftware\\SomeKey" instead.

Related

Berkley DB non deterministic error occurrence when adding an encrypted database within environment

I'm trying to add new and first encrypted database within an environment which already contains several unencrypted databases.
the problem is that once in several attempts to update our software version (to the version that contains the new encrypted database creation), db->open returns error 22 and the following logs from BDB being printed:
enter image description here
Berkeley DB version that being used is 4.8.30
I followed those instructions https://docs.oracle.com/cd/E17076_05/html/programmer_reference/env_encrypt.html
I didn't created new environment, I used the already exist environment with the following configurations:
static STATUS sPR_create_env(const char *passwd, BOOL open_env)
{
STATUS ret=OK, err=OK;
if( db_env_passwd == NULL )
{
asprintf(&db_env_passwd, "%s", passwd);
}
/* Create an environment object and initialize it */
ret = db_env_create(&dbenv, 0 );
dbenv->set_msgcall(dbenv, sPR_db_print_to_syslog);
dbenv->set_errcall(dbenv, sPR_db_err_print);
/*
* We want to specify the shared memory buffer pool cachesize
*/
ret = dbenv->set_cachesize(dbenv, 0, (4 * 1024 * 1024), 0);
/* Set databases prefix to data files. */
(void)dbenv->set_data_dir(dbenv, data_dir);
/* Set encrypt to environment for the supporting secure DB */
ret = dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES);
ret = dbenv->set_tx_max(dbenv, MAX_NUM_OF_TRANSACTIONS);
ret = dbenv->set_lk_partitions(dbenv, 1); /* optimized for single CPU systems */
/* Set Log file auto-removal on */
ret = dbenv->log_set_config(dbenv, DB_LOG_AUTO_REMOVE, 1);
/* Set the maximum # of locks/lockers/lock-objects (should be at least 5*lock-partitions) */
ret = dbenv->set_lk_max_locks(dbenv, 4000);
ret = dbenv->set_lk_max_objects(dbenv, 4000);
ret = dbenv->set_lk_max_lockers(dbenv, 4000);
/* Reject lock request leading to deadlocks which have the least # of locks taken */
ret = dbenv->set_lk_detect(dbenv, DB_LOCK_MINWRITE);
ret = dbenv->set_lg_dir(dbenv, DB_LOG_FILE_PATH);
ret = dbenv->set_lg_max(dbenv, DB_LOG_FILE_SIZE);
if( open_env )
{
/* open environment DB */
ret = dbenv->open(dbenv, DB_home,
DB_THREAD | DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE |
DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG | DB_RECOVER,
0644);
}
exit:
if( err == ERROR )
{
dbenv->close(dbenv, 0);
dbenv=NULL;
}
return err;
}
the way of opening my new database is as follow:
/* set encryption */
ret = dbp->set_flags(dbp, DB_ENCRYPT);
/* Open a database with DB_BTREE access method.*/
ret = dbp->open(dbp,
NULL,
file_name,
NULL,
DB_BTREE,
flags,
0644);
all other databases being open like this:
/* Open a database with DB_BTREE access method.*/
ret = dbp->open(dbp,
NULL,
file_name,
NULL,
DB_BTREE,
flags,
0644);
what can be the reason for this error 22? can it be related to the mixing of encrypted together with unencrypted databases within the same environment?
why sometimes the program runs properly and sometimes not?
is there something wrong with the environment configurations? flags?
thanks.

Read "OS install date" value from registry with RegQueryValueExA() api failed

I wanna read Windows Install Date value from registry using Windows API as bellow :
HKEY hKey = { 0 };
LONG lResult = ERROR_SUCCESS;
// Open a registry key
lResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
0, KEY_READ, &hKey);
// If registry key opened
if (lResult == ERROR_SUCCESS)
{
// Get OS install date/time
DWORD dwInstallDate = 0;
dwBufferSize = sizeof(DWORD);
if (RegQueryValueExA(hKey, "InstallDate", 0, NULL, (LPBYTE)&dwInstallDate, &dwBufferSize) == ERROR_SUCCESS)
{
printf("OS Install Date is : %lu", dwInstallDate);
}
else
{
printf("The specific key not found!");
}
// Finally we should close the key when we finished with it
RegCloseKey(hKey);
}
But the output is always 0, while "InstallDate" value is 1520291827:
OS Installe Date is : 0
Also, I'm used of "%ld" and "d" formats, but it has the same output...
The "InstallDate" value in registry, contained a REG_DWORD type.
By the way, when i create a new REG_DWORD value, my code cannot read it :
For example , I create a value in bellow reg-address as "test" with 123 data :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
But dwInstallDate will be 0 instead of 123 :
RegQueryValueExA(hKey, "test", 0,
NULL, (LPBYTE)&dwInstallDate,
&dwBufferSize);
Any Suggestion? I'm confused about this action...
According Microsoft :
KEY_WOW64_32KEY (0x0200) :
Indicates that an application on 64-bit Windows should operate on the 32-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View.
This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Windows 2000: This flag is not supported.
KEY_WOW64_64KEY (0x0100) :
Indicates that an application on 64-bit Windows should operate on the 64-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View.
This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Windows 2000: This flag is not supported.
I used of KEY_WOW64_64KEY | KEY_READ either way x86 and x64 :
// Open a registry key
lResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
0, KEY_WOW64_64KEY | KEY_READ, &hKey);
It does work.

Reading registry from windows kernel driver in C

I need to read settings from the registry (preferably) or from a file. The driver is a kernel driver that is set to start with type of start set to SYSTEM, so all services and WinAPIs are not necessarily available.
I'm attempting to use the RtlQueryRegistryValues function in order to read a single String value from the registry, but whatever I do I seem to get the same 0xC0000034 error code back which translate to STATUS_OBJECT_NAME_NOT_FOUND.
According to the documentation available at MSDN STATUS_OBJECT_NAME_NOT_FOUND is returned from RtlQueryRegistryValues when the path parameter does not match a valid key, or a specific flag is set and conditions specific to that flag is not met. As far as I can tell the registry keys are actually present in my test machine and I'm not using the RTL_QUERY_REGISTRY_REQUIRED flag.
The registry values I'm attempting to read is located under HKEY_LOCAL_MACHINE/SOFTWARE/company/ProjectName, I'm attempting to read both the default value and a REG_SZ value named parameter. The call to RtlQueryRegistryValues is performed during the DriverEntry(...) stage of loading the driver.
I can't figure out what it is that I'm doing wrong, and since I'm new to kernel drivers and the debugging process is quite tedious I'm not sure whether or not I just refer to the registry values incorrectly or if the registry is available at all during this stage of the system boot.
mydriver.c
NTSTATUS DriverEntry(...) {
NTSTATUS regStatus = 0;
UNICODE_STRING data;
RTL_QUERY_REGISTRY_TABLE query[2];
WCHAR* regPath = L"\\Registry\\Machine\\SOFTWARE\\Company\\ProjectName";
RtlZeroMemory(query, sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
data.Buffer = NULL;
data.MaximumLength = 0;
data.Length = 0;
// query[0].Name = L"Parameter";
query[0].Name = L""; // L"" refers to the default value
query[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
query[0].EntryContext = &data;
regStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, regPath, query, NULL, NULL);
DebugPrint("regStatus: %lx\n", regStatus);
DebugPrint("data: %wZ\n", &data);
}
I'm not 100% sure but I suspect the registry hive for the Software subtree is just not loaded. Why are you trying to access it anyway? The proper place for driver config parameters is its own registry key (\Registry\Machine\System\CurrentControlSet\Services\<DriverName>\) and the path to it is even passed to your DriverEntry function so you don't need to hardcode it.
See also: Registry Trees and Keys for Devices and Drivers.
You could use the RegistryPath passed into DriverEntry like so:
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
// ...
NTSTATUS ntStatus = STATUS_SUCCESS;
UNICODE_STRING valueName = RTL_CONSTANT_STRING(L"<YOUR_VALUE_NAME>");
HANDLE hRegistryKey;
PKEY_VALUE_FULL_INFORMATION pKeyInfo = nullptr;
// Create object attributes for registry key querying
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
do {
ntStatus = ZwOpenKey(&hRegistryKey, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(ntStatus)) {
KdPrint((DRIVER_PREFIX "Registry key open failed (0x%08X)\n", ntStatus));
break;
}
ULONG ulKeyInfoSize;
ULONG ulKeyInfoSizeNeeded = GetKeyInfoSize(hRegistryKey, &valueName);
if (ulKeyInfoSizeNeeded == 0) {
KdPrint((DRIVER_PREFIX "Value not found\n"));
break;
}
ulKeyInfoSize = ulKeyInfoSizeNeeded;
pKeyInfo = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, ulKeyInfoSize, DRIVER_TAG);
if (pKeyInfo == nullptr) {
KdPrint((DRIVER_PREFIX "Could not allocate memory for KeyValueInfo\n"));
break;
}
RtlZeroMemory(pKeyInfo, ulKeyInfoSize);
ntStatus = ZwQueryValueKey(hRegistryKey, &valueName, KeyValueFullInformation, pKeyInfo, ulKeyInfoSize, &ulKeyInfoSizeNeeded);
if (!NT_SUCCESS(ntStatus) || ulKeyInfoSize != ulKeyInfoSizeNeeded) {
KdPrint((DRIVER_PREFIX "Registry value querying failed (0x%08X)\n", ntStatus));
break;
}
// your data
ULONG someLong = *(ULONG*)((ULONG_PTR)pKeyInfo + pKeyInfo->DataOffset);
} while (false);
// cleanup
if (hRegistryKey) {
ZwClose(hRegistryKey);
}
if (pKeyInfo) {
ExFreePoolWithTag(pKeyInfo, DRIVER_TAG);
}
if (!NT_SUCCESS(ntStatus)) {
// Here you can set a default data if something failed it the way
}
// ...
}
ULONG GetKeyInfoSize(HANDLE hRegistryKey, PUNICODE_STRING pValueName) {
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG ulKeyInfoSizeNeeded;
ntStatus = ZwQueryValueKey(hRegistryKey, pValueName, KeyValueFullInformation, 0, 0, &ulKeyInfoSizeNeeded);
if (ntStatus == STATUS_BUFFER_TOO_SMALL || ntStatus == STATUS_BUFFER_OVERFLOW) {
// Expected don't worry - when ZwQueryValueKey fails with one of the above statuses, it returns the size needed
return ulKeyInfoSizeNeeded;
}
else {
KdPrint((DRIVER_PREFIX "Could not get key info size (0x%08X)\n", ntStatus));
}
return 0;
}
In my example I'm reading an ULONG but it could be anything, the idea is that the address of what you're trying to read is at the address pKeyInfo + pKeyInfo->DataOffset.
It looks like the problem is with RTL_QUERY_REGISTRY_DIRECT.
According to the documentation, it requires the RTL_QUERY_REGISTRY_TYPECHECK flag set as well.
The RTL_QUERY_REGISTRY_TYPECHECK flag, in turn, requires DefaultType and DefaultSize (of PKEY_VALUE_FULL_INFORMATION) set. At least that is what I've found, which is not according to documentation.

RegQueryValue fails but RegQueryValueEx returns a value

I am attempting to play with some of the 16 and 32 bit registry functions, and I'm having trouble with using RegQueryValue (not extended). I am opening a handle to HKLM\Software\Microsoft\EventSystem (this key was chosen at random, the problem is persistent across keys). When I call RegQueryValue for "Configured", there is an error. However, for RegQueryValueEx, I am actually able to get the value.
I am running this on Windows 7 x64, tested with admin rights (Not having admin rights means RegOpenKeyEx fails with insufficient rights).
Here is the code (see https://stackoverflow.com/questions/455434/how-should-i-use-formatmessage-properly-in-c for printErrorMessage):
#define BUFLEN 80
int main() {
HKEY hkey;
DWORD ret = RegOpenKeyA(rootKey, "Software\\Microsoft\\EventSystem", &hkey);
printf("Opened key, handle is %i\n", hkey);
LONG buflen = BUFLEN;
DWORD dwbuflen = BUFLEN;
char data[BUFLEN];
BYTE bdata[BUFLEN];
ret = RegQueryValueA(hkey, "Configured", data, &buflen);
if (ret != ERROR_SUCCESS) {
printf("Unable to open Configured with RegQueryValueA\n");
printErrorMessage(ret);
} else {
printf("Value of Configured was %s\n", data);
}
ret = RegQueryValueExA(hkey, "Configured", 0, NULL, bdata, &dwbuflen);
if (ret != ERROR_SUCCESS) {
printf("Unable to open Configured with RegQueryValueExA\n");
printErrorMessage(ret);
} else {
printf("Value of Configured was %s\n", bdata);
}
}
And here is the output:
Opened key, handle is 68
Unable to open Configured with RegQueryValueA
The system cannot find the file specified.
Value of Configured was ☺
(Configured's value is wonky because I am not yet bothering to convert from REG_DWORD to a string, but it is immaterial to the problem I am having).
When you call RegQueryValue(hkey, "Configured"), that tries to read the default value (or unnamed value) of the key named "Configured". This is the semantics of RegQueryValue() as described by MSDN.
So RegQueryValue() cannot be used to read named values like "Configured", so you must use RegQueryValueEx() if you want to read a named value.
You're querying a value, but the string parameter for RegQueryValue() is a subkey. See msdn for RegQueryValue() vs. RegQueryValueEx().

Unable to read certain registry keys in C

I'm using RegOpenKeyEx() and RegQueryValueEx() to try and get the value for six keys in the Windows registry. I'm able to do it for four of the six but am failing on certain others.
wchar_t * getRegKeyValue(HKEY rootKeyToGet, LPCWSTR subKeyToGet, LPCWSTR valueToGet)
{
HKEY resultHKey = 0;
wchar_t resultString[255] = L"";
DWORD dwType = REG_SZ;
DWORD resultSize = 255;
// See if the subkey exists. If it does, get its value.
if (RegOpenKeyEx(rootKeyToGet, subKeyToGet, NULL, KEY_ALL_ACCESS, &resultHKey) == ERROR_SUCCESS)
{
RegQueryValueEx(resultHKey, valueToGet, NULL, &dwType, (LPBYTE) &resultString, &resultSize);
}
RegCloseKey(resultHKey);
resultHKey = NULL;
RegCloseKey(rootKeyToGet);
rootKeyToGet = NULL;
return resultString;
}
The following are some successful calls:
swprintf(buffer, L"&ie=%s", getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Internet Explorer", L"Version"));
swprintf(buffer, L"&os=%s.", getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentVersion"));
wcscat(url, getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuild"));
Example of an unsuccessful call:
wcscpy(buffer, getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CSDVersion"));
I'm able to open the key in the unsuccessful call but the query for that value returns an empty string. I'm running Visual Studio as an administrator. Have been scratching my head for the last day on where I am going wrong.
Update: The code returned is ERROR_FILE_NOT_FOUND. The codes are most definitely shown to exist in regedit.
I guess that you have a 32 bit process and a 64 bit machine. When this happens, registry redirection confounds matters. Attempts to read HKLM\Software\... get redirected to HKLM\Software\Wow64Node\.... So you need to open the 64 bit view of the registry with the RegistryView enumeration.

Resources