I want to read REG_NONE value from regedit with C++.
Here are my codes:
#include <iostream>
#include <windows.h>
using namespace std;
//--- Değişkenler ---//
//DWORD
DWORD dw_Rn_Boyut = MAX_PATH;
DWORD dw_Rn_Deger;
DWORD dw_Rn_DegerTipi = REG_NONE;
//HKEY
HKEY hkey_Rn;
//LONG
LONG long_Rn_Sonuc;
int main()
{
long_Rn_Sonuc = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\DownloadManager\\FoldersTree\\Compressed", 0, KEY_READ | KEY_WOW64_64KEY, &hkey_Rn);
if(long_Rn_Sonuc == ERROR_SUCCESS)
{
long_Rn_Sonuc = RegQueryValueEx(hkey_Rn, "pathW", 0, &dw_Rn_DegerTipi, (LPBYTE)&dw_Rn_Deger, &dw_Rn_Boyut);
if(long_Rn_Sonuc == ERROR_SUCCESS)
{
cout << dw_Rn_Deger;
}
}
getchar();
return 0;
}
My app shows 3801156 as result. This value is decimal version of that reg value. It equals to 3A 00 44
Here is the reg value which I want to read:
But why does not my app read other hex values?
How can I fix my problem?
There is no such thing as a REG_NONE value. On success, your dw_Rn_DegerTipi variable will be updated with the actual value type (in this case, REG_BINARY), and your dw_Rn_Boyut variable will be updated with the number of actual bytes read.
Your problem is that you are using the wrong data type for your dw_Rn_Dege variable. The data in question is not a DWORD value, it is a WCHAR character string, so you need a WCHAR character buffer to receive it. You are telling RegQueryValueEx() that you allocated a buffer to hold MAX_PATH bytes, but you really didn't. So you have a buffer overflow error in your code when RegQueryValueEx() tries to write more than 4 bytes to the memory address of dw_Rn_Deger.
Try this instead:
#include <iostream>
#include <windows.h>
using namespace std;
//--- Değişkenler ---//
WCHAR sz_Rn_Deger[MAX_PATH+1] = {};
DWORD dw_Rn_Boyut = MAX_PATH * sizeof(WCHAR);
//HKEY
HKEY hkey_Rn;
//LONG
LONG long_Rn_Sonuc;
int main()
{
long_Rn_Sonuc = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\DownloadManager\\FoldersTree\\Compressed", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hkey_Rn);
if (long_Rn_Sonuc == ERROR_SUCCESS)
{
long_Rn_Sonuc = RegQueryValueExW(hkey_Rn, L"pathW", NULL, NULL, reinterpret_cast<LPBYTE>(&sz_Rn_Deger), &dw_Rn_Boyut);
if (long_Rn_Sonuc == ERROR_SUCCESS)
{
wcout << sz_Rn_Deger;
}
RegCloseKey(hkey_Rn);
}
getchar();
return 0;
}
Related
I have written a C++ program in Code::Blocks which reads REG_NONE type value from registry.
Here are my codes:
#define KEY_WOW64_64KEY 0x0100
#include "string"
#include "windows.h"
using namespace std;
int main()
{
HKEY hKey;
long longErrorCode;
string strErrorCaption = "Hata";
string strErrorMessage;
string strSubKey = "Software\\DownloadManager\\Scheduler";
longErrorCode = RegOpenKeyEx(HKEY_CURRENT_USER, strSubKey.c_str(), 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey);
if (longErrorCode != ERROR_SUCCESS)
{
strErrorMessage = "Anahtar açılamadı.";
MessageBox(NULL, strErrorMessage.c_str(), strErrorCaption.c_str(), MB_OK | MB_ICONERROR);
return 0;
}
else
{
DWORD dwSize = MAX_PATH;
DWORD dwValueContent;
DWORD dwValueType = REG_NONE;
string strValueName = "startDay";
longErrorCode = RegQueryValueEx(hKey, strValueName.c_str(), 0, &dwValueType, (LPBYTE)&dwValueContent, &dwSize);
if (longErrorCode != ERROR_SUCCESS)
{
RegCloseKey(hKey);
strErrorMessage = "Değer açılamadı.";
MessageBox(NULL, strErrorMessage.c_str(), strErrorCaption.c_str(), MB_OK | MB_ICONERROR);
return 0;
}
else
{
string strValueContent = to_string(dwValueContent);
RegCloseKey(hKey);
strErrorCaption = "Başarılı!";
MessageBox(NULL, strValueContent.c_str(), strErrorCaption.c_str(), MB_OK | MB_ICONINFORMATION);
return 0;
}
}
}
The real value of the registry key which I tried to read is "f5 68 4b 5c".
But the problem is I got "1548445941". I also tried stringstream; but it didn't work.
So, what should I do in order to fix this issue?
the number is correct when you notice the bytes are ordered from the lower to the upper bytes.
Hex 5C4B68F5 = dec 1548445941
Open up windows calculator. Switch to programmer mode. Press DEC type in 1548445941. Notice how it shows HEX is 5C 4B 68 F5. Realise this is the value you got from registry but reversed, then read up about little endian.
I am trying to get the names of all the battery devices on my computer using this code mostly acquired from a Microsoft tutorial but it isn't working.
#define INITGUID
#include <windows.h>
#include<batclass.h>
#include<setupapi.h>
#define GBS_HASBATTERY 0x1
#define GBS_ONBATTERY 0x2
#include<iostream>
using namespace std;
int main()
{
DWORD dwResult = GBS_ONBATTERY;
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVICE_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
for (int idev = 0; idev < 100; idev++)
{
SP_DEVICE_INTERFACE_DATA did = {0};
did.cbSize = sizeof(did);
if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVICE_BATTERY, idev, &did))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR,cbRequired);
if (pdidd)
{
pdidd->cbSize = sizeof(*pdidd);
if (SetupDiGetDeviceInterfaceDetail(hdev,&did,pdidd,cbRequired,&cbRequired,0))
{
HANDLE hBattery = CreateFile(pdidd->DevicePath,GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE != hBattery)
{
BATTERY_QUERY_INFORMATION bqi = {0};
DWORD dwWait = 0;
DWORD dwOut;
if (DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_TAG,
&dwWait,
sizeof(dwWait),
&bqi.BatteryTag,
sizeof(bqi.BatteryTag),
&dwOut,
NULL)
&& bqi.BatteryTag)
{////////////////////////////////////////problem around here///////
string bi;
bqi.InformationLevel = BatteryDeviceName;
if (DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
&bqi,
sizeof(bqi),
&bi,
sizeof(bi),
&dwOut,
NULL))
{
cout<<bi;
BATTERY_WAIT_STATUS bws = {0};
bws.BatteryTag = bqi.BatteryTag;
BATTERY_STATUS bs;
if (DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_STATUS,
&bws,
sizeof(bws),
&bs,
sizeof(bs),
&dwOut,
NULL))
{
if (bs.PowerState & BATTERY_POWER_ON_LINE)
{
dwResult &= ~GBS_ONBATTERY;
}
}
}
}
CloseHandle(hBattery);
}
}
LocalFree(pdidd);
}
}
}
else if (ERROR_NO_MORE_ITEMS == GetLastError())
{
break;
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
i am trying to print the names of all the batteries, but when i run the program it doesnt print anything at all, it does however work when i request a battery_information structure instead of the string BatteryDeviceName please help
The problem is that in your call to DeviceIoControl is wrong. You are passing in garbage, and when you put garbage in you get garbage out.
string bi;
if(DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
bqi,
sizeof(bqi),
&bi, // Really?!?!?!
sizeof(bi), // WHAT?!?
&dwOut,
NULL))
You are passing the address a std::string object to DeviceIoControl, which knows nothing about std::string and expects the adress of a raw buffer that it can write to. You at least specify the right size for that buffer, but even that is wrong in a sense. Basically, when that function returns, that std::string is junk and accessing it could do just about anything - from crashing the program to playing Vivaldi on your speakers.
Try something like this:
WCHAR szBuf[_MAX_PATH] = { 0 }; // In a real program you'd dynamically
// allocate an appropriately sized buffer
// instead.
if(DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
bqi,
sizeof(bqi),
szBuf,
sizeof(szBuf),
&dwOut,
NULL))
I am trying to read a registy key under windows 7 x64 using the following code:
static void ReadRegistryKey(HKEY hkey, TCHAR* path)
{
HKEY hkey2;
TCHAR value[MAX_PATH];
TCHAR data[4096];
const DWORD dataLength = 4096 * sizeof(TCHAR);
const DWORD valueLength = MAX_PATH+1;
DWORD returnval;
DWORD type = 0;
HLOCAL mem = LocalAlloc(LPTR, 260);
char * pc = (char*)mem;
pc++;
wchar_t* pwc = (wchar_t*)pc;
lstrcpy(pwc, path);
// Does key exist?
returnval = RegOpenKeyEx(hkey, pwc, 0 , KEY_READ | KEY_WOW64_64KEY, &hkey2);
if(returnval == ERROR_SUCCESS)
{
int i = 0;
while(returnval == ERROR_SUCCESS)
{
DWORD actualLength = dataLength;
DWORD actualValueLength = valueLength;
returnval = RegEnumValueW( hkey2,
i,
value,
&actualValueLength,
NULL,
&type,
(LPBYTE)data,
&actualLength
);
if(returnval == ERROR_NO_MORE_ITEMS)
{
_tprintf(_T("NO MORE KEYS FOUND in %s\n"), path);
break;
}
if(returnval == ERROR_SUCCESS)
{
// STUFF
}
}
}
}
When I use KEY_READ | KEY_WOW64_32KEY I get the values stored under the 32Bit registry but when I use the code above trying to read the "normal" 64bit registy I get the error code 0x3e6 (ERROR_NOACCESS)
The way i call the method:
ReadRegistryKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run");
What can I do to read the 64bit registry values?
Thanks
I think the allocation and pointer arithmetic of pwc is causing the problem. Pass in the path directly into the RegOpenKeyEx function.
It's also worth noting that the lstrcpy will cause a buffer overflow if path is longer than 260 bytes. Instead use StringCchCopy in Windows to give a string copy that will only copy up to the number of bytes available in the destination buffer.
consider the following code
addHash("hash");
bool addHash(char* hash) {
HKEY hKey = 0;
int code = RegOpenKey(HKEY_CURRENT_USER, subkey, &hKey);
const int length = strlen(hash)+1;
WCHAR whash[100];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, hash, strlen(hash), whash, 100);
LONG setRes = RegSetValueEx(hKey, L"hash", 0, REG_SZ, (LPBYTE)whash, strlen(hash)+1);
return true;
}
After code is compiled and executed "ha" is puted into registry. Can somebody tell me where the problem is?
Thank you in advance!
The last argument is the number of bytes, not the number of characters, that the second last argument points to.
So the first five bytes (strlen(hash) + 1) of whash will be stored in the registry. Change to:
LONG setRes = RegSetValueEx(hKey,
L"hash",
0,
REG_SZ,
(LPBYTE)whash,
(wcslen(whash) + 1) * sizeof(WCHAR));
You may also need to initialise whash (I don't think MultiByteToWideChar() adds a null terminator for you):
WCHAR whash[100] = { 0 };
I think this is what you are trying to do:
#include <tchar.h>
#include <Windows.h>
using namespace std;
bool addHash(wstring hash) {
const wchar_t* wHash = hash.c_str();
LONG ret = RegSetKeyValue(HKEY_CURRENT_USER, _T("Software\\aa\\test"), _T("hash"), REG_SZ, wHash, hash.length() * sizeof(wchar_t));
return (ret == ERROR_SUCCESS);
}
int main()
{
addHash(_T("A42B2094EDC43"));
return 0;
}
Hope this helps ;)
Given a handle to a Windows Registry Key, such as the ones that are set by ::RegOpenKeyEx(), is it possible to determine the full path to that key?
I realize that in a simple application all you have to do is look up 5 or 10 lines and read... but in a complex app like the one I'm debugging, the key I'm interested in can be opened from a series of calls.
Use LoadLibrary and NtQueryKey exported function as in the following code snippet.
#include <windows.h>
#include <string>
typedef LONG NTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif
std::wstring GetKeyPathFromKKEY(HKEY key)
{
std::wstring keyPath;
if (key != NULL)
{
HMODULE dll = LoadLibrary(L"ntdll.dll");
if (dll != NULL) {
typedef DWORD (__stdcall *NtQueryKeyType)(
HANDLE KeyHandle,
int KeyInformationClass,
PVOID KeyInformation,
ULONG Length,
PULONG ResultLength);
NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey"));
if (func != NULL) {
DWORD size = 0;
DWORD result = 0;
result = func(key, 3, 0, 0, &size);
if (result == STATUS_BUFFER_TOO_SMALL)
{
size = size + 2;
wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes
if (buffer != NULL)
{
result = func(key, 3, buffer, size, &size);
if (result == STATUS_SUCCESS)
{
buffer[size / sizeof(wchar_t)] = L'\0';
keyPath = std::wstring(buffer + 2);
}
delete[] buffer;
}
}
}
FreeLibrary(dll);
}
}
return keyPath;
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY key = NULL;
LONG ret = ERROR_SUCCESS;
ret = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft", &key);
if (ret == ERROR_SUCCESS)
{
wprintf_s(L"Key path for %p is '%s'.", key, GetKeyPathFromKKEY(key).c_str());
RegCloseKey(key);
}
return 0;
}
This will print the key path on the console:
Key path for 00000FDC is
'\REGISTRY\MACHINE\SOFTWARE\Microsoft'.
I was excited to find this article and its well liked solution.
Until I found that my system's NTDLL.DLL did not have NtQueryKeyType.
After some hunting around, I ran across ZwQueryKey in the DDK forums.
It is in C#, but here is the solution that works for me:
enum KEY_INFORMATION_CLASS
{
KeyBasicInformation, // A KEY_BASIC_INFORMATION structure is supplied.
KeyNodeInformation, // A KEY_NODE_INFORMATION structure is supplied.
KeyFullInformation, // A KEY_FULL_INFORMATION structure is supplied.
KeyNameInformation, // A KEY_NAME_INFORMATION structure is supplied.
KeyCachedInformation, // A KEY_CACHED_INFORMATION structure is supplied.
KeyFlagsInformation, // Reserved for system use.
KeyVirtualizationInformation, // A KEY_VIRTUALIZATION_INFORMATION structure is supplied.
KeyHandleTagsInformation, // Reserved for system use.
MaxKeyInfoClass // The maximum value in this enumeration type.
}
[StructLayout(LayoutKind.Sequential)]
public struct KEY_NAME_INFORMATION
{
public UInt32 NameLength; // The size, in bytes, of the key name string in the Name array.
public char[] Name; // An array of wide characters that contains the name of the key.
// This character string is not null-terminated.
// Only the first element in this array is included in the
// KEY_NAME_INFORMATION structure definition.
// The storage for the remaining elements in the array immediately
// follows this element.
}
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int ZwQueryKey(IntPtr hKey, KEY_INFORMATION_CLASS KeyInformationClass, IntPtr lpKeyInformation, int Length, out int ResultLength);
public static String GetHKeyName(IntPtr hKey)
{
String result = String.Empty;
IntPtr pKNI = IntPtr.Zero;
int needed = 0;
int status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, IntPtr.Zero, 0, out needed);
if ((UInt32)status == 0xC0000023) // STATUS_BUFFER_TOO_SMALL
{
pKNI = Marshal.AllocHGlobal(sizeof(UInt32) + needed + 4 /*paranoia*/);
status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, pKNI, needed, out needed);
if (status == 0) // STATUS_SUCCESS
{
char[] bytes = new char[2 + needed + 2];
Marshal.Copy(pKNI, bytes, 0, needed);
// startIndex == 2 skips the NameLength field of the structure (2 chars == 4 bytes)
// needed/2 reduces value from bytes to chars
// needed/2 - 2 reduces length to not include the NameLength
result = new String(bytes, 2, (needed/2)-2);
}
}
Marshal.FreeHGlobal(pKNI);
return result;
}
I've only ever tried it while running as Administrator, which may be required.
The result is a bit oddly formatted: \REGISTRY\MACHINE\SOFTWARE\company\product for example, instead of HKEY_LOCAL_MACHINE\SOFTWARE\company\product.
Nominally no because it's just a handle and there is no API that I know of to let you do this in the normal Windows API's.
HOWEVER the Native API has lots of functions some of which can give you handles open for given files and the like so there maybe something similar for the Registry. That and RegMon by SysInternals may do something like this but you'll have to Google I'm afraid :/
You can use RegSaveKey and write it to a file, then look at the file.
Alternatively you can keep a global map of HKEYs to LPCWSTRs and add entries when you open them and do lookups whenever.
You may also be able to do something with the !reg command in WinDBG / NTSD, but you can't just give it the HKEY. You'll have to do some other trickery to get the info you want out of it.
Since std::wstring allows to construct string from pointer and count of characters, and the kernel string always return the count of bytes, it is not necessary to terminated the string with NUL. I do not suggest that to add size or to offset the pointer by constant number directly, it's better to use the real data type like the structure types instead, and std::vector<UCHAR> instead of new for dynamic memory allocating. I modified the code from highly upvoted answer as the followings.
The legacy way, obtaining the function pointer from ntdll.dll dynamically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
typedef NTSTATUS (NTAPI *PFN_NtQueryKey)(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
if (hKey != NULL)
{
HMODULE hinstDLL = GetModuleHandleW(L"ntdll.dll");
if (hinstDLL != NULL)
{
FARPROC pfn = GetProcAddress(hinstDLL, "NtQueryKey");
if (pfn != NULL)
{
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = reinterpret_cast<PFN_NtQueryKey>(pfn)(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
}
}
}
return keyPath;
}
If you are using Visual Studio 2015 or above, ntdll.lib is included by default, so I suggest that linking to ntdll.dll statically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtQueryKey(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = NtQueryKey(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
return keyPath;
}
Note that NtQueryKey returned STATUS_BUFFER_OVERFLOW but not STATUS_BUFFER_TOO_SMALL on Windows 10 if the supplied buffer is insufficient.
For ntsd/windbg:
!handle yourhandle 4